blob: e72739cba881a029f08f3fb495c9d4be1829fdd9 [file] [log] [blame]
Mike Frysinger51a43b42005-09-24 07:11:16 +00001/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002 * e2fsck
3 *
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 * This file may be
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006 * redistributed under the terms of the GNU Public License.
7 *
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008 *
9 * Dictionary Abstract Data Type
10 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
11 * Free Software License:
12 * All rights are reserved by the author, with the following exceptions:
13 * Permission is granted to freely reproduce and distribute this software,
14 * possibly in exchange for a fee, provided that this copyright notice appears
15 * intact. Permission is also granted to adapt this software to produce
16 * derivative works, as long as the modified versions carry this copyright
17 * notice and additional notices stating that the work has been modified.
18 * This source code may be translated into executable form and incorporated
19 * into proprietary software; there is no requirement for such software to
20 * contain a copyright notice related to this source.
21 *
22 * linux/fs/recovery and linux/fs/revoke
23 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
24 *
25 * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
26 *
27 * This file is part of the Linux kernel and is made available under
28 * the terms of the GNU General Public License, version 2, or at your
29 * option, any later version, incorporated herein by reference.
30 *
31 * Journal recovery routines for the generic filesystem journaling code;
32 * part of the ext2fs journaling system.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000033 */
34
35#ifndef _GNU_SOURCE
36#define _GNU_SOURCE 1 /* get strnlen() */
37#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000038
Rob Landley43ac8882006-04-01 00:40:33 +000039#include "e2fsck.h" /*Put all of our defines here to clean things up*/
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000040
41#ifdef __GNUC__
42#define _INLINE_ __inline__
43#define EXT2FS_ATTR(x) __attribute__(x)
44#else
45#define _INLINE_
46#define EXT2FS_ATTR(x)
47#endif
48
49/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000050 * Procedure declarations
51 */
52
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000053static void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000054
55/* pass1.c */
56static void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000057
58/* pass2.c */
59static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
60 ext2_ino_t ino, char *buf);
61
62/* pass3.c */
63static int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
64static errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
65 int num, int gauranteed_size);
66static ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix);
67static errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino,
68 int adj);
69
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000070/* rehash.c */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000071static void e2fsck_rehash_directories(e2fsck_t ctx);
72
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000073/* util.c */
74static void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
75 const char *description);
76static int ask(e2fsck_t ctx, const char * string, int def);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000077static void e2fsck_read_bitmaps(e2fsck_t ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000078static void preenhalt(e2fsck_t ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000079static void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
80 struct ext2_inode * inode, const char * proc);
81static void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
82 struct ext2_inode * inode, const char * proc);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000083static blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs,
84 const char *name, io_manager manager);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000085
86/* unix.c */
87static void e2fsck_clear_progbar(e2fsck_t ctx);
88static int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
89 float percent, unsigned int dpynum);
Rob Landley43ac8882006-04-01 00:40:33 +000090
91
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000092/*
93 * problem.h --- e2fsck problem error codes
94 */
95
96typedef __u32 problem_t;
97
98struct problem_context {
99 errcode_t errcode;
100 ext2_ino_t ino, ino2, dir;
101 struct ext2_inode *inode;
102 struct ext2_dir_entry *dirent;
103 blk_t blk, blk2;
104 e2_blkcnt_t blkcount;
105 int group;
106 __u64 num;
107 const char *str;
108};
109
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000110
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000111
112/*
113 * Function declarations
114 */
115static int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx);
116static int end_problem_latch(e2fsck_t ctx, int mask);
117static int set_latch_flags(int mask, int setflags, int clearflags);
118static void clear_problem_context(struct problem_context *ctx);
119
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000120/*
121 * Dictionary Abstract Data Type
122 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
123 *
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000124 * dict.h v 1.22.2.6 2000/11/13 01:36:44 kaz
125 * kazlib_1_20
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000126 */
127
128#ifndef DICT_H
129#define DICT_H
130
131/*
132 * Blurb for inclusion into C++ translation units
133 */
134
135typedef unsigned long dictcount_t;
136#define DICTCOUNT_T_MAX ULONG_MAX
137
138/*
139 * The dictionary is implemented as a red-black tree
140 */
141
142typedef enum { dnode_red, dnode_black } dnode_color_t;
143
144typedef struct dnode_t {
145 struct dnode_t *dict_left;
146 struct dnode_t *dict_right;
147 struct dnode_t *dict_parent;
148 dnode_color_t dict_color;
149 const void *dict_key;
150 void *dict_data;
151} dnode_t;
152
153typedef int (*dict_comp_t)(const void *, const void *);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000154typedef void (*dnode_free_t)(dnode_t *);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000155
156typedef struct dict_t {
157 dnode_t dict_nilnode;
158 dictcount_t dict_nodecount;
159 dictcount_t dict_maxcount;
160 dict_comp_t dict_compare;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000161 dnode_free_t dict_freenode;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000162 int dict_dupes;
163} dict_t;
164
165typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
166
167typedef struct dict_load_t {
168 dict_t *dict_dictptr;
169 dnode_t dict_nilnode;
170} dict_load_t;
171
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000172#define dict_count(D) ((D)->dict_nodecount)
173#define dnode_get(N) ((N)->dict_data)
174#define dnode_getkey(N) ((N)->dict_key)
175
176#endif
177
178/*
179 * Compatibility header file for e2fsck which should be included
180 * instead of linux/jfs.h
181 *
182 * Copyright (C) 2000 Stephen C. Tweedie
183 */
184
185/*
186 * Pull in the definition of the e2fsck context structure
187 */
188
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000189struct buffer_head {
190 char b_data[8192];
191 e2fsck_t b_ctx;
192 io_channel b_io;
193 int b_size;
194 blk_t b_blocknr;
195 int b_dirty;
196 int b_uptodate;
197 int b_err;
198};
199
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000200
201#define K_DEV_FS 1
202#define K_DEV_JOURNAL 2
203
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000204#define lock_buffer(bh) do {} while(0)
205#define unlock_buffer(bh) do {} while(0)
206#define buffer_req(bh) 1
207#define do_readahead(journal, start) do {} while(0)
208
209static e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
210
211typedef struct {
212 int object_length;
213} kmem_cache_t;
214
215#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000216
217/*
218 * We use the standard libext2fs portability tricks for inline
219 * functions.
220 */
221
222static _INLINE_ kmem_cache_t * do_cache_create(int len)
223{
224 kmem_cache_t *new_cache;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000225
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000226 new_cache = malloc(sizeof(*new_cache));
227 if (new_cache)
228 new_cache->object_length = len;
229 return new_cache;
230}
231
232static _INLINE_ void do_cache_destroy(kmem_cache_t *cache)
233{
234 free(cache);
235}
236
237/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000238 * badblocks.c --- replace/append bad blocks to the bad block inode
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000239 */
240
241static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt,
242 void *priv_data);
243
244
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +0000245static void invalid_block(ext2_filsys fs FSCK_ATTR((unused)), blk_t blk)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000246{
247 printf(_("Bad block %u out of range; ignored.\n"), blk);
248 return;
249}
250
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000251static void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000252 int replace_bad_blocks)
253{
254 ext2_filsys fs = ctx->fs;
255 errcode_t retval;
256 badblocks_list bb_list = 0;
257 FILE *f;
258 char buf[1024];
259
260 e2fsck_read_bitmaps(ctx);
261
262 /*
263 * Make sure the bad block inode is sane. If there are any
264 * illegal blocks, clear them.
265 */
266 retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0,
267 check_bb_inode_blocks, 0);
268 if (retval) {
269 com_err("ext2fs_block_iterate", retval,
270 _("while sanity checking the bad blocks inode"));
271 goto fatal;
272 }
273
274 /*
275 * If we're appending to the bad blocks inode, read in the
276 * current bad blocks.
277 */
278 if (!replace_bad_blocks) {
279 retval = ext2fs_read_bb_inode(fs, &bb_list);
280 if (retval) {
281 com_err("ext2fs_read_bb_inode", retval,
282 _("while reading the bad blocks inode"));
283 goto fatal;
284 }
285 }
286
287 /*
288 * Now read in the bad blocks from the file; if
289 * bad_blocks_file is null, then try to run the badblocks
290 * command.
291 */
292 if (bad_blocks_file) {
293 f = fopen(bad_blocks_file, "r");
294 if (!f) {
295 com_err("read_bad_blocks_file", errno,
296 _("while trying to open %s"), bad_blocks_file);
297 goto fatal;
298 }
299 } else {
300 sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize,
301 (ctx->options & E2F_OPT_PREEN) ? "" : "-s ",
302 (ctx->options & E2F_OPT_WRITECHECK) ? "-n " : "",
303 fs->device_name, fs->super->s_blocks_count);
304 f = popen(buf, "r");
305 if (!f) {
306 com_err("read_bad_blocks_file", errno,
307 _("while trying popen '%s'"), buf);
308 goto fatal;
309 }
310 }
311 retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
312 if (bad_blocks_file)
313 fclose(f);
314 else
315 pclose(f);
316 if (retval) {
317 com_err("ext2fs_read_bb_FILE", retval,
318 _("while reading in list of bad blocks from file"));
319 goto fatal;
320 }
321
322 /*
323 * Finally, update the bad blocks from the bad_block_map
324 */
325 retval = ext2fs_update_bb_inode(fs, bb_list);
326 if (retval) {
327 com_err("ext2fs_update_bb_inode", retval,
328 _("while updating bad block inode"));
329 goto fatal;
330 }
331
332 ext2fs_badblocks_list_free(bb_list);
333 return;
334
335fatal:
336 ctx->flags |= E2F_FLAG_ABORT;
337 return;
338
339}
340
341static int check_bb_inode_blocks(ext2_filsys fs,
342 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +0000343 int blockcnt FSCK_ATTR((unused)),
344 void *priv_data FSCK_ATTR((unused)))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000345{
346 if (!*block_nr)
347 return 0;
348
349 /*
350 * If the block number is outrageous, clear it and ignore it.
351 */
352 if (*block_nr >= fs->super->s_blocks_count ||
353 *block_nr < fs->super->s_first_data_block) {
354 printf(_("Warning illegal block %u found in bad block inode. Cleared.\n"), *block_nr);
355 *block_nr = 0;
356 return BLOCK_CHANGED;
357 }
358
359 return 0;
360}
361
362/*
363 * Dictionary Abstract Data Type
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000364 */
365
366
367/*
368 * These macros provide short convenient names for structure members,
369 * which are embellished with dict_ prefixes so that they are
370 * properly confined to the documented namespace. It's legal for a
371 * program which uses dict to define, for instance, a macro called ``parent''.
372 * Such a macro would interfere with the dnode_t struct definition.
373 * In general, highly portable and reusable C modules which expose their
374 * structures need to confine structure member names to well-defined spaces.
375 * The resulting identifiers aren't necessarily convenient to use, nor
376 * readable, in the implementation, however!
377 */
378
379#define left dict_left
380#define right dict_right
381#define parent dict_parent
382#define color dict_color
383#define key dict_key
384#define data dict_data
385
386#define nilnode dict_nilnode
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000387#define maxcount dict_maxcount
388#define compare dict_compare
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000389#define dupes dict_dupes
390
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000391#define dict_root(D) ((D)->nilnode.left)
392#define dict_nil(D) (&(D)->nilnode)
393#define DICT_DEPTH_MAX 64
394
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000395static void dnode_free(dnode_t *node);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000396
397/*
398 * Perform a ``left rotation'' adjustment on the tree. The given node P and
399 * its right child C are rearranged so that the P instead becomes the left
400 * child of C. The left subtree of C is inherited as the new right subtree
401 * for P. The ordering of the keys within the tree is thus preserved.
402 */
403
404static void rotate_left(dnode_t *upper)
405{
406 dnode_t *lower, *lowleft, *upparent;
407
408 lower = upper->right;
409 upper->right = lowleft = lower->left;
410 lowleft->parent = upper;
411
412 lower->parent = upparent = upper->parent;
413
414 /* don't need to check for root node here because root->parent is
415 the sentinel nil node, and root->parent->left points back to root */
416
417 if (upper == upparent->left) {
418 upparent->left = lower;
419 } else {
420 assert (upper == upparent->right);
421 upparent->right = lower;
422 }
423
424 lower->left = upper;
425 upper->parent = lower;
426}
427
428/*
429 * This operation is the ``mirror'' image of rotate_left. It is
430 * the same procedure, but with left and right interchanged.
431 */
432
433static void rotate_right(dnode_t *upper)
434{
435 dnode_t *lower, *lowright, *upparent;
436
437 lower = upper->left;
438 upper->left = lowright = lower->right;
439 lowright->parent = upper;
440
441 lower->parent = upparent = upper->parent;
442
443 if (upper == upparent->right) {
444 upparent->right = lower;
445 } else {
446 assert (upper == upparent->left);
447 upparent->left = lower;
448 }
449
450 lower->right = upper;
451 upper->parent = lower;
452}
453
454/*
455 * Do a postorder traversal of the tree rooted at the specified
456 * node and free everything under it. Used by dict_free().
457 */
458
459static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
460{
461 if (node == nil)
462 return;
463 free_nodes(dict, node->left, nil);
464 free_nodes(dict, node->right, nil);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000465 dict->dict_freenode(node);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000466}
467
468/*
469 * Verify that the tree contains the given node. This is done by
470 * traversing all of the nodes and comparing their pointers to the
471 * given pointer. Returns 1 if the node is found, otherwise
472 * returns zero. It is intended for debugging purposes.
473 */
474
475static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
476{
477 if (root != nil) {
478 return root == node
479 || verify_dict_has_node(nil, root->left, node)
480 || verify_dict_has_node(nil, root->right, node);
481 }
482 return 0;
483}
484
485
486/*
487 * Select a different set of node allocator routines.
488 */
489
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000490static void dict_set_allocator(dict_t *dict, dnode_free_t fr)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000491{
492 assert (dict_count(dict) == 0);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000493 dict->dict_freenode = fr;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000494}
495
496/*
497 * Free all the nodes in the dictionary by using the dictionary's
498 * installed free routine. The dictionary is emptied.
499 */
500
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000501static void dict_free_nodes(dict_t *dict)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000502{
503 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
504 free_nodes(dict, root, nil);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000505 dict->dict_nodecount = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000506 dict->nilnode.left = &dict->nilnode;
507 dict->nilnode.right = &dict->nilnode;
508}
509
510/*
511 * Initialize a user-supplied dictionary object.
512 */
513
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000514static dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000515{
516 dict->compare = comp;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000517 dict->dict_freenode = dnode_free;
518 dict->dict_nodecount = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000519 dict->maxcount = maxcount;
520 dict->nilnode.left = &dict->nilnode;
521 dict->nilnode.right = &dict->nilnode;
522 dict->nilnode.parent = &dict->nilnode;
523 dict->nilnode.color = dnode_black;
524 dict->dupes = 0;
525 return dict;
526}
527
528/*
529 * Locate a node in the dictionary having the given key.
530 * If the node is not found, a null a pointer is returned (rather than
531 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
532 * located node is returned.
533 */
534
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000535static dnode_t *dict_lookup(dict_t *dict, const void *key)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000536{
537 dnode_t *root = dict_root(dict);
538 dnode_t *nil = dict_nil(dict);
539 dnode_t *saved;
540 int result;
541
542 /* simple binary search adapted for trees that contain duplicate keys */
543
544 while (root != nil) {
545 result = dict->compare(key, root->key);
546 if (result < 0)
547 root = root->left;
548 else if (result > 0)
549 root = root->right;
550 else {
551 if (!dict->dupes) { /* no duplicates, return match */
552 return root;
553 } else { /* could be dupes, find leftmost one */
554 do {
555 saved = root;
556 root = root->left;
557 while (root != nil && dict->compare(key, root->key))
558 root = root->right;
559 } while (root != nil);
560 return saved;
561 }
562 }
563 }
564
565 return NULL;
566}
567
568/*
569 * Insert a node into the dictionary. The node should have been
570 * initialized with a data field. All other fields are ignored.
571 * The behavior is undefined if the user attempts to insert into
572 * a dictionary that is already full (for which the dict_isfull()
573 * function returns true).
574 */
575
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000576static void dict_insert(dict_t *dict, dnode_t *node, const void *key)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000577{
578 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
579 dnode_t *parent = nil, *uncle, *grandpa;
580 int result = -1;
581
582 node->key = key;
583
584 /* basic binary tree insert */
585
586 while (where != nil) {
587 parent = where;
588 result = dict->compare(key, where->key);
589 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
590 assert (dict->dupes || result != 0);
591 if (result < 0)
592 where = where->left;
593 else
594 where = where->right;
595 }
596
597 assert (where == nil);
598
599 if (result < 0)
600 parent->left = node;
601 else
602 parent->right = node;
603
604 node->parent = parent;
605 node->left = nil;
606 node->right = nil;
607
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000608 dict->dict_nodecount++;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000609
610 /* red black adjustments */
611
612 node->color = dnode_red;
613
614 while (parent->color == dnode_red) {
615 grandpa = parent->parent;
616 if (parent == grandpa->left) {
617 uncle = grandpa->right;
618 if (uncle->color == dnode_red) { /* red parent, red uncle */
619 parent->color = dnode_black;
620 uncle->color = dnode_black;
621 grandpa->color = dnode_red;
622 node = grandpa;
623 parent = grandpa->parent;
624 } else { /* red parent, black uncle */
625 if (node == parent->right) {
626 rotate_left(parent);
627 parent = node;
628 assert (grandpa == parent->parent);
629 /* rotation between parent and child preserves grandpa */
630 }
631 parent->color = dnode_black;
632 grandpa->color = dnode_red;
633 rotate_right(grandpa);
634 break;
635 }
636 } else { /* symmetric cases: parent == parent->parent->right */
637 uncle = grandpa->left;
638 if (uncle->color == dnode_red) {
639 parent->color = dnode_black;
640 uncle->color = dnode_black;
641 grandpa->color = dnode_red;
642 node = grandpa;
643 parent = grandpa->parent;
644 } else {
645 if (node == parent->left) {
646 rotate_right(parent);
647 parent = node;
648 assert (grandpa == parent->parent);
649 }
650 parent->color = dnode_black;
651 grandpa->color = dnode_red;
652 rotate_left(grandpa);
653 break;
654 }
655 }
656 }
657
658 dict_root(dict)->color = dnode_black;
659
660}
661
662/*
663 * Allocate a node using the dictionary's allocator routine, give it
664 * the data item.
665 */
666
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000667static dnode_t *dnode_init(dnode_t *dnode, void *data)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000668{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000669 dnode->data = data;
670 dnode->parent = NULL;
671 dnode->left = NULL;
672 dnode->right = NULL;
673 return dnode;
674}
675
676static int dict_alloc_insert(dict_t *dict, const void *key, void *data)
677{
678 dnode_t *node = malloc(sizeof(dnode_t));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000679
680 if (node) {
681 dnode_init(node, data);
682 dict_insert(dict, node, key);
683 return 1;
684 }
685 return 0;
686}
687
688/*
689 * Return the node with the lowest (leftmost) key. If the dictionary is empty
690 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
691 */
692
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000693static dnode_t *dict_first(dict_t *dict)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000694{
695 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
696
697 if (root != nil)
698 while ((left = root->left) != nil)
699 root = left;
700
701 return (root == nil) ? NULL : root;
702}
703
704/*
705 * Return the given node's successor node---the node which has the
706 * next key in the the left to right ordering. If the node has
707 * no successor, a null pointer is returned rather than a pointer to
708 * the nil node.
709 */
710
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000711static dnode_t *dict_next(dict_t *dict, dnode_t *curr)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000712{
713 dnode_t *nil = dict_nil(dict), *parent, *left;
714
715 if (curr->right != nil) {
716 curr = curr->right;
717 while ((left = curr->left) != nil)
718 curr = left;
719 return curr;
720 }
721
722 parent = curr->parent;
723
724 while (parent != nil && curr == parent->right) {
725 curr = parent;
726 parent = curr->parent;
727 }
728
729 return (parent == nil) ? NULL : parent;
730}
731
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000732
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000733static void dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000734{
735 free(node);
736}
737
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000738
739#undef left
740#undef right
741#undef parent
742#undef color
743#undef key
744#undef data
745
746#undef nilnode
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000747#undef maxcount
748#undef compare
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000749#undef dupes
750
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000751
752/*
753 * dirinfo.c --- maintains the directory information table for e2fsck.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000754 */
755
756/*
757 * This subroutine is called during pass1 to create a directory info
758 * entry. During pass1, the passed-in parent is 0; it will get filled
759 * in during pass2.
760 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000761static void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000762{
763 struct dir_info *dir;
764 int i, j;
765 ext2_ino_t num_dirs;
766 errcode_t retval;
767 unsigned long old_size;
768
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000769 if (!ctx->dir_info) {
770 ctx->dir_info_count = 0;
771 retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
772 if (retval)
773 num_dirs = 1024; /* Guess */
774 ctx->dir_info_size = num_dirs + 10;
775 ctx->dir_info = (struct dir_info *)
776 e2fsck_allocate_memory(ctx, ctx->dir_info_size
777 * sizeof (struct dir_info),
778 "directory map");
779 }
780
781 if (ctx->dir_info_count >= ctx->dir_info_size) {
782 old_size = ctx->dir_info_size * sizeof(struct dir_info);
783 ctx->dir_info_size += 10;
784 retval = ext2fs_resize_mem(old_size, ctx->dir_info_size *
785 sizeof(struct dir_info),
786 &ctx->dir_info);
787 if (retval) {
788 ctx->dir_info_size -= 10;
789 return;
790 }
791 }
792
793 /*
794 * Normally, add_dir_info is called with each inode in
795 * sequential order; but once in a while (like when pass 3
796 * needs to recreate the root directory or lost+found
797 * directory) it is called out of order. In those cases, we
798 * need to move the dir_info entries down to make room, since
799 * the dir_info array needs to be sorted by inode number for
800 * get_dir_info()'s sake.
801 */
802 if (ctx->dir_info_count &&
803 ctx->dir_info[ctx->dir_info_count-1].ino >= ino) {
804 for (i = ctx->dir_info_count-1; i > 0; i--)
805 if (ctx->dir_info[i-1].ino < ino)
806 break;
807 dir = &ctx->dir_info[i];
808 if (dir->ino != ino)
809 for (j = ctx->dir_info_count++; j > i; j--)
810 ctx->dir_info[j] = ctx->dir_info[j-1];
811 } else
812 dir = &ctx->dir_info[ctx->dir_info_count++];
813
814 dir->ino = ino;
815 dir->dotdot = parent;
816 dir->parent = parent;
817}
818
819/*
820 * get_dir_info() --- given an inode number, try to find the directory
821 * information entry for it.
822 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000823static struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000824{
825 int low, high, mid;
826
827 low = 0;
828 high = ctx->dir_info_count-1;
829 if (!ctx->dir_info)
830 return 0;
831 if (ino == ctx->dir_info[low].ino)
832 return &ctx->dir_info[low];
833 if (ino == ctx->dir_info[high].ino)
834 return &ctx->dir_info[high];
835
836 while (low < high) {
837 mid = (low+high)/2;
838 if (mid == low || mid == high)
839 break;
840 if (ino == ctx->dir_info[mid].ino)
841 return &ctx->dir_info[mid];
842 if (ino < ctx->dir_info[mid].ino)
843 high = mid;
844 else
845 low = mid;
846 }
847 return 0;
848}
849
850/*
851 * Free the dir_info structure when it isn't needed any more.
852 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000853static void e2fsck_free_dir_info(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000854{
Rob Landleye7c43b62006-03-01 16:39:45 +0000855 ext2fs_free_mem(&ctx->dir_info);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000856 ctx->dir_info_size = 0;
857 ctx->dir_info_count = 0;
858}
859
860/*
861 * Return the count of number of directories in the dir_info structure
862 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000863static inline int e2fsck_get_num_dirinfo(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000864{
865 return ctx->dir_info_count;
866}
867
868/*
869 * A simple interator function
870 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000871static struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000872{
873 if (*control >= ctx->dir_info_count)
874 return 0;
875
876 return(ctx->dir_info + (*control)++);
877}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000878
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000879/*
880 * dirinfo.c --- maintains the directory information table for e2fsck.
881 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000882 */
883
884#ifdef ENABLE_HTREE
885
886/*
887 * This subroutine is called during pass1 to create a directory info
888 * entry. During pass1, the passed-in parent is 0; it will get filled
889 * in during pass2.
890 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000891static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000892{
893 struct dx_dir_info *dir;
894 int i, j;
895 errcode_t retval;
896 unsigned long old_size;
897
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000898 if (!ctx->dx_dir_info) {
899 ctx->dx_dir_info_count = 0;
900 ctx->dx_dir_info_size = 100; /* Guess */
901 ctx->dx_dir_info = (struct dx_dir_info *)
902 e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
903 * sizeof (struct dx_dir_info),
904 "directory map");
905 }
906
907 if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
908 old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
909 ctx->dx_dir_info_size += 10;
910 retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
911 sizeof(struct dx_dir_info),
912 &ctx->dx_dir_info);
913 if (retval) {
914 ctx->dx_dir_info_size -= 10;
915 return;
916 }
917 }
918
919 /*
920 * Normally, add_dx_dir_info is called with each inode in
921 * sequential order; but once in a while (like when pass 3
922 * needs to recreate the root directory or lost+found
923 * directory) it is called out of order. In those cases, we
924 * need to move the dx_dir_info entries down to make room, since
925 * the dx_dir_info array needs to be sorted by inode number for
926 * get_dx_dir_info()'s sake.
927 */
928 if (ctx->dx_dir_info_count &&
929 ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
930 for (i = ctx->dx_dir_info_count-1; i > 0; i--)
931 if (ctx->dx_dir_info[i-1].ino < ino)
932 break;
933 dir = &ctx->dx_dir_info[i];
934 if (dir->ino != ino)
935 for (j = ctx->dx_dir_info_count++; j > i; j--)
936 ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
937 } else
938 dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
939
940 dir->ino = ino;
941 dir->numblocks = num_blocks;
942 dir->hashversion = 0;
943 dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
944 * sizeof (struct dx_dirblock_info),
945 "dx_block info array");
946
947}
948
949/*
950 * get_dx_dir_info() --- given an inode number, try to find the directory
951 * information entry for it.
952 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000953static struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000954{
955 int low, high, mid;
956
957 low = 0;
958 high = ctx->dx_dir_info_count-1;
959 if (!ctx->dx_dir_info)
960 return 0;
961 if (ino == ctx->dx_dir_info[low].ino)
962 return &ctx->dx_dir_info[low];
963 if (ino == ctx->dx_dir_info[high].ino)
964 return &ctx->dx_dir_info[high];
965
966 while (low < high) {
967 mid = (low+high)/2;
968 if (mid == low || mid == high)
969 break;
970 if (ino == ctx->dx_dir_info[mid].ino)
971 return &ctx->dx_dir_info[mid];
972 if (ino < ctx->dx_dir_info[mid].ino)
973 high = mid;
974 else
975 low = mid;
976 }
977 return 0;
978}
979
980/*
981 * Free the dx_dir_info structure when it isn't needed any more.
982 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000983static void e2fsck_free_dx_dir_info(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000984{
985 int i;
986 struct dx_dir_info *dir;
987
988 if (ctx->dx_dir_info) {
989 dir = ctx->dx_dir_info;
990 for (i=0; i < ctx->dx_dir_info_count; i++) {
Rob Landleye7c43b62006-03-01 16:39:45 +0000991 ext2fs_free_mem(&dir->dx_block);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000992 }
993 ext2fs_free_mem(&ctx->dx_dir_info);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000994 }
995 ctx->dx_dir_info_size = 0;
996 ctx->dx_dir_info_count = 0;
997}
998
999/*
1000 * A simple interator function
1001 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001002static struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001003{
1004 if (*control >= ctx->dx_dir_info_count)
1005 return 0;
1006
1007 return(ctx->dx_dir_info + (*control)++);
1008}
1009
1010#endif /* ENABLE_HTREE */
1011/*
1012 * e2fsck.c - a consistency checker for the new extended file system.
1013 *
Mike Frysinger51a43b42005-09-24 07:11:16 +00001014 */
1015
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001016/*
1017 * This function allocates an e2fsck context
1018 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001019static errcode_t e2fsck_allocate_context(e2fsck_t *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001020{
1021 e2fsck_t context;
1022 errcode_t retval;
1023
1024 retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
1025 if (retval)
1026 return retval;
1027
1028 memset(context, 0, sizeof(struct e2fsck_struct));
1029
1030 context->process_inode_size = 256;
1031 context->ext_attr_ver = 2;
1032
1033 *ret = context;
1034 return 0;
1035}
1036
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001037struct ea_refcount_el {
1038 blk_t ea_blk;
1039 int ea_count;
1040};
1041
1042struct ea_refcount {
1043 blk_t count;
1044 blk_t size;
1045 blk_t cursor;
1046 struct ea_refcount_el *list;
1047};
1048
1049static void ea_refcount_free(ext2_refcount_t refcount)
1050{
1051 if (!refcount)
1052 return;
1053
Rob Landleye7c43b62006-03-01 16:39:45 +00001054 ext2fs_free_mem(&refcount->list);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001055 ext2fs_free_mem(&refcount);
1056}
1057
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001058/*
1059 * This function resets an e2fsck context; it is called when e2fsck
1060 * needs to be restarted.
1061 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001062static errcode_t e2fsck_reset_context(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001063{
1064 ctx->flags = 0;
1065 ctx->lost_and_found = 0;
1066 ctx->bad_lost_and_found = 0;
Rob Landleye7c43b62006-03-01 16:39:45 +00001067 ext2fs_free_inode_bitmap(ctx->inode_used_map);
1068 ctx->inode_used_map = 0;
1069 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
1070 ctx->inode_dir_map = 0;
1071 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
1072 ctx->inode_reg_map = 0;
1073 ext2fs_free_block_bitmap(ctx->block_found_map);
1074 ctx->block_found_map = 0;
1075 ext2fs_free_icount(ctx->inode_link_info);
1076 ctx->inode_link_info = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001077 if (ctx->journal_io) {
1078 if (ctx->fs && ctx->fs->io != ctx->journal_io)
1079 io_channel_close(ctx->journal_io);
1080 ctx->journal_io = 0;
1081 }
Rob Landleye7c43b62006-03-01 16:39:45 +00001082 if (ctx->fs) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001083 ext2fs_free_dblist(ctx->fs->dblist);
1084 ctx->fs->dblist = 0;
1085 }
1086 e2fsck_free_dir_info(ctx);
1087#ifdef ENABLE_HTREE
1088 e2fsck_free_dx_dir_info(ctx);
Mike Frysinger51a43b42005-09-24 07:11:16 +00001089#endif
Rob Landleye7c43b62006-03-01 16:39:45 +00001090 ea_refcount_free(ctx->refcount);
1091 ctx->refcount = 0;
1092 ea_refcount_free(ctx->refcount_extra);
1093 ctx->refcount_extra = 0;
1094 ext2fs_free_block_bitmap(ctx->block_dup_map);
1095 ctx->block_dup_map = 0;
1096 ext2fs_free_block_bitmap(ctx->block_ea_map);
1097 ctx->block_ea_map = 0;
1098 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
1099 ctx->inode_bb_map = 0;
1100 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
1101 ctx->inode_bad_map = 0;
1102 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
1103 ctx->inode_imagic_map = 0;
1104 ext2fs_u32_list_free(ctx->dirs_to_hash);
1105 ctx->dirs_to_hash = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001106
1107 /*
1108 * Clear the array of invalid meta-data flags
1109 */
Rob Landleye7c43b62006-03-01 16:39:45 +00001110 ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
1111 ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
1112 ext2fs_free_mem(&ctx->invalid_inode_table_flag);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001113
1114 /* Clear statistic counters */
1115 ctx->fs_directory_count = 0;
1116 ctx->fs_regular_count = 0;
1117 ctx->fs_blockdev_count = 0;
1118 ctx->fs_chardev_count = 0;
1119 ctx->fs_links_count = 0;
1120 ctx->fs_symlinks_count = 0;
1121 ctx->fs_fast_symlinks_count = 0;
1122 ctx->fs_fifo_count = 0;
1123 ctx->fs_total_count = 0;
1124 ctx->fs_badblocks_count = 0;
1125 ctx->fs_sockets_count = 0;
1126 ctx->fs_ind_count = 0;
1127 ctx->fs_dind_count = 0;
1128 ctx->fs_tind_count = 0;
1129 ctx->fs_fragmented = 0;
1130 ctx->large_files = 0;
1131
1132 /* Reset the superblock to the user's requested value */
1133 ctx->superblock = ctx->use_superblock;
1134
1135 return 0;
1136}
1137
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001138static void e2fsck_free_context(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001139{
1140 if (!ctx)
1141 return;
1142
1143 e2fsck_reset_context(ctx);
1144 if (ctx->blkid)
1145 blkid_put_cache(ctx->blkid);
1146
1147 ext2fs_free_mem(&ctx);
1148}
1149
1150/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001151 * ea_refcount.c
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001152 */
1153
1154/*
1155 * The strategy we use for keeping track of EA refcounts is as
1156 * follows. We keep a sorted array of first EA blocks and its
1157 * reference counts. Once the refcount has dropped to zero, it is
1158 * removed from the array to save memory space. Once the EA block is
1159 * checked, its bit is set in the block_ea_map bitmap.
1160 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001161
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001162
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001163static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001164{
1165 ext2_refcount_t refcount;
1166 errcode_t retval;
1167 size_t bytes;
1168
1169 retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount);
1170 if (retval)
1171 return retval;
1172 memset(refcount, 0, sizeof(struct ea_refcount));
1173
1174 if (!size)
1175 size = 500;
1176 refcount->size = size;
1177 bytes = (size_t) (size * sizeof(struct ea_refcount_el));
1178#ifdef DEBUG
1179 printf("Refcount allocated %d entries, %d bytes.\n",
1180 refcount->size, bytes);
1181#endif
1182 retval = ext2fs_get_mem(bytes, &refcount->list);
1183 if (retval)
1184 goto errout;
1185 memset(refcount->list, 0, bytes);
1186
1187 refcount->count = 0;
1188 refcount->cursor = 0;
1189
1190 *ret = refcount;
1191 return 0;
1192
1193errout:
1194 ea_refcount_free(refcount);
1195 return(retval);
1196}
1197
1198/*
1199 * collapse_refcount() --- go through the refcount array, and get rid
1200 * of any count == zero entries
1201 */
1202static void refcount_collapse(ext2_refcount_t refcount)
1203{
1204 unsigned int i, j;
1205 struct ea_refcount_el *list;
1206
1207 list = refcount->list;
1208 for (i = 0, j = 0; i < refcount->count; i++) {
1209 if (list[i].ea_count) {
1210 if (i != j)
1211 list[j] = list[i];
1212 j++;
1213 }
1214 }
1215#if defined(DEBUG) || defined(TEST_PROGRAM)
1216 printf("Refcount_collapse: size was %d, now %d\n",
1217 refcount->count, j);
1218#endif
1219 refcount->count = j;
1220}
1221
1222
1223/*
1224 * insert_refcount_el() --- Insert a new entry into the sorted list at a
1225 * specified position.
1226 */
1227static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
1228 blk_t blk, int pos)
1229{
1230 struct ea_refcount_el *el;
1231 errcode_t retval;
1232 blk_t new_size = 0;
1233 int num;
1234
1235 if (refcount->count >= refcount->size) {
1236 new_size = refcount->size + 100;
1237#ifdef DEBUG
1238 printf("Reallocating refcount %d entries...\n", new_size);
1239#endif
1240 retval = ext2fs_resize_mem((size_t) refcount->size *
1241 sizeof(struct ea_refcount_el),
1242 (size_t) new_size *
1243 sizeof(struct ea_refcount_el),
1244 &refcount->list);
1245 if (retval)
1246 return 0;
1247 refcount->size = new_size;
1248 }
1249 num = (int) refcount->count - pos;
1250 if (num < 0)
1251 return 0; /* should never happen */
1252 if (num) {
1253 memmove(&refcount->list[pos+1], &refcount->list[pos],
1254 sizeof(struct ea_refcount_el) * num);
1255 }
1256 refcount->count++;
1257 el = &refcount->list[pos];
1258 el->ea_count = 0;
1259 el->ea_blk = blk;
1260 return el;
1261}
1262
1263
1264/*
1265 * get_refcount_el() --- given an block number, try to find refcount
1266 * information in the sorted list. If the create flag is set,
1267 * and we can't find an entry, create one in the sorted list.
1268 */
1269static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
1270 blk_t blk, int create)
1271{
1272 float range;
1273 int low, high, mid;
1274 blk_t lowval, highval;
1275
1276 if (!refcount || !refcount->list)
1277 return 0;
1278retry:
1279 low = 0;
1280 high = (int) refcount->count-1;
1281 if (create && ((refcount->count == 0) ||
1282 (blk > refcount->list[high].ea_blk))) {
1283 if (refcount->count >= refcount->size)
1284 refcount_collapse(refcount);
1285
1286 return insert_refcount_el(refcount, blk,
1287 (unsigned) refcount->count);
1288 }
1289 if (refcount->count == 0)
1290 return 0;
1291
1292 if (refcount->cursor >= refcount->count)
1293 refcount->cursor = 0;
1294 if (blk == refcount->list[refcount->cursor].ea_blk)
1295 return &refcount->list[refcount->cursor++];
1296#ifdef DEBUG
1297 printf("Non-cursor get_refcount_el: %u\n", blk);
1298#endif
1299 while (low <= high) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001300 if (low == high)
1301 mid = low;
1302 else {
1303 /* Interpolate for efficiency */
1304 lowval = refcount->list[low].ea_blk;
1305 highval = refcount->list[high].ea_blk;
1306
1307 if (blk < lowval)
1308 range = 0;
1309 else if (blk > highval)
1310 range = 1;
1311 else
1312 range = ((float) (blk - lowval)) /
1313 (highval - lowval);
1314 mid = low + ((int) (range * (high-low)));
1315 }
Rob Landley3e72c592006-04-06 22:49:04 +00001316
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001317 if (blk == refcount->list[mid].ea_blk) {
1318 refcount->cursor = mid+1;
1319 return &refcount->list[mid];
1320 }
1321 if (blk < refcount->list[mid].ea_blk)
1322 high = mid-1;
1323 else
1324 low = mid+1;
1325 }
1326 /*
1327 * If we need to create a new entry, it should be right at
1328 * low (where high will be left at low-1).
1329 */
1330 if (create) {
1331 if (refcount->count >= refcount->size) {
1332 refcount_collapse(refcount);
1333 if (refcount->count < refcount->size)
1334 goto retry;
1335 }
1336 return insert_refcount_el(refcount, blk, low);
1337 }
1338 return 0;
1339}
1340
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001341static errcode_t
1342ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001343{
1344 struct ea_refcount_el *el;
1345
1346 el = get_refcount_el(refcount, blk, 1);
1347 if (!el)
1348 return EXT2_ET_NO_MEMORY;
1349 el->ea_count++;
1350
1351 if (ret)
1352 *ret = el->ea_count;
1353 return 0;
1354}
1355
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001356static errcode_t
1357ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001358{
1359 struct ea_refcount_el *el;
1360
1361 el = get_refcount_el(refcount, blk, 0);
1362 if (!el || el->ea_count == 0)
1363 return EXT2_ET_INVALID_ARGUMENT;
1364
1365 el->ea_count--;
1366
1367 if (ret)
1368 *ret = el->ea_count;
1369 return 0;
1370}
1371
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001372static errcode_t
1373ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001374{
1375 struct ea_refcount_el *el;
1376
1377 /*
1378 * Get the refcount element
1379 */
1380 el = get_refcount_el(refcount, blk, count ? 1 : 0);
1381 if (!el)
1382 return count ? EXT2_ET_NO_MEMORY : 0;
1383 el->ea_count = count;
1384 return 0;
1385}
1386
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001387static inline void ea_refcount_intr_begin(ext2_refcount_t refcount)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001388{
1389 refcount->cursor = 0;
1390}
1391
1392
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001393static blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001394{
1395 struct ea_refcount_el *list;
1396
1397 while (1) {
1398 if (refcount->cursor >= refcount->count)
1399 return 0;
1400 list = refcount->list;
1401 if (list[refcount->cursor].ea_count) {
1402 if (ret)
1403 *ret = list[refcount->cursor].ea_count;
1404 return list[refcount->cursor++].ea_blk;
1405 }
1406 refcount->cursor++;
1407 }
1408}
1409
1410
1411/*
1412 * ehandler.c --- handle bad block errors which come up during the
1413 * course of an e2fsck session.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001414 */
1415
1416
1417static const char *operation;
1418
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001419static errcode_t
1420e2fsck_handle_read_error(io_channel channel, unsigned long block, int count,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00001421 void *data, size_t size FSCK_ATTR((unused)),
1422 int actual FSCK_ATTR((unused)), errcode_t error)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001423{
1424 int i;
1425 char *p;
1426 ext2_filsys fs = (ext2_filsys) channel->app_data;
1427 e2fsck_t ctx;
1428
1429 ctx = (e2fsck_t) fs->priv_data;
1430
1431 /*
1432 * If more than one block was read, try reading each block
1433 * separately. We could use the actual bytes read to figure
1434 * out where to start, but we don't bother.
1435 */
1436 if (count > 1) {
1437 p = (char *) data;
1438 for (i=0; i < count; i++, p += channel->block_size, block++) {
1439 error = io_channel_read_blk(channel, block,
1440 1, p);
1441 if (error)
1442 return error;
1443 }
1444 return 0;
1445 }
1446 if (operation)
1447 printf(_("Error reading block %lu (%s) while %s. "), block,
1448 error_message(error), operation);
1449 else
1450 printf(_("Error reading block %lu (%s). "), block,
1451 error_message(error));
1452 preenhalt(ctx);
1453 if (ask(ctx, _("Ignore error"), 1)) {
1454 if (ask(ctx, _("Force rewrite"), 1))
1455 io_channel_write_blk(channel, block, 1, data);
1456 return 0;
1457 }
1458
1459 return error;
1460}
1461
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001462static errcode_t
1463e2fsck_handle_write_error(io_channel channel, unsigned long block, int count,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00001464 const void *data, size_t size FSCK_ATTR((unused)),
1465 int actual FSCK_ATTR((unused)), errcode_t error)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001466{
1467 int i;
1468 const char *p;
1469 ext2_filsys fs = (ext2_filsys) channel->app_data;
1470 e2fsck_t ctx;
1471
1472 ctx = (e2fsck_t) fs->priv_data;
1473
1474 /*
1475 * If more than one block was written, try writing each block
1476 * separately. We could use the actual bytes read to figure
1477 * out where to start, but we don't bother.
1478 */
1479 if (count > 1) {
1480 p = (const char *) data;
1481 for (i=0; i < count; i++, p += channel->block_size, block++) {
1482 error = io_channel_write_blk(channel, block,
1483 1, p);
1484 if (error)
1485 return error;
1486 }
1487 return 0;
1488 }
1489
1490 if (operation)
1491 printf(_("Error writing block %lu (%s) while %s. "), block,
1492 error_message(error), operation);
1493 else
1494 printf(_("Error writing block %lu (%s). "), block,
1495 error_message(error));
1496 preenhalt(ctx);
1497 if (ask(ctx, _("Ignore error"), 1))
1498 return 0;
1499
1500 return error;
1501}
1502
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001503static inline const char *ehandler_operation(const char *op)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001504{
1505 const char *ret = operation;
1506
1507 operation = op;
1508 return ret;
1509}
1510
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001511static void ehandler_init(io_channel channel)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001512{
1513 channel->read_error = e2fsck_handle_read_error;
1514 channel->write_error = e2fsck_handle_write_error;
1515}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001516
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001517/*
1518 * journal.c --- code for handling the "ext3" journal
1519 *
1520 * Copyright (C) 2000 Andreas Dilger
1521 * Copyright (C) 2000 Theodore Ts'o
1522 *
1523 * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie
1524 * Copyright (C) 1999 Red Hat Software
1525 *
1526 * This file may be redistributed under the terms of the
1527 * GNU General Public License version 2 or at your discretion
1528 * any later version.
1529 */
1530
1531#define MNT_FL (MS_MGC_VAL | MS_RDONLY)
1532
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001533/*
1534 * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
1535 * This creates a larger static binary, and a smaller binary using
1536 * shared libraries. It's also probably slightly less CPU-efficient,
1537 * which is why it's not on by default. But, it's a good way of
1538 * testing the functions in inode_io.c and fileio.c.
1539 */
1540#undef USE_INODE_IO
1541
1542/* Kernel compatibility functions for handling the journal. These allow us
1543 * to use the recovery.c file virtually unchanged from the kernel, so we
1544 * don't have to do much to keep kernel and user recovery in sync.
1545 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001546static int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001547{
1548#ifdef USE_INODE_IO
1549 *phys = block;
1550 return 0;
1551#else
1552 struct inode *inode = journal->j_inode;
1553 errcode_t retval;
1554 blk_t pblk;
1555
1556 if (!inode) {
1557 *phys = block;
1558 return 0;
1559 }
1560
1561 retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino,
1562 &inode->i_ext2, NULL, 0, block, &pblk);
1563 *phys = pblk;
1564 return (retval);
1565#endif
1566}
1567
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001568static struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001569{
1570 struct buffer_head *bh;
1571
1572 bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer");
1573 if (!bh)
1574 return NULL;
1575
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001576 bh->b_ctx = kdev->k_ctx;
1577 if (kdev->k_dev == K_DEV_FS)
1578 bh->b_io = kdev->k_ctx->fs->io;
1579 else
1580 bh->b_io = kdev->k_ctx->journal_io;
1581 bh->b_size = blocksize;
1582 bh->b_blocknr = blocknr;
1583
1584 return bh;
1585}
1586
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001587static void sync_blockdev(kdev_t kdev)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001588{
1589 io_channel io;
1590
1591 if (kdev->k_dev == K_DEV_FS)
1592 io = kdev->k_ctx->fs->io;
1593 else
1594 io = kdev->k_ctx->journal_io;
1595
1596 io_channel_flush(io);
1597}
1598
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001599static void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001600{
1601 int retval;
1602 struct buffer_head *bh;
1603
1604 for (; nr > 0; --nr) {
1605 bh = *bhp++;
1606 if (rw == READ && !bh->b_uptodate) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001607 retval = io_channel_read_blk(bh->b_io,
1608 bh->b_blocknr,
1609 1, bh->b_data);
1610 if (retval) {
1611 com_err(bh->b_ctx->device_name, retval,
1612 "while reading block %lu\n",
1613 (unsigned long) bh->b_blocknr);
1614 bh->b_err = retval;
1615 continue;
1616 }
1617 bh->b_uptodate = 1;
1618 } else if (rw == WRITE && bh->b_dirty) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001619 retval = io_channel_write_blk(bh->b_io,
1620 bh->b_blocknr,
1621 1, bh->b_data);
1622 if (retval) {
1623 com_err(bh->b_ctx->device_name, retval,
1624 "while writing block %lu\n",
1625 (unsigned long) bh->b_blocknr);
1626 bh->b_err = retval;
1627 continue;
1628 }
1629 bh->b_dirty = 0;
1630 bh->b_uptodate = 1;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001631 }
1632 }
1633}
1634
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001635static inline void mark_buffer_dirty(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001636{
1637 bh->b_dirty = 1;
1638}
1639
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001640static inline void mark_buffer_clean(struct buffer_head * bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001641{
1642 bh->b_dirty = 0;
1643}
1644
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001645static void brelse(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001646{
1647 if (bh->b_dirty)
1648 ll_rw_block(WRITE, 1, &bh);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001649 ext2fs_free_mem(&bh);
1650}
1651
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001652static inline int buffer_uptodate(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001653{
1654 return bh->b_uptodate;
1655}
1656
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001657static inline void mark_buffer_uptodate(struct buffer_head *bh, int val)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001658{
1659 bh->b_uptodate = val;
1660}
1661
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001662static void wait_on_buffer(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001663{
1664 if (!bh->b_uptodate)
1665 ll_rw_block(READ, 1, &bh);
1666}
1667
1668
1669static void e2fsck_clear_recover(e2fsck_t ctx, int error)
1670{
1671 ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
1672
1673 /* if we had an error doing journal recovery, we need a full fsck */
1674 if (error)
1675 ctx->fs->super->s_state &= ~EXT2_VALID_FS;
1676 ext2fs_mark_super_dirty(ctx->fs);
1677}
1678
1679static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
1680{
1681 struct ext2_super_block *sb = ctx->fs->super;
1682 struct ext2_super_block jsuper;
1683 struct problem_context pctx;
1684 struct buffer_head *bh;
1685 struct inode *j_inode = NULL;
1686 struct kdev_s *dev_fs = NULL, *dev_journal;
1687 const char *journal_name = 0;
1688 journal_t *journal = NULL;
1689 errcode_t retval = 0;
1690 io_manager io_ptr = 0;
1691 unsigned long start = 0;
1692 blk_t blk;
1693 int ext_journal = 0;
1694 int tried_backup_jnl = 0;
1695 int i;
1696
1697 clear_problem_context(&pctx);
1698
1699 journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
1700 if (!journal) {
1701 return EXT2_ET_NO_MEMORY;
1702 }
1703
1704 dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
1705 if (!dev_fs) {
1706 retval = EXT2_ET_NO_MEMORY;
1707 goto errout;
1708 }
1709 dev_journal = dev_fs+1;
1710
1711 dev_fs->k_ctx = dev_journal->k_ctx = ctx;
1712 dev_fs->k_dev = K_DEV_FS;
1713 dev_journal->k_dev = K_DEV_JOURNAL;
1714
1715 journal->j_dev = dev_journal;
1716 journal->j_fs_dev = dev_fs;
1717 journal->j_inode = NULL;
1718 journal->j_blocksize = ctx->fs->blocksize;
1719
1720 if (uuid_is_null(sb->s_journal_uuid)) {
1721 if (!sb->s_journal_inum)
1722 return EXT2_ET_BAD_INODE_NUM;
1723 j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
1724 "journal inode");
1725 if (!j_inode) {
1726 retval = EXT2_ET_NO_MEMORY;
1727 goto errout;
1728 }
1729
1730 j_inode->i_ctx = ctx;
1731 j_inode->i_ino = sb->s_journal_inum;
1732
1733 if ((retval = ext2fs_read_inode(ctx->fs,
1734 sb->s_journal_inum,
1735 &j_inode->i_ext2))) {
1736 try_backup_journal:
1737 if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
1738 tried_backup_jnl)
1739 goto errout;
1740 memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
1741 memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
1742 EXT2_N_BLOCKS*4);
1743 j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
1744 j_inode->i_ext2.i_links_count = 1;
1745 j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
1746 tried_backup_jnl++;
1747 }
1748 if (!j_inode->i_ext2.i_links_count ||
1749 !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
1750 retval = EXT2_ET_NO_JOURNAL;
1751 goto try_backup_journal;
1752 }
1753 if (j_inode->i_ext2.i_size / journal->j_blocksize <
1754 JFS_MIN_JOURNAL_BLOCKS) {
1755 retval = EXT2_ET_JOURNAL_TOO_SMALL;
1756 goto try_backup_journal;
1757 }
1758 for (i=0; i < EXT2_N_BLOCKS; i++) {
1759 blk = j_inode->i_ext2.i_block[i];
1760 if (!blk) {
1761 if (i < EXT2_NDIR_BLOCKS) {
1762 retval = EXT2_ET_JOURNAL_TOO_SMALL;
1763 goto try_backup_journal;
1764 }
1765 continue;
1766 }
1767 if (blk < sb->s_first_data_block ||
1768 blk >= sb->s_blocks_count) {
1769 retval = EXT2_ET_BAD_BLOCK_NUM;
1770 goto try_backup_journal;
1771 }
1772 }
1773 journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;
1774
1775#ifdef USE_INODE_IO
1776 retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
1777 &j_inode->i_ext2,
1778 &journal_name);
1779 if (retval)
1780 goto errout;
1781
1782 io_ptr = inode_io_manager;
1783#else
1784 journal->j_inode = j_inode;
1785 ctx->journal_io = ctx->fs->io;
1786 if ((retval = journal_bmap(journal, 0, &start)) != 0)
1787 goto errout;
1788#endif
1789 } else {
1790 ext_journal = 1;
1791 if (!ctx->journal_name) {
1792 char uuid[37];
1793
1794 uuid_unparse(sb->s_journal_uuid, uuid);
1795 ctx->journal_name = blkid_get_devname(ctx->blkid,
1796 "UUID", uuid);
1797 if (!ctx->journal_name)
1798 ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
1799 }
1800 journal_name = ctx->journal_name;
1801
1802 if (!journal_name) {
1803 fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
1804 return EXT2_ET_LOAD_EXT_JOURNAL;
1805 }
1806
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001807 io_ptr = unix_io_manager;
1808 }
1809
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001810#ifndef USE_INODE_IO
1811 if (ext_journal)
1812#endif
1813 retval = io_ptr->open(journal_name, IO_FLAG_RW,
1814 &ctx->journal_io);
1815 if (retval)
1816 goto errout;
1817
1818 io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
1819
1820 if (ext_journal) {
1821 if (ctx->fs->blocksize == 1024)
1822 start = 1;
1823 bh = getblk(dev_journal, start, ctx->fs->blocksize);
1824 if (!bh) {
1825 retval = EXT2_ET_NO_MEMORY;
1826 goto errout;
1827 }
1828 ll_rw_block(READ, 1, &bh);
1829 if ((retval = bh->b_err) != 0)
1830 goto errout;
1831 memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
1832 sizeof(jsuper));
1833 brelse(bh);
1834#ifdef EXT2FS_ENABLE_SWAPFS
1835 if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
1836 ext2fs_swap_super(&jsuper);
1837#endif
1838 if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
1839 !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
1840 fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
1841 retval = EXT2_ET_LOAD_EXT_JOURNAL;
1842 goto errout;
1843 }
1844 /* Make sure the journal UUID is correct */
1845 if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
1846 sizeof(jsuper.s_uuid))) {
1847 fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
1848 retval = EXT2_ET_LOAD_EXT_JOURNAL;
1849 goto errout;
1850 }
1851
1852 journal->j_maxlen = jsuper.s_blocks_count;
1853 start++;
1854 }
1855
1856 if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
1857 retval = EXT2_ET_NO_MEMORY;
1858 goto errout;
1859 }
1860
1861 journal->j_sb_buffer = bh;
1862 journal->j_superblock = (journal_superblock_t *)bh->b_data;
1863
1864#ifdef USE_INODE_IO
Rob Landleye7c43b62006-03-01 16:39:45 +00001865 ext2fs_free_mem(&j_inode);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001866#endif
1867
1868 *ret_journal = journal;
1869 return 0;
1870
1871errout:
Rob Landleye7c43b62006-03-01 16:39:45 +00001872 ext2fs_free_mem(&dev_fs);
1873 ext2fs_free_mem(&j_inode);
1874 ext2fs_free_mem(&journal);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001875 return retval;
1876
1877}
1878
1879static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
1880 struct problem_context *pctx)
1881{
1882 struct ext2_super_block *sb = ctx->fs->super;
1883 int recover = ctx->fs->super->s_feature_incompat &
1884 EXT3_FEATURE_INCOMPAT_RECOVER;
1885 int has_journal = ctx->fs->super->s_feature_compat &
1886 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
1887
1888 if (has_journal || sb->s_journal_inum) {
1889 /* The journal inode is bogus, remove and force full fsck */
1890 pctx->ino = sb->s_journal_inum;
1891 if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
1892 if (has_journal && sb->s_journal_inum)
1893 printf("*** ext3 journal has been deleted - "
1894 "filesystem is now ext2 only ***\n\n");
1895 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
1896 sb->s_journal_inum = 0;
1897 ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */
1898 e2fsck_clear_recover(ctx, 1);
1899 return 0;
1900 }
1901 return EXT2_ET_BAD_INODE_NUM;
1902 } else if (recover) {
1903 if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
1904 e2fsck_clear_recover(ctx, 1);
1905 return 0;
1906 }
1907 return EXT2_ET_UNSUPP_FEATURE;
1908 }
1909 return 0;
1910}
1911
1912#define V1_SB_SIZE 0x0024
1913static void clear_v2_journal_fields(journal_t *journal)
1914{
1915 e2fsck_t ctx = journal->j_dev->k_ctx;
1916 struct problem_context pctx;
1917
1918 clear_problem_context(&pctx);
1919
1920 if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
1921 return;
1922
1923 memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
1924 ctx->fs->blocksize-V1_SB_SIZE);
1925 mark_buffer_dirty(journal->j_sb_buffer);
1926}
1927
1928
1929static errcode_t e2fsck_journal_load(journal_t *journal)
1930{
1931 e2fsck_t ctx = journal->j_dev->k_ctx;
1932 journal_superblock_t *jsb;
1933 struct buffer_head *jbh = journal->j_sb_buffer;
1934 struct problem_context pctx;
1935
1936 clear_problem_context(&pctx);
1937
1938 ll_rw_block(READ, 1, &jbh);
1939 if (jbh->b_err) {
1940 com_err(ctx->device_name, jbh->b_err,
1941 _("reading journal superblock\n"));
1942 return jbh->b_err;
1943 }
1944
1945 jsb = journal->j_superblock;
1946 /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
1947 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
1948 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
1949
1950 switch (ntohl(jsb->s_header.h_blocktype)) {
1951 case JFS_SUPERBLOCK_V1:
1952 journal->j_format_version = 1;
1953 if (jsb->s_feature_compat ||
1954 jsb->s_feature_incompat ||
1955 jsb->s_feature_ro_compat ||
1956 jsb->s_nr_users)
1957 clear_v2_journal_fields(journal);
1958 break;
1959
1960 case JFS_SUPERBLOCK_V2:
1961 journal->j_format_version = 2;
1962 if (ntohl(jsb->s_nr_users) > 1 &&
1963 uuid_is_null(ctx->fs->super->s_journal_uuid))
1964 clear_v2_journal_fields(journal);
1965 if (ntohl(jsb->s_nr_users) > 1) {
1966 fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
1967 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
1968 }
1969 break;
1970
1971 /*
1972 * These should never appear in a journal super block, so if
1973 * they do, the journal is badly corrupted.
1974 */
1975 case JFS_DESCRIPTOR_BLOCK:
1976 case JFS_COMMIT_BLOCK:
1977 case JFS_REVOKE_BLOCK:
1978 return EXT2_ET_CORRUPT_SUPERBLOCK;
1979
1980 /* If we don't understand the superblock major type, but there
1981 * is a magic number, then it is likely to be a new format we
1982 * just don't understand, so leave it alone. */
1983 default:
1984 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
1985 }
1986
1987 if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
1988 return EXT2_ET_UNSUPP_FEATURE;
1989
1990 if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
1991 return EXT2_ET_RO_UNSUPP_FEATURE;
1992
1993 /* We have now checked whether we know enough about the journal
1994 * format to be able to proceed safely, so any other checks that
1995 * fail we should attempt to recover from. */
1996 if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
1997 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
1998 _("%s: no valid journal superblock found\n"),
1999 ctx->device_name);
2000 return EXT2_ET_CORRUPT_SUPERBLOCK;
2001 }
2002
2003 if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
2004 journal->j_maxlen = ntohl(jsb->s_maxlen);
2005 else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
2006 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
2007 _("%s: journal too short\n"),
2008 ctx->device_name);
2009 return EXT2_ET_CORRUPT_SUPERBLOCK;
2010 }
2011
2012 journal->j_tail_sequence = ntohl(jsb->s_sequence);
2013 journal->j_transaction_sequence = journal->j_tail_sequence;
2014 journal->j_tail = ntohl(jsb->s_start);
2015 journal->j_first = ntohl(jsb->s_first);
2016 journal->j_last = ntohl(jsb->s_maxlen);
2017
2018 return 0;
2019}
2020
2021static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
2022 journal_t *journal)
2023{
2024 char *p;
2025 union {
2026 uuid_t uuid;
2027 __u32 val[4];
2028 } u;
2029 __u32 new_seq = 0;
2030 int i;
2031
2032 /* Leave a valid existing V1 superblock signature alone.
2033 * Anything unrecognisable we overwrite with a new V2
2034 * signature. */
2035
2036 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
2037 jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
2038 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
2039 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
2040 }
2041
2042 /* Zero out everything else beyond the superblock header */
2043
2044 p = ((char *) jsb) + sizeof(journal_header_t);
2045 memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
2046
2047 jsb->s_blocksize = htonl(ctx->fs->blocksize);
2048 jsb->s_maxlen = htonl(journal->j_maxlen);
2049 jsb->s_first = htonl(1);
2050
2051 /* Initialize the journal sequence number so that there is "no"
2052 * chance we will find old "valid" transactions in the journal.
2053 * This avoids the need to zero the whole journal (slow to do,
2054 * and risky when we are just recovering the filesystem).
2055 */
2056 uuid_generate(u.uuid);
2057 for (i = 0; i < 4; i ++)
2058 new_seq ^= u.val[i];
2059 jsb->s_sequence = htonl(new_seq);
2060
2061 mark_buffer_dirty(journal->j_sb_buffer);
2062 ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
2063}
2064
2065static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
2066 journal_t *journal,
2067 struct problem_context *pctx)
2068{
2069 struct ext2_super_block *sb = ctx->fs->super;
2070 int recover = ctx->fs->super->s_feature_incompat &
2071 EXT3_FEATURE_INCOMPAT_RECOVER;
2072
2073 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
2074 if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
2075 e2fsck_journal_reset_super(ctx, journal->j_superblock,
2076 journal);
2077 journal->j_transaction_sequence = 1;
2078 e2fsck_clear_recover(ctx, recover);
2079 return 0;
2080 }
2081 return EXT2_ET_CORRUPT_SUPERBLOCK;
2082 } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
2083 return EXT2_ET_CORRUPT_SUPERBLOCK;
2084
2085 return 0;
2086}
2087
2088static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
2089 int reset, int drop)
2090{
2091 journal_superblock_t *jsb;
2092
2093 if (drop)
2094 mark_buffer_clean(journal->j_sb_buffer);
2095 else if (!(ctx->options & E2F_OPT_READONLY)) {
2096 jsb = journal->j_superblock;
2097 jsb->s_sequence = htonl(journal->j_transaction_sequence);
2098 if (reset)
2099 jsb->s_start = 0; /* this marks the journal as empty */
2100 mark_buffer_dirty(journal->j_sb_buffer);
2101 }
2102 brelse(journal->j_sb_buffer);
2103
2104 if (ctx->journal_io) {
2105 if (ctx->fs && ctx->fs->io != ctx->journal_io)
2106 io_channel_close(ctx->journal_io);
2107 ctx->journal_io = 0;
2108 }
2109
2110#ifndef USE_INODE_IO
Rob Landleye7c43b62006-03-01 16:39:45 +00002111 ext2fs_free_mem(&journal->j_inode);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002112#endif
Rob Landleye7c43b62006-03-01 16:39:45 +00002113 ext2fs_free_mem(&journal->j_fs_dev);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002114 ext2fs_free_mem(&journal);
2115}
2116
2117/*
2118 * This function makes sure that the superblock fields regarding the
2119 * journal are consistent.
2120 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002121static int e2fsck_check_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002122{
2123 struct ext2_super_block *sb = ctx->fs->super;
2124 journal_t *journal;
2125 int recover = ctx->fs->super->s_feature_incompat &
2126 EXT3_FEATURE_INCOMPAT_RECOVER;
2127 struct problem_context pctx;
2128 problem_t problem;
2129 int reset = 0, force_fsck = 0;
2130 int retval;
2131
2132 /* If we don't have any journal features, don't do anything more */
2133 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
2134 !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
2135 uuid_is_null(sb->s_journal_uuid))
2136 return 0;
2137
2138 clear_problem_context(&pctx);
2139 pctx.num = sb->s_journal_inum;
2140
2141 retval = e2fsck_get_journal(ctx, &journal);
2142 if (retval) {
2143 if ((retval == EXT2_ET_BAD_INODE_NUM) ||
2144 (retval == EXT2_ET_BAD_BLOCK_NUM) ||
2145 (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
2146 (retval == EXT2_ET_NO_JOURNAL))
2147 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
2148 return retval;
2149 }
2150
2151 retval = e2fsck_journal_load(journal);
2152 if (retval) {
2153 if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
2154 ((retval == EXT2_ET_UNSUPP_FEATURE) &&
2155 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
2156 &pctx))) ||
2157 ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
2158 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
2159 &pctx))) ||
2160 ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
2161 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
2162 retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
2163 &pctx);
2164 e2fsck_journal_release(ctx, journal, 0, 1);
2165 return retval;
2166 }
2167
2168 /*
2169 * We want to make the flags consistent here. We will not leave with
2170 * needs_recovery set but has_journal clear. We can't get in a loop
2171 * with -y, -n, or -p, only if a user isn't making up their mind.
2172 */
2173no_has_journal:
2174 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
2175 recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
2176 pctx.str = "inode";
2177 if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
2178 if (recover &&
2179 !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
2180 goto no_has_journal;
2181 /*
2182 * Need a full fsck if we are releasing a
2183 * journal stored on a reserved inode.
2184 */
2185 force_fsck = recover ||
2186 (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
2187 /* Clear all of the journal fields */
2188 sb->s_journal_inum = 0;
2189 sb->s_journal_dev = 0;
2190 memset(sb->s_journal_uuid, 0,
2191 sizeof(sb->s_journal_uuid));
2192 e2fsck_clear_recover(ctx, force_fsck);
2193 } else if (!(ctx->options & E2F_OPT_READONLY)) {
2194 sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
2195 ext2fs_mark_super_dirty(ctx->fs);
2196 }
2197 }
2198
2199 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
2200 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
2201 journal->j_superblock->s_start != 0) {
2202 /* Print status information */
2203 fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
2204 if (ctx->superblock)
2205 problem = PR_0_JOURNAL_RUN_DEFAULT;
2206 else
2207 problem = PR_0_JOURNAL_RUN;
2208 if (fix_problem(ctx, problem, &pctx)) {
2209 ctx->options |= E2F_OPT_FORCE;
2210 sb->s_feature_incompat |=
2211 EXT3_FEATURE_INCOMPAT_RECOVER;
2212 ext2fs_mark_super_dirty(ctx->fs);
2213 } else if (fix_problem(ctx,
2214 PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
2215 reset = 1;
2216 sb->s_state &= ~EXT2_VALID_FS;
2217 ext2fs_mark_super_dirty(ctx->fs);
2218 }
2219 /*
2220 * If the user answers no to the above question, we
2221 * ignore the fact that journal apparently has data;
2222 * accidentally replaying over valid data would be far
2223 * worse than skipping a questionable recovery.
2224 *
2225 * XXX should we abort with a fatal error here? What
2226 * will the ext3 kernel code do if a filesystem with
2227 * !NEEDS_RECOVERY but with a non-zero
2228 * journal->j_superblock->s_start is mounted?
2229 */
2230 }
2231
2232 e2fsck_journal_release(ctx, journal, reset, 0);
2233 return retval;
2234}
2235
2236static errcode_t recover_ext3_journal(e2fsck_t ctx)
2237{
2238 journal_t *journal;
2239 int retval;
2240
2241 journal_init_revoke_caches();
2242 retval = e2fsck_get_journal(ctx, &journal);
2243 if (retval)
2244 return retval;
2245
2246 retval = e2fsck_journal_load(journal);
2247 if (retval)
2248 goto errout;
2249
2250 retval = journal_init_revoke(journal, 1024);
2251 if (retval)
2252 goto errout;
2253
2254 retval = -journal_recover(journal);
2255 if (retval)
2256 goto errout;
2257
2258 if (journal->j_superblock->s_errno) {
2259 ctx->fs->super->s_state |= EXT2_ERROR_FS;
2260 ext2fs_mark_super_dirty(ctx->fs);
2261 journal->j_superblock->s_errno = 0;
2262 mark_buffer_dirty(journal->j_sb_buffer);
2263 }
2264
2265errout:
2266 journal_destroy_revoke(journal);
2267 journal_destroy_revoke_caches();
2268 e2fsck_journal_release(ctx, journal, 1, 0);
2269 return retval;
2270}
2271
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002272static int e2fsck_run_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002273{
2274 io_manager io_ptr = ctx->fs->io->manager;
2275 int blocksize = ctx->fs->blocksize;
2276 errcode_t retval, recover_retval;
2277
2278 printf(_("%s: recovering journal\n"), ctx->device_name);
2279 if (ctx->options & E2F_OPT_READONLY) {
2280 printf(_("%s: won't do journal recovery while read-only\n"),
2281 ctx->device_name);
2282 return EXT2_ET_FILE_RO;
2283 }
2284
2285 if (ctx->fs->flags & EXT2_FLAG_DIRTY)
2286 ext2fs_flush(ctx->fs); /* Force out any modifications */
2287
2288 recover_retval = recover_ext3_journal(ctx);
2289
2290 /*
2291 * Reload the filesystem context to get up-to-date data from disk
2292 * because journal recovery will change the filesystem under us.
2293 */
2294 ext2fs_close(ctx->fs);
2295 retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
2296 ctx->superblock, blocksize, io_ptr,
2297 &ctx->fs);
2298
2299 if (retval) {
2300 com_err(ctx->program_name, retval,
2301 _("while trying to re-open %s"),
2302 ctx->device_name);
2303 fatal_error(ctx, 0);
2304 }
2305 ctx->fs->priv_data = ctx;
2306
2307 /* Set the superblock flags */
2308 e2fsck_clear_recover(ctx, recover_retval);
2309 return recover_retval;
2310}
2311
2312/*
2313 * This function will move the journal inode from a visible file in
2314 * the filesystem directory hierarchy to the reserved inode if necessary.
2315 */
2316static const char * const journal_names[] = {
2317 ".journal", "journal", ".journal.dat", "journal.dat", 0 };
2318
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002319static void e2fsck_move_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002320{
2321 struct ext2_super_block *sb = ctx->fs->super;
2322 struct problem_context pctx;
2323 struct ext2_inode inode;
2324 ext2_filsys fs = ctx->fs;
2325 ext2_ino_t ino;
2326 errcode_t retval;
2327 const char * const * cpp;
2328 int group, mount_flags;
2329
2330 clear_problem_context(&pctx);
2331
2332 /*
2333 * If the filesystem is opened read-only, or there is no
2334 * journal, then do nothing.
2335 */
2336 if ((ctx->options & E2F_OPT_READONLY) ||
2337 (sb->s_journal_inum == 0) ||
2338 !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
2339 return;
2340
2341 /*
2342 * Read in the journal inode
2343 */
2344 if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
2345 return;
2346
2347 /*
2348 * If it's necessary to backup the journal inode, do so.
2349 */
2350 if ((sb->s_jnl_backup_type == 0) ||
2351 ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
2352 memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
2353 if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
2354 memcpy(sb->s_jnl_blocks, inode.i_block,
2355 EXT2_N_BLOCKS*4);
2356 sb->s_jnl_blocks[16] = inode.i_size;
2357 sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
2358 ext2fs_mark_super_dirty(fs);
2359 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
2360 }
2361 }
2362
2363 /*
2364 * If the journal is already the hidden inode, then do nothing
2365 */
2366 if (sb->s_journal_inum == EXT2_JOURNAL_INO)
2367 return;
2368
2369 /*
2370 * The journal inode had better have only one link and not be readable.
2371 */
2372 if (inode.i_links_count != 1)
2373 return;
2374
2375 /*
2376 * If the filesystem is mounted, or we can't tell whether
2377 * or not it's mounted, do nothing.
2378 */
2379 retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
2380 if (retval || (mount_flags & EXT2_MF_MOUNTED))
2381 return;
2382
2383 /*
2384 * If we can't find the name of the journal inode, then do
2385 * nothing.
2386 */
2387 for (cpp = journal_names; *cpp; cpp++) {
2388 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
2389 strlen(*cpp), 0, &ino);
2390 if ((retval == 0) && (ino == sb->s_journal_inum))
2391 break;
2392 }
2393 if (*cpp == 0)
2394 return;
2395
2396 /* We need the inode bitmap to be loaded */
2397 retval = ext2fs_read_bitmaps(fs);
2398 if (retval)
2399 return;
2400
2401 pctx.str = *cpp;
2402 if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
2403 return;
2404
2405 /*
2406 * OK, we've done all the checks, let's actually move the
2407 * journal inode. Errors at this point mean we need to force
2408 * an ext2 filesystem check.
2409 */
2410 if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
2411 goto err_out;
2412 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
2413 goto err_out;
2414 sb->s_journal_inum = EXT2_JOURNAL_INO;
2415 ext2fs_mark_super_dirty(fs);
2416 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
2417 inode.i_links_count = 0;
2418 inode.i_dtime = time(0);
2419 if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
2420 goto err_out;
2421
2422 group = ext2fs_group_of_ino(fs, ino);
2423 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
2424 ext2fs_mark_ib_dirty(fs);
2425 fs->group_desc[group].bg_free_inodes_count++;
2426 fs->super->s_free_inodes_count++;
2427 return;
2428
2429err_out:
2430 pctx.errcode = retval;
2431 fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
2432 fs->super->s_state &= ~EXT2_VALID_FS;
2433 ext2fs_mark_super_dirty(fs);
2434 return;
2435}
2436
2437/*
2438 * message.c --- print e2fsck messages (with compression)
2439 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002440 * print_e2fsck_message() prints a message to the user, using
2441 * compression techniques and expansions of abbreviations.
2442 *
2443 * The following % expansions are supported:
2444 *
2445 * %b <blk> block number
2446 * %B <blkcount> integer
2447 * %c <blk2> block number
2448 * %Di <dirent>->ino inode number
2449 * %Dn <dirent>->name string
2450 * %Dr <dirent>->rec_len
2451 * %Dl <dirent>->name_len
2452 * %Dt <dirent>->filetype
2453 * %d <dir> inode number
2454 * %g <group> integer
2455 * %i <ino> inode number
2456 * %Is <inode> -> i_size
2457 * %IS <inode> -> i_extra_isize
2458 * %Ib <inode> -> i_blocks
2459 * %Il <inode> -> i_links_count
2460 * %Im <inode> -> i_mode
2461 * %IM <inode> -> i_mtime
2462 * %IF <inode> -> i_faddr
2463 * %If <inode> -> i_file_acl
2464 * %Id <inode> -> i_dir_acl
2465 * %Iu <inode> -> i_uid
2466 * %Ig <inode> -> i_gid
2467 * %j <ino2> inode number
2468 * %m <com_err error message>
2469 * %N <num>
2470 * %p ext2fs_get_pathname of directory <ino>
2471 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
2472 * the containing directory. (If dirent is NULL
2473 * then return the pathname of directory <ino2>)
2474 * %q ext2fs_get_pathname of directory <dir>
2475 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
2476 * the containing directory.
2477 * %s <str> miscellaneous string
2478 * %S backup superblock
2479 * %X <num> hexadecimal format
2480 *
2481 * The following '@' expansions are supported:
2482 *
2483 * @a extended attribute
2484 * @A error allocating
2485 * @b block
2486 * @B bitmap
2487 * @c compress
2488 * @C conflicts with some other fs block
2489 * @D deleted
2490 * @d directory
2491 * @e entry
2492 * @E Entry '%Dn' in %p (%i)
2493 * @f filesystem
2494 * @F for @i %i (%Q) is
2495 * @g group
2496 * @h HTREE directory inode
2497 * @i inode
2498 * @I illegal
2499 * @j journal
2500 * @l lost+found
2501 * @L is a link
Mike Frysinger874af852006-03-08 07:03:27 +00002502 * @m multiply-claimed
2503 * @n invalid
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002504 * @o orphaned
2505 * @p problem in
2506 * @r root inode
2507 * @s should be
2508 * @S superblock
2509 * @u unattached
2510 * @v device
2511 * @z zero-length
2512 */
2513
2514
2515/*
2516 * This structure defines the abbreviations used by the text strings
2517 * below. The first character in the string is the index letter. An
2518 * abbreviation of the form '@<i>' is expanded by looking up the index
2519 * letter <i> in the table below.
2520 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002521static const char * const abbrevs[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002522 N_("aextended attribute"),
2523 N_("Aerror allocating"),
2524 N_("bblock"),
2525 N_("Bbitmap"),
2526 N_("ccompress"),
2527 N_("Cconflicts with some other fs @b"),
2528 N_("iinode"),
2529 N_("Iillegal"),
2530 N_("jjournal"),
2531 N_("Ddeleted"),
2532 N_("ddirectory"),
2533 N_("eentry"),
2534 N_("E@e '%Dn' in %p (%i)"),
2535 N_("ffilesystem"),
2536 N_("Ffor @i %i (%Q) is"),
2537 N_("ggroup"),
2538 N_("hHTREE @d @i"),
2539 N_("llost+found"),
2540 N_("Lis a link"),
Mike Frysinger874af852006-03-08 07:03:27 +00002541 N_("mmultiply-claimed"),
2542 N_("ninvalid"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002543 N_("oorphaned"),
2544 N_("pproblem in"),
2545 N_("rroot @i"),
2546 N_("sshould be"),
2547 N_("Ssuper@b"),
2548 N_("uunattached"),
2549 N_("vdevice"),
2550 N_("zzero-length"),
2551 "@@",
2552 0
2553 };
2554
2555/*
2556 * Give more user friendly names to the "special" inodes.
2557 */
2558#define num_special_inodes 11
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002559static const char * const special_inode_name[] =
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002560{
2561 N_("<The NULL inode>"), /* 0 */
2562 N_("<The bad blocks inode>"), /* 1 */
2563 "/", /* 2 */
2564 N_("<The ACL index inode>"), /* 3 */
2565 N_("<The ACL data inode>"), /* 4 */
2566 N_("<The boot loader inode>"), /* 5 */
2567 N_("<The undelete directory inode>"), /* 6 */
2568 N_("<The group descriptor inode>"), /* 7 */
2569 N_("<The journal inode>"), /* 8 */
2570 N_("<Reserved inode 9>"), /* 9 */
2571 N_("<Reserved inode 10>"), /* 10 */
2572};
2573
2574/*
2575 * This function does "safe" printing. It will convert non-printable
2576 * ASCII characters using '^' and M- notation.
2577 */
2578static void safe_print(const char *cp, int len)
2579{
2580 unsigned char ch;
2581
2582 if (len < 0)
2583 len = strlen(cp);
2584
2585 while (len--) {
2586 ch = *cp++;
2587 if (ch > 128) {
2588 fputs("M-", stdout);
2589 ch -= 128;
2590 }
2591 if ((ch < 32) || (ch == 0x7f)) {
2592 fputc('^', stdout);
2593 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
2594 }
2595 fputc(ch, stdout);
2596 }
2597}
2598
2599
2600/*
2601 * This function prints a pathname, using the ext2fs_get_pathname
2602 * function
2603 */
2604static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
2605{
2606 errcode_t retval;
2607 char *path;
2608
2609 if (!dir && (ino < num_special_inodes)) {
2610 fputs(_(special_inode_name[ino]), stdout);
2611 return;
2612 }
2613
2614 retval = ext2fs_get_pathname(fs, dir, ino, &path);
2615 if (retval)
2616 fputs("???", stdout);
2617 else {
2618 safe_print(path, -1);
2619 ext2fs_free_mem(&path);
2620 }
2621}
2622
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002623static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
2624 struct problem_context *pctx, int first);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002625/*
2626 * This function handles the '@' expansion. We allow recursive
2627 * expansion; an @ expression can contain further '@' and '%'
2628 * expressions.
2629 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002630static void expand_at_expression(e2fsck_t ctx, char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002631 struct problem_context *pctx,
2632 int *first)
2633{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002634 const char * const *cpp;
2635 const char *str;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002636
2637 /* Search for the abbreviation */
2638 for (cpp = abbrevs; *cpp; cpp++) {
2639 if (ch == *cpp[0])
2640 break;
2641 }
2642 if (*cpp) {
2643 str = _(*cpp) + 1;
2644 if (*first && islower(*str)) {
2645 *first = 0;
2646 fputc(toupper(*str++), stdout);
2647 }
2648 print_e2fsck_message(ctx, str, pctx, *first);
2649 } else
2650 printf("@%c", ch);
2651}
2652
2653/*
2654 * This function expands '%IX' expressions
2655 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002656static void expand_inode_expression(char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002657 struct problem_context *ctx)
2658{
2659 struct ext2_inode *inode;
2660 struct ext2_inode_large *large_inode;
2661 char * time_str;
2662 time_t t;
2663 int do_gmt = -1;
2664
2665 if (!ctx || !ctx->inode)
2666 goto no_inode;
2667
2668 inode = ctx->inode;
2669 large_inode = (struct ext2_inode_large *) inode;
2670
2671 switch (ch) {
2672 case 's':
2673 if (LINUX_S_ISDIR(inode->i_mode))
2674 printf("%u", inode->i_size);
2675 else {
2676#ifdef EXT2_NO_64_TYPE
2677 if (inode->i_size_high)
2678 printf("0x%x%08x", inode->i_size_high,
2679 inode->i_size);
2680 else
2681 printf("%u", inode->i_size);
2682#else
2683 printf("%llu", (inode->i_size |
2684 ((__u64) inode->i_size_high << 32)));
2685#endif
2686 }
2687 break;
2688 case 'S':
2689 printf("%u", large_inode->i_extra_isize);
2690 break;
2691 case 'b':
2692 printf("%u", inode->i_blocks);
2693 break;
2694 case 'l':
2695 printf("%d", inode->i_links_count);
2696 break;
2697 case 'm':
2698 printf("0%o", inode->i_mode);
2699 break;
2700 case 'M':
2701 /* The diet libc doesn't respect the TZ environemnt variable */
2702 if (do_gmt == -1) {
2703 time_str = getenv("TZ");
2704 if (!time_str)
2705 time_str = "";
2706 do_gmt = !strcmp(time_str, "GMT");
2707 }
2708 t = inode->i_mtime;
2709 time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
2710 printf("%.24s", time_str);
2711 break;
2712 case 'F':
2713 printf("%u", inode->i_faddr);
2714 break;
2715 case 'f':
2716 printf("%u", inode->i_file_acl);
2717 break;
2718 case 'd':
2719 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
2720 inode->i_dir_acl : 0));
2721 break;
2722 case 'u':
2723 printf("%d", (inode->i_uid |
2724 (inode->osd2.linux2.l_i_uid_high << 16)));
2725 break;
2726 case 'g':
2727 printf("%d", (inode->i_gid |
2728 (inode->osd2.linux2.l_i_gid_high << 16)));
2729 break;
2730 default:
2731 no_inode:
2732 printf("%%I%c", ch);
2733 break;
2734 }
2735}
2736
2737/*
2738 * This function expands '%dX' expressions
2739 */
2740static _INLINE_ void expand_dirent_expression(char ch,
2741 struct problem_context *ctx)
2742{
2743 struct ext2_dir_entry *dirent;
2744 int len;
2745
2746 if (!ctx || !ctx->dirent)
2747 goto no_dirent;
2748
2749 dirent = ctx->dirent;
2750
2751 switch (ch) {
2752 case 'i':
2753 printf("%u", dirent->inode);
2754 break;
2755 case 'n':
2756 len = dirent->name_len & 0xFF;
2757 if (len > EXT2_NAME_LEN)
2758 len = EXT2_NAME_LEN;
2759 if (len > dirent->rec_len)
2760 len = dirent->rec_len;
2761 safe_print(dirent->name, len);
2762 break;
2763 case 'r':
2764 printf("%u", dirent->rec_len);
2765 break;
2766 case 'l':
2767 printf("%u", dirent->name_len & 0xFF);
2768 break;
2769 case 't':
2770 printf("%u", dirent->name_len >> 8);
2771 break;
2772 default:
2773 no_dirent:
2774 printf("%%D%c", ch);
2775 break;
2776 }
2777}
2778
2779static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
2780 struct problem_context *ctx)
2781{
2782 if (!ctx)
2783 goto no_context;
2784
2785 switch (ch) {
2786 case '%':
2787 fputc('%', stdout);
2788 break;
2789 case 'b':
2790 printf("%u", ctx->blk);
2791 break;
2792 case 'B':
2793#ifdef EXT2_NO_64_TYPE
2794 printf("%d", ctx->blkcount);
2795#else
2796 printf("%lld", ctx->blkcount);
2797#endif
2798 break;
2799 case 'c':
2800 printf("%u", ctx->blk2);
2801 break;
2802 case 'd':
2803 printf("%u", ctx->dir);
2804 break;
2805 case 'g':
2806 printf("%d", ctx->group);
2807 break;
2808 case 'i':
2809 printf("%u", ctx->ino);
2810 break;
2811 case 'j':
2812 printf("%u", ctx->ino2);
2813 break;
2814 case 'm':
2815 printf("%s", error_message(ctx->errcode));
2816 break;
2817 case 'N':
2818#ifdef EXT2_NO_64_TYPE
2819 printf("%u", ctx->num);
2820#else
2821 printf("%llu", ctx->num);
2822#endif
2823 break;
2824 case 'p':
2825 print_pathname(fs, ctx->ino, 0);
2826 break;
2827 case 'P':
2828 print_pathname(fs, ctx->ino2,
2829 ctx->dirent ? ctx->dirent->inode : 0);
2830 break;
2831 case 'q':
2832 print_pathname(fs, ctx->dir, 0);
2833 break;
2834 case 'Q':
2835 print_pathname(fs, ctx->dir, ctx->ino);
2836 break;
2837 case 'S':
2838 printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
2839 break;
2840 case 's':
2841 printf("%s", ctx->str ? ctx->str : "NULL");
2842 break;
2843 case 'X':
2844#ifdef EXT2_NO_64_TYPE
2845 printf("0x%x", ctx->num);
2846#else
2847 printf("0x%llx", ctx->num);
2848#endif
2849 break;
2850 default:
2851 no_context:
2852 printf("%%%c", ch);
2853 break;
2854 }
2855}
2856
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002857
2858static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002859 struct problem_context *pctx, int first)
2860{
2861 ext2_filsys fs = ctx->fs;
2862 const char * cp;
2863 int i;
2864
2865 e2fsck_clear_progbar(ctx);
2866 for (cp = msg; *cp; cp++) {
2867 if (cp[0] == '@') {
2868 cp++;
2869 expand_at_expression(ctx, *cp, pctx, &first);
2870 } else if (cp[0] == '%' && cp[1] == 'I') {
2871 cp += 2;
2872 expand_inode_expression(*cp, pctx);
2873 } else if (cp[0] == '%' && cp[1] == 'D') {
2874 cp += 2;
2875 expand_dirent_expression(*cp, pctx);
2876 } else if ((cp[0] == '%')) {
2877 cp++;
2878 expand_percent_expression(fs, *cp, pctx);
2879 } else {
2880 for (i=0; cp[i]; i++)
2881 if ((cp[i] == '@') || cp[i] == '%')
2882 break;
2883 printf("%.*s", i, cp);
2884 cp += i-1;
2885 }
2886 first = 0;
2887 }
2888}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002889
2890
2891/*
2892 * region.c --- code which manages allocations within a region.
2893 */
2894
2895struct region_el {
2896 region_addr_t start;
2897 region_addr_t end;
2898 struct region_el *next;
2899};
2900
2901struct region_struct {
2902 region_addr_t min;
2903 region_addr_t max;
2904 struct region_el *allocated;
2905};
2906
2907static region_t region_create(region_addr_t min, region_addr_t max)
2908{
2909 region_t region;
2910
2911 region = malloc(sizeof(struct region_struct));
2912 if (!region)
2913 return NULL;
2914 memset(region, 0, sizeof(struct region_struct));
2915 region->min = min;
2916 region->max = max;
2917 return region;
2918}
2919
2920static void region_free(region_t region)
2921{
2922 struct region_el *r, *next;
2923
2924 for (r = region->allocated; r; r = next) {
2925 next = r->next;
2926 free(r);
2927 }
2928 memset(region, 0, sizeof(struct region_struct));
2929 free(region);
2930}
2931
2932static int region_allocate(region_t region, region_addr_t start, int n)
2933{
2934 struct region_el *r, *new_region, *prev, *next;
2935 region_addr_t end;
2936
2937 end = start+n;
2938 if ((start < region->min) || (end > region->max))
2939 return -1;
2940 if (n == 0)
2941 return 1;
2942
2943 /*
2944 * Search through the linked list. If we find that it
2945 * conflicts witih something that's already allocated, return
2946 * 1; if we can find an existing region which we can grow, do
2947 * so. Otherwise, stop when we find the appropriate place
2948 * insert a new region element into the linked list.
2949 */
2950 for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
2951 if (((start >= r->start) && (start < r->end)) ||
2952 ((end > r->start) && (end <= r->end)) ||
2953 ((start <= r->start) && (end >= r->end)))
2954 return 1;
2955 if (end == r->start) {
2956 r->start = start;
2957 return 0;
2958 }
2959 if (start == r->end) {
2960 if ((next = r->next)) {
2961 if (end > next->start)
2962 return 1;
2963 if (end == next->start) {
2964 r->end = next->end;
2965 r->next = next->next;
2966 free(next);
2967 return 0;
2968 }
2969 }
2970 r->end = end;
2971 return 0;
2972 }
2973 if (start < r->start)
2974 break;
2975 }
2976 /*
2977 * Insert a new region element structure into the linked list
2978 */
2979 new_region = malloc(sizeof(struct region_el));
2980 if (!new_region)
2981 return -1;
2982 new_region->start = start;
2983 new_region->end = start + n;
2984 new_region->next = r;
2985 if (prev)
2986 prev->next = new_region;
2987 else
2988 region->allocated = new_region;
2989 return 0;
2990}
2991
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002992/*
2993 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
2994 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002995 * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
2996 * and applies the following tests to each inode:
2997 *
2998 * - The mode field of the inode must be legal.
2999 * - The size and block count fields of the inode are correct.
3000 * - A data block must not be used by another inode
3001 *
3002 * Pass 1 also gathers the collects the following information:
3003 *
3004 * - A bitmap of which inodes are in use. (inode_used_map)
3005 * - A bitmap of which inodes are directories. (inode_dir_map)
3006 * - A bitmap of which inodes are regular files. (inode_reg_map)
3007 * - A bitmap of which inodes have bad fields. (inode_bad_map)
3008 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
3009 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
3010 * - A bitmap of which blocks are in use. (block_found_map)
3011 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
3012 * - The data blocks of the directory inodes. (dir_map)
3013 *
3014 * Pass 1 is designed to stash away enough information so that the
3015 * other passes should not need to read in the inode information
3016 * during the normal course of a filesystem check. (Althogh if an
3017 * inconsistency is detected, other passes may need to read in an
3018 * inode to fix it.)
3019 *
3020 * Note that pass 1B will be invoked if there are any duplicate blocks
3021 * found.
3022 */
3023
3024
3025static int process_block(ext2_filsys fs, blk_t *blocknr,
3026 e2_blkcnt_t blockcnt, blk_t ref_blk,
3027 int ref_offset, void *priv_data);
3028static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
3029 e2_blkcnt_t blockcnt, blk_t ref_blk,
3030 int ref_offset, void *priv_data);
3031static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
3032 char *block_buf);
3033static void mark_table_blocks(e2fsck_t ctx);
3034static void alloc_bb_map(e2fsck_t ctx);
3035static void alloc_imagic_map(e2fsck_t ctx);
3036static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
3037static void handle_fs_bad_blocks(e2fsck_t ctx);
3038static void process_inodes(e2fsck_t ctx, char *block_buf);
3039static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
3040static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
3041 dgrp_t group, void * priv_data);
3042static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
3043 char *block_buf, int adjust_sign);
3044/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
3045
3046static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
3047 struct ext2_inode * inode, int bufsize,
3048 const char *proc);
3049
3050struct process_block_struct_1 {
3051 ext2_ino_t ino;
3052 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
3053 fragmented:1, compressed:1, bbcheck:1;
3054 blk_t num_blocks;
3055 blk_t max_blocks;
3056 e2_blkcnt_t last_block;
3057 int num_illegal_blocks;
3058 blk_t previous_block;
3059 struct ext2_inode *inode;
3060 struct problem_context *pctx;
3061 ext2fs_block_bitmap fs_meta_blocks;
3062 e2fsck_t ctx;
3063};
3064
3065struct process_inode_block {
3066 ext2_ino_t ino;
3067 struct ext2_inode inode;
3068};
3069
3070struct scan_callback_struct {
3071 e2fsck_t ctx;
3072 char *block_buf;
3073};
3074
3075/*
3076 * For the inodes to process list.
3077 */
3078static struct process_inode_block *inodes_to_process;
3079static int process_inode_count;
3080
3081static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
3082 EXT2_MIN_BLOCK_LOG_SIZE + 1];
3083
3084/*
3085 * Free all memory allocated by pass1 in preparation for restarting
3086 * things.
3087 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003088static void unwind_pass1(void)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003089{
3090 ext2fs_free_mem(&inodes_to_process);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003091}
3092
3093/*
3094 * Check to make sure a device inode is real. Returns 1 if the device
3095 * checks out, 0 if not.
3096 *
3097 * Note: this routine is now also used to check FIFO's and Sockets,
3098 * since they have the same requirement; the i_block fields should be
3099 * zero.
3100 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003101static int
3102e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003103{
3104 int i;
3105
3106 /*
3107 * If i_blocks is non-zero, or the index flag is set, then
3108 * this is a bogus device/fifo/socket
3109 */
3110 if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
3111 (inode->i_flags & EXT2_INDEX_FL))
3112 return 0;
3113
3114 /*
3115 * We should be able to do the test below all the time, but
3116 * because the kernel doesn't forcibly clear the device
3117 * inode's additional i_block fields, there are some rare
3118 * occasions when a legitimate device inode will have non-zero
3119 * additional i_block fields. So for now, we only complain
3120 * when the immutable flag is set, which should never happen
3121 * for devices. (And that's when the problem is caused, since
3122 * you can't set or clear immutable flags for devices.) Once
3123 * the kernel has been fixed we can change this...
3124 */
3125 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
3126 for (i=4; i < EXT2_N_BLOCKS; i++)
3127 if (inode->i_block[i])
3128 return 0;
3129 }
3130 return 1;
3131}
3132
3133/*
3134 * Check to make sure a symlink inode is real. Returns 1 if the symlink
3135 * checks out, 0 if not.
3136 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003137static int
3138e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, char *buf)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003139{
3140 unsigned int len;
3141 int i;
3142 blk_t blocks;
3143
3144 if ((inode->i_size_high || inode->i_size == 0) ||
3145 (inode->i_flags & EXT2_INDEX_FL))
3146 return 0;
3147
3148 blocks = ext2fs_inode_data_blocks(fs, inode);
3149 if (blocks) {
3150 if ((inode->i_size >= fs->blocksize) ||
3151 (blocks != fs->blocksize >> 9) ||
3152 (inode->i_block[0] < fs->super->s_first_data_block) ||
3153 (inode->i_block[0] >= fs->super->s_blocks_count))
3154 return 0;
3155
3156 for (i = 1; i < EXT2_N_BLOCKS; i++)
3157 if (inode->i_block[i])
3158 return 0;
3159
3160 if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
3161 return 0;
3162
3163 len = strnlen(buf, fs->blocksize);
3164 if (len == fs->blocksize)
3165 return 0;
3166 } else {
3167 if (inode->i_size >= sizeof(inode->i_block))
3168 return 0;
3169
3170 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
3171 if (len == sizeof(inode->i_block))
3172 return 0;
3173 }
3174 if (len != inode->i_size)
3175 return 0;
3176 return 1;
3177}
3178
3179/*
3180 * If the immutable (or append-only) flag is set on the inode, offer
3181 * to clear it.
3182 */
3183#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
3184static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
3185{
3186 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
3187 return;
3188
3189 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
3190 return;
3191
3192 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
3193 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
3194}
3195
3196/*
3197 * If device, fifo or socket, check size is zero -- if not offer to
3198 * clear it
3199 */
3200static void check_size(e2fsck_t ctx, struct problem_context *pctx)
3201{
3202 struct ext2_inode *inode = pctx->inode;
3203
3204 if ((inode->i_size == 0) && (inode->i_size_high == 0))
3205 return;
3206
3207 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
3208 return;
3209
3210 inode->i_size = 0;
3211 inode->i_size_high = 0;
3212 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
3213}
3214
3215static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
3216{
3217 struct ext2_super_block *sb = ctx->fs->super;
3218 struct ext2_inode_large *inode;
3219 struct ext2_ext_attr_entry *entry;
3220 char *start, *end;
3221 int storage_size, remain, offs;
3222 int problem = 0;
3223
3224 inode = (struct ext2_inode_large *) pctx->inode;
3225 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
3226 inode->i_extra_isize;
3227 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
3228 inode->i_extra_isize + sizeof(__u32);
3229 end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
3230 entry = (struct ext2_ext_attr_entry *) start;
3231
3232 /* scan all entry's headers first */
3233
3234 /* take finish entry 0UL into account */
3235 remain = storage_size - sizeof(__u32);
3236 offs = end - start;
3237
3238 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
3239
3240 /* header eats this space */
3241 remain -= sizeof(struct ext2_ext_attr_entry);
3242
3243 /* is attribute name valid? */
3244 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
3245 pctx->num = entry->e_name_len;
3246 problem = PR_1_ATTR_NAME_LEN;
3247 goto fix;
3248 }
3249
3250 /* attribute len eats this space */
3251 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
3252
3253 /* check value size */
3254 if (entry->e_value_size == 0 || entry->e_value_size > remain) {
3255 pctx->num = entry->e_value_size;
3256 problem = PR_1_ATTR_VALUE_SIZE;
3257 goto fix;
3258 }
3259
3260 /* check value placement */
3261 if (entry->e_value_offs +
3262 EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
3263 printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
3264 pctx->num = entry->e_value_offs;
3265 problem = PR_1_ATTR_VALUE_OFFSET;
3266 goto fix;
3267 }
3268
3269 /* e_value_block must be 0 in inode's ea */
3270 if (entry->e_value_block != 0) {
3271 pctx->num = entry->e_value_block;
3272 problem = PR_1_ATTR_VALUE_BLOCK;
3273 goto fix;
3274 }
3275
3276 /* e_hash must be 0 in inode's ea */
3277 if (entry->e_hash != 0) {
3278 pctx->num = entry->e_hash;
3279 problem = PR_1_ATTR_HASH;
3280 goto fix;
3281 }
3282
3283 remain -= entry->e_value_size;
3284 offs -= EXT2_XATTR_SIZE(entry->e_value_size);
3285
3286 entry = EXT2_EXT_ATTR_NEXT(entry);
3287 }
3288fix:
3289 /*
3290 * it seems like a corruption. it's very unlikely we could repair
3291 * EA(s) in automatic fashion -bzzz
3292 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003293 if (problem == 0 || !fix_problem(ctx, problem, pctx))
3294 return;
3295
3296 /* simple remove all possible EA(s) */
3297 *((__u32 *)start) = 0UL;
3298 e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
3299 EXT2_INODE_SIZE(sb), "pass1");
3300}
3301
3302static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
3303{
3304 struct ext2_super_block *sb = ctx->fs->super;
3305 struct ext2_inode_large *inode;
3306 __u32 *eamagic;
3307 int min, max;
3308
3309 inode = (struct ext2_inode_large *) pctx->inode;
3310 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
3311 /* this isn't large inode. so, nothing to check */
3312 return;
3313 }
3314
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003315 /* i_extra_isize must cover i_extra_isize + i_pad1 at least */
3316 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
3317 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
3318 /*
3319 * For now we will allow i_extra_isize to be 0, but really
3320 * implementations should never allow i_extra_isize to be 0
3321 */
3322 if (inode->i_extra_isize &&
3323 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
3324 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
3325 return;
3326 inode->i_extra_isize = min;
3327 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
3328 EXT2_INODE_SIZE(sb), "pass1");
3329 return;
3330 }
3331
3332 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
3333 inode->i_extra_isize);
3334 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
3335 /* it seems inode has an extended attribute(s) in body */
3336 check_ea_in_inode(ctx, pctx);
3337 }
3338}
3339
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003340static void e2fsck_pass1(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003341{
3342 int i;
3343 __u64 max_sizes;
3344 ext2_filsys fs = ctx->fs;
3345 ext2_ino_t ino;
3346 struct ext2_inode *inode;
3347 ext2_inode_scan scan;
3348 char *block_buf;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003349 unsigned char frag, fsize;
3350 struct problem_context pctx;
3351 struct scan_callback_struct scan_struct;
3352 struct ext2_super_block *sb = ctx->fs->super;
3353 int imagic_fs;
3354 int busted_fs_time = 0;
3355 int inode_size;
3356
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003357 clear_problem_context(&pctx);
3358
3359 if (!(ctx->options & E2F_OPT_PREEN))
3360 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
3361
3362 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
3363 !(ctx->options & E2F_OPT_NO)) {
3364 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
3365 ctx->dirs_to_hash = 0;
3366 }
3367
Rob Landley3e72c592006-04-06 22:49:04 +00003368 /* Pass 1 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003369
3370#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
3371
3372 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
3373 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
3374 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
3375 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
3376 max_sizes = (max_sizes * (1UL << i)) - 1;
3377 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
3378 }
3379#undef EXT2_BPP
3380
3381 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
3382
3383 /*
3384 * Allocate bitmaps structures
3385 */
3386 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
3387 &ctx->inode_used_map);
3388 if (pctx.errcode) {
3389 pctx.num = 1;
3390 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3391 ctx->flags |= E2F_FLAG_ABORT;
3392 return;
3393 }
3394 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
3395 _("directory inode map"), &ctx->inode_dir_map);
3396 if (pctx.errcode) {
3397 pctx.num = 2;
3398 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3399 ctx->flags |= E2F_FLAG_ABORT;
3400 return;
3401 }
3402 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
3403 _("regular file inode map"), &ctx->inode_reg_map);
3404 if (pctx.errcode) {
3405 pctx.num = 6;
3406 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3407 ctx->flags |= E2F_FLAG_ABORT;
3408 return;
3409 }
3410 pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
3411 &ctx->block_found_map);
3412 if (pctx.errcode) {
3413 pctx.num = 1;
3414 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
3415 ctx->flags |= E2F_FLAG_ABORT;
3416 return;
3417 }
3418 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
3419 &ctx->inode_link_info);
3420 if (pctx.errcode) {
3421 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
3422 ctx->flags |= E2F_FLAG_ABORT;
3423 return;
3424 }
3425 inode_size = EXT2_INODE_SIZE(fs->super);
3426 inode = (struct ext2_inode *)
3427 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
3428
3429 inodes_to_process = (struct process_inode_block *)
3430 e2fsck_allocate_memory(ctx,
3431 (ctx->process_inode_size *
3432 sizeof(struct process_inode_block)),
3433 "array of inodes to process");
3434 process_inode_count = 0;
3435
3436 pctx.errcode = ext2fs_init_dblist(fs, 0);
3437 if (pctx.errcode) {
3438 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
3439 ctx->flags |= E2F_FLAG_ABORT;
3440 return;
3441 }
3442
3443 /*
3444 * If the last orphan field is set, clear it, since the pass1
3445 * processing will automatically find and clear the orphans.
3446 * In the future, we may want to try using the last_orphan
3447 * linked list ourselves, but for now, we clear it so that the
3448 * ext3 mount code won't get confused.
3449 */
3450 if (!(ctx->options & E2F_OPT_READONLY)) {
3451 if (fs->super->s_last_orphan) {
3452 fs->super->s_last_orphan = 0;
3453 ext2fs_mark_super_dirty(fs);
3454 }
3455 }
3456
3457 mark_table_blocks(ctx);
3458 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
3459 "block interate buffer");
3460 e2fsck_use_inode_shortcuts(ctx, 1);
3461 ehandler_operation(_("doing inode scan"));
3462 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
3463 &scan);
3464 if (pctx.errcode) {
3465 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
3466 ctx->flags |= E2F_FLAG_ABORT;
3467 return;
3468 }
3469 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
3470 ctx->stashed_inode = inode;
3471 scan_struct.ctx = ctx;
3472 scan_struct.block_buf = block_buf;
3473 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
3474 if (ctx->progress)
3475 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
3476 return;
Mike Frysinger874af852006-03-08 07:03:27 +00003477 if ((fs->super->s_wtime < fs->super->s_inodes_count) ||
3478 (fs->super->s_mtime < fs->super->s_inodes_count))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003479 busted_fs_time = 1;
3480
3481 while (1) {
3482 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
3483 inode, inode_size);
3484 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3485 return;
3486 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
3487 if (!ctx->inode_bb_map)
3488 alloc_bb_map(ctx);
3489 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
3490 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3491 continue;
3492 }
3493 if (pctx.errcode) {
3494 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
3495 ctx->flags |= E2F_FLAG_ABORT;
3496 return;
3497 }
3498 if (!ino)
3499 break;
3500 pctx.ino = ino;
3501 pctx.inode = inode;
3502 ctx->stashed_ino = ino;
3503 if (inode->i_links_count) {
3504 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
3505 ino, inode->i_links_count);
3506 if (pctx.errcode) {
3507 pctx.num = inode->i_links_count;
3508 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
3509 ctx->flags |= E2F_FLAG_ABORT;
3510 return;
3511 }
3512 }
3513 if (ino == EXT2_BAD_INO) {
3514 struct process_block_struct_1 pb;
3515
3516 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
3517 &pb.fs_meta_blocks);
3518 if (pctx.errcode) {
3519 pctx.num = 4;
3520 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
3521 ctx->flags |= E2F_FLAG_ABORT;
3522 return;
3523 }
3524 pb.ino = EXT2_BAD_INO;
3525 pb.num_blocks = pb.last_block = 0;
3526 pb.num_illegal_blocks = 0;
3527 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
3528 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
3529 pb.inode = inode;
3530 pb.pctx = &pctx;
3531 pb.ctx = ctx;
3532 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
3533 block_buf, process_bad_block, &pb);
3534 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
3535 if (pctx.errcode) {
3536 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
3537 ctx->flags |= E2F_FLAG_ABORT;
3538 return;
3539 }
3540 if (pb.bbcheck)
3541 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
3542 ctx->flags |= E2F_FLAG_ABORT;
3543 return;
3544 }
3545 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3546 clear_problem_context(&pctx);
3547 continue;
3548 } else if (ino == EXT2_ROOT_INO) {
3549 /*
3550 * Make sure the root inode is a directory; if
3551 * not, offer to clear it. It will be
3552 * regnerated in pass #3.
3553 */
3554 if (!LINUX_S_ISDIR(inode->i_mode)) {
3555 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
3556 inode->i_dtime = time(0);
3557 inode->i_links_count = 0;
3558 ext2fs_icount_store(ctx->inode_link_info,
3559 ino, 0);
3560 e2fsck_write_inode(ctx, ino, inode,
3561 "pass1");
3562 }
3563
3564 }
3565 /*
3566 * If dtime is set, offer to clear it. mke2fs
3567 * version 0.2b created filesystems with the
3568 * dtime field set for the root and lost+found
3569 * directories. We won't worry about
3570 * /lost+found, since that can be regenerated
3571 * easily. But we will fix the root directory
3572 * as a special case.
3573 */
3574 if (inode->i_dtime && inode->i_links_count) {
3575 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
3576 inode->i_dtime = 0;
3577 e2fsck_write_inode(ctx, ino, inode,
3578 "pass1");
3579 }
3580 }
3581 } else if (ino == EXT2_JOURNAL_INO) {
3582 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3583 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
3584 if (!LINUX_S_ISREG(inode->i_mode) &&
3585 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
3586 &pctx)) {
3587 inode->i_mode = LINUX_S_IFREG;
3588 e2fsck_write_inode(ctx, ino, inode,
3589 "pass1");
3590 }
3591 check_blocks(ctx, &pctx, block_buf);
3592 continue;
3593 }
3594 if ((inode->i_links_count || inode->i_blocks ||
3595 inode->i_blocks || inode->i_block[0]) &&
3596 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
3597 &pctx)) {
3598 memset(inode, 0, inode_size);
3599 ext2fs_icount_store(ctx->inode_link_info,
3600 ino, 0);
3601 e2fsck_write_inode_full(ctx, ino, inode,
3602 inode_size, "pass1");
3603 }
3604 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
3605 int problem = 0;
3606
3607 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3608 if (ino == EXT2_BOOT_LOADER_INO) {
3609 if (LINUX_S_ISDIR(inode->i_mode))
3610 problem = PR_1_RESERVED_BAD_MODE;
3611 } else if (ino == EXT2_RESIZE_INO) {
3612 if (inode->i_mode &&
3613 !LINUX_S_ISREG(inode->i_mode))
3614 problem = PR_1_RESERVED_BAD_MODE;
3615 } else {
3616 if (inode->i_mode != 0)
3617 problem = PR_1_RESERVED_BAD_MODE;
3618 }
3619 if (problem) {
3620 if (fix_problem(ctx, problem, &pctx)) {
3621 inode->i_mode = 0;
3622 e2fsck_write_inode(ctx, ino, inode,
3623 "pass1");
3624 }
3625 }
3626 check_blocks(ctx, &pctx, block_buf);
3627 continue;
3628 }
3629 /*
3630 * Check for inodes who might have been part of the
3631 * orphaned list linked list. They should have gotten
3632 * dealt with by now, unless the list had somehow been
3633 * corrupted.
3634 *
3635 * FIXME: In the future, inodes which are still in use
3636 * (and which are therefore) pending truncation should
3637 * be handled specially. Right now we just clear the
3638 * dtime field, and the normal e2fsck handling of
3639 * inodes where i_size and the inode blocks are
3640 * inconsistent is to fix i_size, instead of releasing
3641 * the extra blocks. This won't catch the inodes that
3642 * was at the end of the orphan list, but it's better
3643 * than nothing. The right answer is that there
3644 * shouldn't be any bugs in the orphan list handling. :-)
3645 */
3646 if (inode->i_dtime && !busted_fs_time &&
3647 inode->i_dtime < ctx->fs->super->s_inodes_count) {
3648 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
3649 inode->i_dtime = inode->i_links_count ?
3650 0 : time(0);
3651 e2fsck_write_inode(ctx, ino, inode,
3652 "pass1");
3653 }
3654 }
3655
3656 /*
3657 * This code assumes that deleted inodes have
3658 * i_links_count set to 0.
3659 */
3660 if (!inode->i_links_count) {
3661 if (!inode->i_dtime && inode->i_mode) {
3662 if (fix_problem(ctx,
3663 PR_1_ZERO_DTIME, &pctx)) {
3664 inode->i_dtime = time(0);
3665 e2fsck_write_inode(ctx, ino, inode,
3666 "pass1");
3667 }
3668 }
3669 continue;
3670 }
3671 /*
3672 * n.b. 0.3c ext2fs code didn't clear i_links_count for
3673 * deleted files. Oops.
3674 *
3675 * Since all new ext2 implementations get this right,
3676 * we now assume that the case of non-zero
3677 * i_links_count and non-zero dtime means that we
3678 * should keep the file, not delete it.
3679 *
3680 */
3681 if (inode->i_dtime) {
3682 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
3683 inode->i_dtime = 0;
3684 e2fsck_write_inode(ctx, ino, inode, "pass1");
3685 }
3686 }
3687
3688 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3689 switch (fs->super->s_creator_os) {
3690 case EXT2_OS_LINUX:
3691 frag = inode->osd2.linux2.l_i_frag;
3692 fsize = inode->osd2.linux2.l_i_fsize;
3693 break;
3694 case EXT2_OS_HURD:
3695 frag = inode->osd2.hurd2.h_i_frag;
3696 fsize = inode->osd2.hurd2.h_i_fsize;
3697 break;
3698 case EXT2_OS_MASIX:
3699 frag = inode->osd2.masix2.m_i_frag;
3700 fsize = inode->osd2.masix2.m_i_fsize;
3701 break;
3702 default:
3703 frag = fsize = 0;
3704 }
3705
3706 if (inode->i_faddr || frag || fsize ||
3707 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
3708 mark_inode_bad(ctx, ino);
3709 if (inode->i_flags & EXT2_IMAGIC_FL) {
3710 if (imagic_fs) {
3711 if (!ctx->inode_imagic_map)
3712 alloc_imagic_map(ctx);
3713 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
3714 ino);
3715 } else {
3716 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
3717 inode->i_flags &= ~EXT2_IMAGIC_FL;
3718 e2fsck_write_inode(ctx, ino,
3719 inode, "pass1");
3720 }
3721 }
3722 }
3723
3724 check_inode_extra_space(ctx, &pctx);
3725
3726 if (LINUX_S_ISDIR(inode->i_mode)) {
3727 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
3728 e2fsck_add_dir_info(ctx, ino, 0);
3729 ctx->fs_directory_count++;
3730 } else if (LINUX_S_ISREG (inode->i_mode)) {
3731 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
3732 ctx->fs_regular_count++;
3733 } else if (LINUX_S_ISCHR (inode->i_mode) &&
3734 e2fsck_pass1_check_device_inode(fs, inode)) {
3735 check_immutable(ctx, &pctx);
3736 check_size(ctx, &pctx);
3737 ctx->fs_chardev_count++;
3738 } else if (LINUX_S_ISBLK (inode->i_mode) &&
3739 e2fsck_pass1_check_device_inode(fs, inode)) {
3740 check_immutable(ctx, &pctx);
3741 check_size(ctx, &pctx);
3742 ctx->fs_blockdev_count++;
3743 } else if (LINUX_S_ISLNK (inode->i_mode) &&
3744 e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
3745 check_immutable(ctx, &pctx);
3746 ctx->fs_symlinks_count++;
3747 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
3748 ctx->fs_fast_symlinks_count++;
3749 check_blocks(ctx, &pctx, block_buf);
3750 continue;
3751 }
3752 }
3753 else if (LINUX_S_ISFIFO (inode->i_mode) &&
3754 e2fsck_pass1_check_device_inode(fs, inode)) {
3755 check_immutable(ctx, &pctx);
3756 check_size(ctx, &pctx);
3757 ctx->fs_fifo_count++;
3758 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
3759 e2fsck_pass1_check_device_inode(fs, inode)) {
3760 check_immutable(ctx, &pctx);
3761 check_size(ctx, &pctx);
3762 ctx->fs_sockets_count++;
3763 } else
3764 mark_inode_bad(ctx, ino);
3765 if (inode->i_block[EXT2_IND_BLOCK])
3766 ctx->fs_ind_count++;
3767 if (inode->i_block[EXT2_DIND_BLOCK])
3768 ctx->fs_dind_count++;
3769 if (inode->i_block[EXT2_TIND_BLOCK])
3770 ctx->fs_tind_count++;
3771 if (inode->i_block[EXT2_IND_BLOCK] ||
3772 inode->i_block[EXT2_DIND_BLOCK] ||
3773 inode->i_block[EXT2_TIND_BLOCK] ||
3774 inode->i_file_acl) {
3775 inodes_to_process[process_inode_count].ino = ino;
3776 inodes_to_process[process_inode_count].inode = *inode;
3777 process_inode_count++;
3778 } else
3779 check_blocks(ctx, &pctx, block_buf);
3780
3781 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3782 return;
3783
3784 if (process_inode_count >= ctx->process_inode_size) {
3785 process_inodes(ctx, block_buf);
3786
3787 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3788 return;
3789 }
3790 }
3791 process_inodes(ctx, block_buf);
3792 ext2fs_close_inode_scan(scan);
3793 ehandler_operation(0);
3794
3795 /*
3796 * If any extended attribute blocks' reference counts need to
3797 * be adjusted, either up (ctx->refcount_extra), or down
3798 * (ctx->refcount), then fix them.
3799 */
3800 if (ctx->refcount) {
3801 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
3802 ea_refcount_free(ctx->refcount);
3803 ctx->refcount = 0;
3804 }
3805 if (ctx->refcount_extra) {
3806 adjust_extattr_refcount(ctx, ctx->refcount_extra,
3807 block_buf, +1);
3808 ea_refcount_free(ctx->refcount_extra);
3809 ctx->refcount_extra = 0;
3810 }
3811
3812 if (ctx->invalid_bitmaps)
3813 handle_fs_bad_blocks(ctx);
3814
3815 /* We don't need the block_ea_map any more */
Rob Landleye7c43b62006-03-01 16:39:45 +00003816 ext2fs_free_block_bitmap(ctx->block_ea_map);
3817 ctx->block_ea_map = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003818
3819 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
3820 ext2fs_block_bitmap save_bmap;
3821
3822 save_bmap = fs->block_map;
3823 fs->block_map = ctx->block_found_map;
3824 clear_problem_context(&pctx);
3825 pctx.errcode = ext2fs_create_resize_inode(fs);
3826 if (pctx.errcode) {
3827 fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
3828 /* Should never get here */
3829 ctx->flags |= E2F_FLAG_ABORT;
3830 return;
3831 }
Mike Frysinger874af852006-03-08 07:03:27 +00003832 e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
3833 "recreate inode");
3834 inode->i_mtime = time(0);
3835 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
3836 "recreate inode");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003837 fs->block_map = save_bmap;
3838 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
3839 }
3840
3841 if (ctx->flags & E2F_FLAG_RESTART) {
3842 /*
3843 * Only the master copy of the superblock and block
3844 * group descriptors are going to be written during a
3845 * restart, so set the superblock to be used to be the
3846 * master superblock.
3847 */
3848 ctx->use_superblock = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003849 unwind_pass1();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003850 goto endit;
3851 }
3852
3853 if (ctx->block_dup_map) {
3854 if (ctx->options & E2F_OPT_PREEN) {
3855 clear_problem_context(&pctx);
3856 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
3857 }
3858 e2fsck_pass1_dupblocks(ctx, block_buf);
3859 }
3860 ext2fs_free_mem(&inodes_to_process);
3861endit:
3862 e2fsck_use_inode_shortcuts(ctx, 0);
3863
3864 ext2fs_free_mem(&block_buf);
3865 ext2fs_free_mem(&inode);
3866
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003867}
3868
3869/*
3870 * When the inode_scan routines call this callback at the end of the
3871 * glock group, call process_inodes.
3872 */
3873static errcode_t scan_callback(ext2_filsys fs,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00003874 ext2_inode_scan scan FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003875 dgrp_t group, void * priv_data)
3876{
3877 struct scan_callback_struct *scan_struct;
3878 e2fsck_t ctx;
3879
3880 scan_struct = (struct scan_callback_struct *) priv_data;
3881 ctx = scan_struct->ctx;
3882
3883 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
3884
3885 if (ctx->progress)
3886 if ((ctx->progress)(ctx, 1, group+1,
3887 ctx->fs->group_desc_count))
3888 return EXT2_ET_CANCEL_REQUESTED;
3889
3890 return 0;
3891}
3892
3893/*
3894 * Process the inodes in the "inodes to process" list.
3895 */
3896static void process_inodes(e2fsck_t ctx, char *block_buf)
3897{
3898 int i;
3899 struct ext2_inode *old_stashed_inode;
3900 ext2_ino_t old_stashed_ino;
3901 const char *old_operation;
3902 char buf[80];
3903 struct problem_context pctx;
3904
Rob Landley3e72c592006-04-06 22:49:04 +00003905 /* begin process_inodes */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003906 if (process_inode_count == 0)
3907 return;
3908 old_operation = ehandler_operation(0);
3909 old_stashed_inode = ctx->stashed_inode;
3910 old_stashed_ino = ctx->stashed_ino;
3911 qsort(inodes_to_process, process_inode_count,
3912 sizeof(struct process_inode_block), process_inode_cmp);
3913 clear_problem_context(&pctx);
3914 for (i=0; i < process_inode_count; i++) {
3915 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
3916 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003917 sprintf(buf, _("reading indirect blocks of inode %u"),
3918 pctx.ino);
3919 ehandler_operation(buf);
3920 check_blocks(ctx, &pctx, block_buf);
3921 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3922 break;
3923 }
3924 ctx->stashed_inode = old_stashed_inode;
3925 ctx->stashed_ino = old_stashed_ino;
3926 process_inode_count = 0;
Rob Landley3e72c592006-04-06 22:49:04 +00003927 /* end process inodes */
3928
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003929 ehandler_operation(old_operation);
3930}
3931
3932static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
3933{
3934 const struct process_inode_block *ib_a =
3935 (const struct process_inode_block *) a;
3936 const struct process_inode_block *ib_b =
3937 (const struct process_inode_block *) b;
3938 int ret;
3939
3940 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
3941 ib_b->inode.i_block[EXT2_IND_BLOCK]);
3942 if (ret == 0)
3943 ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
3944 return ret;
3945}
3946
3947/*
3948 * Mark an inode as being bad in some what
3949 */
3950static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
3951{
3952 struct problem_context pctx;
3953
3954 if (!ctx->inode_bad_map) {
3955 clear_problem_context(&pctx);
3956
3957 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
3958 _("bad inode map"), &ctx->inode_bad_map);
3959 if (pctx.errcode) {
3960 pctx.num = 3;
3961 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3962 /* Should never get here */
3963 ctx->flags |= E2F_FLAG_ABORT;
3964 return;
3965 }
3966 }
3967 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
3968}
3969
3970
3971/*
3972 * This procedure will allocate the inode "bb" (badblock) map table
3973 */
3974static void alloc_bb_map(e2fsck_t ctx)
3975{
3976 struct problem_context pctx;
3977
3978 clear_problem_context(&pctx);
3979 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
3980 _("inode in bad block map"),
3981 &ctx->inode_bb_map);
3982 if (pctx.errcode) {
3983 pctx.num = 4;
3984 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3985 /* Should never get here */
3986 ctx->flags |= E2F_FLAG_ABORT;
3987 return;
3988 }
3989}
3990
3991/*
3992 * This procedure will allocate the inode imagic table
3993 */
3994static void alloc_imagic_map(e2fsck_t ctx)
3995{
3996 struct problem_context pctx;
3997
3998 clear_problem_context(&pctx);
3999 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
4000 _("imagic inode map"),
4001 &ctx->inode_imagic_map);
4002 if (pctx.errcode) {
4003 pctx.num = 5;
4004 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4005 /* Should never get here */
4006 ctx->flags |= E2F_FLAG_ABORT;
4007 return;
4008 }
4009}
4010
4011/*
4012 * Marks a block as in use, setting the dup_map if it's been set
4013 * already. Called by process_block and process_bad_block.
4014 *
4015 * WARNING: Assumes checks have already been done to make sure block
4016 * is valid. This is true in both process_block and process_bad_block.
4017 */
4018static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
4019{
4020 struct problem_context pctx;
4021
4022 clear_problem_context(&pctx);
4023
4024 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
4025 if (!ctx->block_dup_map) {
4026 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
4027 _("multiply claimed block map"),
4028 &ctx->block_dup_map);
4029 if (pctx.errcode) {
4030 pctx.num = 3;
4031 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
4032 &pctx);
4033 /* Should never get here */
4034 ctx->flags |= E2F_FLAG_ABORT;
4035 return;
4036 }
4037 }
4038 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
4039 } else {
4040 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
4041 }
4042}
4043
4044/*
4045 * Adjust the extended attribute block's reference counts at the end
4046 * of pass 1, either by subtracting out references for EA blocks that
4047 * are still referenced in ctx->refcount, or by adding references for
4048 * EA blocks that had extra references as accounted for in
4049 * ctx->refcount_extra.
4050 */
4051static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
4052 char *block_buf, int adjust_sign)
4053{
4054 struct ext2_ext_attr_header *header;
4055 struct problem_context pctx;
4056 ext2_filsys fs = ctx->fs;
4057 blk_t blk;
4058 __u32 should_be;
4059 int count;
4060
4061 clear_problem_context(&pctx);
4062
4063 ea_refcount_intr_begin(refcount);
4064 while (1) {
4065 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
4066 break;
4067 pctx.blk = blk;
4068 pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
4069 if (pctx.errcode) {
4070 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
4071 return;
4072 }
4073 header = (struct ext2_ext_attr_header *) block_buf;
4074 pctx.blkcount = header->h_refcount;
4075 should_be = header->h_refcount + adjust_sign * count;
4076 pctx.num = should_be;
4077 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
4078 header->h_refcount = should_be;
4079 pctx.errcode = ext2fs_write_ext_attr(fs, blk,
4080 block_buf);
4081 if (pctx.errcode) {
4082 fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
4083 continue;
4084 }
4085 }
4086 }
4087}
4088
4089/*
4090 * Handle processing the extended attribute blocks
4091 */
4092static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
4093 char *block_buf)
4094{
4095 ext2_filsys fs = ctx->fs;
4096 ext2_ino_t ino = pctx->ino;
4097 struct ext2_inode *inode = pctx->inode;
4098 blk_t blk;
4099 char * end;
4100 struct ext2_ext_attr_header *header;
4101 struct ext2_ext_attr_entry *entry;
4102 int count;
4103 region_t region;
4104
4105 blk = inode->i_file_acl;
4106 if (blk == 0)
4107 return 0;
4108
4109 /*
4110 * If the Extended attribute flag isn't set, then a non-zero
4111 * file acl means that the inode is corrupted.
4112 *
4113 * Or if the extended attribute block is an invalid block,
4114 * then the inode is also corrupted.
4115 */
4116 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
4117 (blk < fs->super->s_first_data_block) ||
4118 (blk >= fs->super->s_blocks_count)) {
4119 mark_inode_bad(ctx, ino);
4120 return 0;
4121 }
4122
4123 /* If ea bitmap hasn't been allocated, create it */
4124 if (!ctx->block_ea_map) {
4125 pctx->errcode = ext2fs_allocate_block_bitmap(fs,
4126 _("ext attr block map"),
4127 &ctx->block_ea_map);
4128 if (pctx->errcode) {
4129 pctx->num = 2;
4130 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
4131 ctx->flags |= E2F_FLAG_ABORT;
4132 return 0;
4133 }
4134 }
4135
4136 /* Create the EA refcount structure if necessary */
4137 if (!ctx->refcount) {
4138 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
4139 if (pctx->errcode) {
4140 pctx->num = 1;
4141 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
4142 ctx->flags |= E2F_FLAG_ABORT;
4143 return 0;
4144 }
4145 }
4146
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004147 /* Have we seen this EA block before? */
4148 if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
4149 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
4150 return 1;
4151 /* Ooops, this EA was referenced more than it stated */
4152 if (!ctx->refcount_extra) {
4153 pctx->errcode = ea_refcount_create(0,
4154 &ctx->refcount_extra);
4155 if (pctx->errcode) {
4156 pctx->num = 2;
4157 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
4158 ctx->flags |= E2F_FLAG_ABORT;
4159 return 0;
4160 }
4161 }
4162 ea_refcount_increment(ctx->refcount_extra, blk, 0);
4163 return 1;
4164 }
4165
4166 /*
4167 * OK, we haven't seen this EA block yet. So we need to
4168 * validate it
4169 */
4170 pctx->blk = blk;
4171 pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
4172 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
4173 goto clear_extattr;
4174 header = (struct ext2_ext_attr_header *) block_buf;
4175 pctx->blk = inode->i_file_acl;
4176 if (((ctx->ext_attr_ver == 1) &&
4177 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
4178 ((ctx->ext_attr_ver == 2) &&
4179 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
4180 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
4181 goto clear_extattr;
4182 }
4183
4184 if (header->h_blocks != 1) {
4185 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
4186 goto clear_extattr;
4187 }
4188
4189 region = region_create(0, fs->blocksize);
4190 if (!region) {
4191 fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
4192 ctx->flags |= E2F_FLAG_ABORT;
4193 return 0;
4194 }
4195 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
4196 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4197 goto clear_extattr;
4198 }
4199
4200 entry = (struct ext2_ext_attr_entry *)(header+1);
4201 end = block_buf + fs->blocksize;
4202 while ((char *)entry < end && *(__u32 *)entry) {
4203 if (region_allocate(region, (char *)entry - (char *)header,
4204 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
4205 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4206 goto clear_extattr;
4207 }
4208 if ((ctx->ext_attr_ver == 1 &&
4209 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
4210 (ctx->ext_attr_ver == 2 &&
4211 entry->e_name_index == 0)) {
4212 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
4213 goto clear_extattr;
4214 }
4215 if (entry->e_value_block != 0) {
4216 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
4217 goto clear_extattr;
4218 }
4219 if (entry->e_value_size &&
4220 region_allocate(region, entry->e_value_offs,
4221 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
4222 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4223 goto clear_extattr;
4224 }
4225 entry = EXT2_EXT_ATTR_NEXT(entry);
4226 }
4227 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
4228 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4229 goto clear_extattr;
4230 }
4231 region_free(region);
4232
4233 count = header->h_refcount - 1;
4234 if (count)
4235 ea_refcount_store(ctx->refcount, blk, count);
4236 mark_block_used(ctx, blk);
4237 ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
4238
4239 return 1;
4240
4241clear_extattr:
4242 inode->i_file_acl = 0;
4243 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
4244 return 0;
4245}
4246
4247/* Returns 1 if bad htree, 0 if OK */
4248static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00004249 ext2_ino_t ino FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004250 struct ext2_inode *inode,
4251 char *block_buf)
4252{
4253 struct ext2_dx_root_info *root;
4254 ext2_filsys fs = ctx->fs;
4255 errcode_t retval;
4256 blk_t blk;
4257
4258 if ((!LINUX_S_ISDIR(inode->i_mode) &&
4259 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
4260 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
4261 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
4262 return 1;
4263
4264 blk = inode->i_block[0];
4265 if (((blk == 0) ||
4266 (blk < fs->super->s_first_data_block) ||
4267 (blk >= fs->super->s_blocks_count)) &&
4268 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
4269 return 1;
4270
4271 retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
4272 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
4273 return 1;
4274
4275 /* XXX should check that beginning matches a directory */
4276 root = (struct ext2_dx_root_info *) (block_buf + 24);
4277
4278 if ((root->reserved_zero || root->info_length < 8) &&
4279 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
4280 return 1;
4281
4282 pctx->num = root->hash_version;
4283 if ((root->hash_version != EXT2_HASH_LEGACY) &&
4284 (root->hash_version != EXT2_HASH_HALF_MD4) &&
4285 (root->hash_version != EXT2_HASH_TEA) &&
4286 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
4287 return 1;
4288
4289 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
4290 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
4291 return 1;
4292
4293 pctx->num = root->indirect_levels;
4294 if ((root->indirect_levels > 1) &&
4295 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
4296 return 1;
4297
4298 return 0;
4299}
4300
4301/*
4302 * This subroutine is called on each inode to account for all of the
4303 * blocks used by that inode.
4304 */
4305static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
4306 char *block_buf)
4307{
4308 ext2_filsys fs = ctx->fs;
4309 struct process_block_struct_1 pb;
4310 ext2_ino_t ino = pctx->ino;
4311 struct ext2_inode *inode = pctx->inode;
4312 int bad_size = 0;
4313 int dirty_inode = 0;
4314 __u64 size;
4315
4316 pb.ino = ino;
4317 pb.num_blocks = 0;
4318 pb.last_block = -1;
4319 pb.num_illegal_blocks = 0;
4320 pb.suppress = 0; pb.clear = 0;
4321 pb.fragmented = 0;
4322 pb.compressed = 0;
4323 pb.previous_block = 0;
4324 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
4325 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
4326 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
4327 pb.inode = inode;
4328 pb.pctx = pctx;
4329 pb.ctx = ctx;
4330 pctx->ino = ino;
4331 pctx->errcode = 0;
4332
4333 if (inode->i_flags & EXT2_COMPRBLK_FL) {
4334 if (fs->super->s_feature_incompat &
4335 EXT2_FEATURE_INCOMPAT_COMPRESSION)
4336 pb.compressed = 1;
4337 else {
4338 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
4339 inode->i_flags &= ~EXT2_COMPRBLK_FL;
4340 dirty_inode++;
4341 }
4342 }
4343 }
4344
4345 if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
4346 pb.num_blocks++;
4347
4348 if (ext2fs_inode_has_valid_blocks(inode))
4349 pctx->errcode = ext2fs_block_iterate2(fs, ino,
4350 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
4351 block_buf, process_block, &pb);
4352 end_problem_latch(ctx, PR_LATCH_BLOCK);
4353 end_problem_latch(ctx, PR_LATCH_TOOBIG);
4354 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4355 goto out;
4356 if (pctx->errcode)
4357 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
4358
4359 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
4360 ctx->fs_fragmented++;
4361
4362 if (pb.clear) {
4363 inode->i_links_count = 0;
4364 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
4365 inode->i_dtime = time(0);
4366 dirty_inode++;
4367 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
4368 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
4369 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
4370 /*
4371 * The inode was probably partially accounted for
4372 * before processing was aborted, so we need to
4373 * restart the pass 1 scan.
4374 */
4375 ctx->flags |= E2F_FLAG_RESTART;
4376 goto out;
4377 }
4378
4379 if (inode->i_flags & EXT2_INDEX_FL) {
4380 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
4381 inode->i_flags &= ~EXT2_INDEX_FL;
4382 dirty_inode++;
4383 } else {
4384#ifdef ENABLE_HTREE
4385 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
4386#endif
4387 }
4388 }
4389 if (ctx->dirs_to_hash && pb.is_dir &&
4390 !(inode->i_flags & EXT2_INDEX_FL) &&
4391 ((inode->i_size / fs->blocksize) >= 3))
4392 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
4393
4394 if (!pb.num_blocks && pb.is_dir) {
4395 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
4396 inode->i_links_count = 0;
4397 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
4398 inode->i_dtime = time(0);
4399 dirty_inode++;
4400 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
4401 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
4402 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
4403 ctx->fs_directory_count--;
4404 goto out;
4405 }
4406 }
4407
4408 pb.num_blocks *= (fs->blocksize / 512);
Rob Landley3e72c592006-04-06 22:49:04 +00004409
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004410 if (pb.is_dir) {
4411 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
4412 if (nblock > (pb.last_block + 1))
4413 bad_size = 1;
4414 else if (nblock < (pb.last_block + 1)) {
4415 if (((pb.last_block + 1) - nblock) >
4416 fs->super->s_prealloc_dir_blocks)
4417 bad_size = 2;
4418 }
4419 } else {
4420 size = EXT2_I_SIZE(inode);
4421 if ((pb.last_block >= 0) &&
4422 (size < (__u64) pb.last_block * fs->blocksize))
4423 bad_size = 3;
4424 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
4425 bad_size = 4;
4426 }
4427 /* i_size for symlinks is checked elsewhere */
4428 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
4429 pctx->num = (pb.last_block+1) * fs->blocksize;
4430 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
4431 inode->i_size = pctx->num;
4432 if (!LINUX_S_ISDIR(inode->i_mode))
4433 inode->i_size_high = pctx->num >> 32;
4434 dirty_inode++;
4435 }
4436 pctx->num = 0;
4437 }
4438 if (LINUX_S_ISREG(inode->i_mode) &&
4439 (inode->i_size_high || inode->i_size & 0x80000000UL))
4440 ctx->large_files++;
4441 if (pb.num_blocks != inode->i_blocks) {
4442 pctx->num = pb.num_blocks;
4443 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
4444 inode->i_blocks = pb.num_blocks;
4445 dirty_inode++;
4446 }
4447 pctx->num = 0;
4448 }
4449out:
4450 if (dirty_inode)
4451 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
4452}
4453
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004454
4455/*
4456 * This is a helper function for check_blocks().
4457 */
4458static int process_block(ext2_filsys fs,
4459 blk_t *block_nr,
4460 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00004461 blk_t ref_block FSCK_ATTR((unused)),
4462 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004463 void *priv_data)
4464{
4465 struct process_block_struct_1 *p;
4466 struct problem_context *pctx;
4467 blk_t blk = *block_nr;
4468 int ret_code = 0;
4469 int problem = 0;
4470 e2fsck_t ctx;
4471
4472 p = (struct process_block_struct_1 *) priv_data;
4473 pctx = p->pctx;
4474 ctx = p->ctx;
4475
4476 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
4477 /* todo: Check that the comprblk_fl is high, that the
4478 blkaddr pattern looks right (all non-holes up to
4479 first EXT2FS_COMPRESSED_BLKADDR, then all
4480 EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
4481 that the feature_incompat bit is high, and that the
4482 inode is a regular file. If we're doing a "full
4483 check" (a concept introduced to e2fsck by e2compr,
4484 meaning that we look at data blocks as well as
4485 metadata) then call some library routine that
4486 checks the compressed data. I'll have to think
4487 about this, because one particularly important
4488 problem to be able to fix is to recalculate the
4489 cluster size if necessary. I think that perhaps
4490 we'd better do most/all e2compr-specific checks
4491 separately, after the non-e2compr checks. If not
4492 doing a full check, it may be useful to test that
4493 the personality is linux; e.g. if it isn't then
4494 perhaps this really is just an illegal block. */
4495 return 0;
4496 }
4497
4498 if (blk == 0) {
4499 if (p->is_dir == 0) {
4500 /*
4501 * Should never happen, since only directories
4502 * get called with BLOCK_FLAG_HOLE
4503 */
4504#if DEBUG_E2FSCK
4505 printf("process_block() called with blk == 0, "
4506 "blockcnt=%d, inode %lu???\n",
4507 blockcnt, p->ino);
4508#endif
4509 return 0;
4510 }
4511 if (blockcnt < 0)
4512 return 0;
4513 if (blockcnt * fs->blocksize < p->inode->i_size) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004514 goto mark_dir;
4515 }
4516 return 0;
4517 }
4518
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004519 /*
4520 * Simplistic fragmentation check. We merely require that the
4521 * file be contiguous. (Which can never be true for really
4522 * big files that are greater than a block group.)
4523 */
4524 if (!HOLE_BLKADDR(p->previous_block)) {
4525 if (p->previous_block+1 != blk)
4526 p->fragmented = 1;
4527 }
4528 p->previous_block = blk;
4529
4530 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
4531 problem = PR_1_TOOBIG_DIR;
4532 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
4533 problem = PR_1_TOOBIG_REG;
4534 if (!p->is_dir && !p->is_reg && blockcnt > 0)
4535 problem = PR_1_TOOBIG_SYMLINK;
4536
4537 if (blk < fs->super->s_first_data_block ||
4538 blk >= fs->super->s_blocks_count)
4539 problem = PR_1_ILLEGAL_BLOCK_NUM;
4540
4541 if (problem) {
4542 p->num_illegal_blocks++;
4543 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
4544 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
4545 p->clear = 1;
4546 return BLOCK_ABORT;
4547 }
4548 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
4549 p->suppress = 1;
4550 set_latch_flags(PR_LATCH_BLOCK,
4551 PRL_SUPPRESS, 0);
4552 }
4553 }
4554 pctx->blk = blk;
4555 pctx->blkcount = blockcnt;
4556 if (fix_problem(ctx, problem, pctx)) {
4557 blk = *block_nr = 0;
4558 ret_code = BLOCK_CHANGED;
4559 goto mark_dir;
4560 } else
4561 return 0;
4562 }
4563
4564 if (p->ino == EXT2_RESIZE_INO) {
4565 /*
4566 * The resize inode has already be sanity checked
4567 * during pass #0 (the superblock checks). All we
4568 * have to do is mark the double indirect block as
4569 * being in use; all of the other blocks are handled
4570 * by mark_table_blocks()).
4571 */
4572 if (blockcnt == BLOCK_COUNT_DIND)
4573 mark_block_used(ctx, blk);
4574 } else
4575 mark_block_used(ctx, blk);
4576 p->num_blocks++;
4577 if (blockcnt >= 0)
4578 p->last_block = blockcnt;
4579mark_dir:
4580 if (p->is_dir && (blockcnt >= 0)) {
4581 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
4582 blk, blockcnt);
4583 if (pctx->errcode) {
4584 pctx->blk = blk;
4585 pctx->num = blockcnt;
4586 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
4587 /* Should never get here */
4588 ctx->flags |= E2F_FLAG_ABORT;
4589 return BLOCK_ABORT;
4590 }
4591 }
4592 return ret_code;
4593}
4594
4595static int process_bad_block(ext2_filsys fs,
4596 blk_t *block_nr,
4597 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00004598 blk_t ref_block FSCK_ATTR((unused)),
4599 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004600 void *priv_data)
4601{
4602 struct process_block_struct_1 *p;
4603 blk_t blk = *block_nr;
4604 blk_t first_block;
4605 dgrp_t i;
4606 struct problem_context *pctx;
4607 e2fsck_t ctx;
4608
4609 /*
4610 * Note: This function processes blocks for the bad blocks
4611 * inode, which is never compressed. So we don't use HOLE_BLKADDR().
4612 */
4613
4614 if (!blk)
4615 return 0;
4616
4617 p = (struct process_block_struct_1 *) priv_data;
4618 ctx = p->ctx;
4619 pctx = p->pctx;
4620
4621 pctx->ino = EXT2_BAD_INO;
4622 pctx->blk = blk;
4623 pctx->blkcount = blockcnt;
4624
4625 if ((blk < fs->super->s_first_data_block) ||
4626 (blk >= fs->super->s_blocks_count)) {
4627 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
4628 *block_nr = 0;
4629 return BLOCK_CHANGED;
4630 } else
4631 return 0;
4632 }
4633
4634 if (blockcnt < 0) {
4635 if (ext2fs_test_block_bitmap(p->fs_meta_blocks, blk)) {
4636 p->bbcheck = 1;
4637 if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) {
4638 *block_nr = 0;
4639 return BLOCK_CHANGED;
4640 }
4641 } else if (ext2fs_test_block_bitmap(ctx->block_found_map,
4642 blk)) {
4643 p->bbcheck = 1;
4644 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
4645 pctx)) {
4646 *block_nr = 0;
4647 return BLOCK_CHANGED;
4648 }
4649 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4650 return BLOCK_ABORT;
4651 } else
4652 mark_block_used(ctx, blk);
4653 return 0;
4654 }
Rob Landley3e72c592006-04-06 22:49:04 +00004655
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004656 ctx->fs_badblocks_count++;
4657 /*
4658 * If the block is not used, then mark it as used and return.
4659 * If it is already marked as found, this must mean that
4660 * there's an overlap between the filesystem table blocks
4661 * (bitmaps and inode table) and the bad block list.
4662 */
4663 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
4664 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
4665 return 0;
4666 }
4667 /*
4668 * Try to find the where the filesystem block was used...
4669 */
4670 first_block = fs->super->s_first_data_block;
4671
4672 for (i = 0; i < fs->group_desc_count; i++ ) {
4673 pctx->group = i;
4674 pctx->blk = blk;
4675 if (!ext2fs_bg_has_super(fs, i))
4676 goto skip_super;
4677 if (blk == first_block) {
4678 if (i == 0) {
4679 if (fix_problem(ctx,
4680 PR_1_BAD_PRIMARY_SUPERBLOCK,
4681 pctx)) {
4682 *block_nr = 0;
4683 return BLOCK_CHANGED;
4684 }
4685 return 0;
4686 }
4687 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
4688 return 0;
4689 }
4690 if ((blk > first_block) &&
4691 (blk <= first_block + fs->desc_blocks)) {
4692 if (i == 0) {
4693 pctx->blk = *block_nr;
4694 if (fix_problem(ctx,
4695 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
4696 *block_nr = 0;
4697 return BLOCK_CHANGED;
4698 }
4699 return 0;
4700 }
4701 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
4702 return 0;
4703 }
4704 skip_super:
4705 if (blk == fs->group_desc[i].bg_block_bitmap) {
4706 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
4707 ctx->invalid_block_bitmap_flag[i]++;
4708 ctx->invalid_bitmaps++;
4709 }
4710 return 0;
4711 }
4712 if (blk == fs->group_desc[i].bg_inode_bitmap) {
4713 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
4714 ctx->invalid_inode_bitmap_flag[i]++;
4715 ctx->invalid_bitmaps++;
4716 }
4717 return 0;
4718 }
4719 if ((blk >= fs->group_desc[i].bg_inode_table) &&
4720 (blk < (fs->group_desc[i].bg_inode_table +
4721 fs->inode_blocks_per_group))) {
4722 /*
4723 * If there are bad blocks in the inode table,
4724 * the inode scan code will try to do
4725 * something reasonable automatically.
4726 */
4727 return 0;
4728 }
4729 first_block += fs->super->s_blocks_per_group;
4730 }
4731 /*
4732 * If we've gotten to this point, then the only
4733 * possibility is that the bad block inode meta data
4734 * is using a bad block.
4735 */
4736 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
4737 (blk == p->inode->i_block[EXT2_DIND_BLOCK]) ||
4738 (blk == p->inode->i_block[EXT2_TIND_BLOCK])) {
4739 p->bbcheck = 1;
4740 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) {
4741 *block_nr = 0;
4742 return BLOCK_CHANGED;
4743 }
4744 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4745 return BLOCK_ABORT;
4746 return 0;
4747 }
4748
4749 pctx->group = -1;
4750
4751 /* Warn user that the block wasn't claimed */
4752 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
4753
4754 return 0;
4755}
4756
4757static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
4758 const char *name, int num, blk_t *new_block)
4759{
4760 ext2_filsys fs = ctx->fs;
4761 blk_t old_block = *new_block;
4762 int i;
4763 char *buf;
4764 struct problem_context pctx;
4765
4766 clear_problem_context(&pctx);
4767
4768 pctx.group = group;
4769 pctx.blk = old_block;
4770 pctx.str = name;
4771
4772 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
4773 first_block + fs->super->s_blocks_per_group,
4774 num, ctx->block_found_map, new_block);
4775 if (pctx.errcode) {
4776 pctx.num = num;
4777 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
4778 ext2fs_unmark_valid(fs);
4779 return;
4780 }
4781 pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf);
4782 if (pctx.errcode) {
4783 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
4784 ext2fs_unmark_valid(fs);
4785 return;
4786 }
4787 ext2fs_mark_super_dirty(fs);
4788 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
4789 pctx.blk2 = *new_block;
4790 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
4791 PR_1_RELOC_TO), &pctx);
4792 pctx.blk2 = 0;
4793 for (i = 0; i < num; i++) {
4794 pctx.blk = i;
4795 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
4796 if (old_block) {
4797 pctx.errcode = io_channel_read_blk(fs->io,
4798 old_block + i, 1, buf);
4799 if (pctx.errcode)
4800 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
4801 } else
4802 memset(buf, 0, fs->blocksize);
4803
4804 pctx.blk = (*new_block) + i;
4805 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
4806 1, buf);
4807 if (pctx.errcode)
4808 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
4809 }
4810 ext2fs_free_mem(&buf);
4811}
4812
4813/*
4814 * This routine gets called at the end of pass 1 if bad blocks are
4815 * detected in the superblock, group descriptors, inode_bitmaps, or
4816 * block bitmaps. At this point, all of the blocks have been mapped
4817 * out, so we can try to allocate new block(s) to replace the bad
4818 * blocks.
4819 */
4820static void handle_fs_bad_blocks(e2fsck_t ctx)
4821{
4822 ext2_filsys fs = ctx->fs;
4823 dgrp_t i;
4824 int first_block = fs->super->s_first_data_block;
4825
4826 for (i = 0; i < fs->group_desc_count; i++) {
4827 if (ctx->invalid_block_bitmap_flag[i]) {
4828 new_table_block(ctx, first_block, i, _("block bitmap"),
4829 1, &fs->group_desc[i].bg_block_bitmap);
4830 }
4831 if (ctx->invalid_inode_bitmap_flag[i]) {
4832 new_table_block(ctx, first_block, i, _("inode bitmap"),
4833 1, &fs->group_desc[i].bg_inode_bitmap);
4834 }
4835 if (ctx->invalid_inode_table_flag[i]) {
4836 new_table_block(ctx, first_block, i, _("inode table"),
4837 fs->inode_blocks_per_group,
4838 &fs->group_desc[i].bg_inode_table);
4839 ctx->flags |= E2F_FLAG_RESTART;
4840 }
4841 first_block += fs->super->s_blocks_per_group;
4842 }
4843 ctx->invalid_bitmaps = 0;
4844}
4845
4846/*
4847 * This routine marks all blocks which are used by the superblock,
4848 * group descriptors, inode bitmaps, and block bitmaps.
4849 */
4850static void mark_table_blocks(e2fsck_t ctx)
4851{
4852 ext2_filsys fs = ctx->fs;
4853 blk_t block, b;
4854 dgrp_t i;
4855 int j;
4856 struct problem_context pctx;
4857
4858 clear_problem_context(&pctx);
4859
4860 block = fs->super->s_first_data_block;
4861 for (i = 0; i < fs->group_desc_count; i++) {
4862 pctx.group = i;
4863
4864 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
4865
4866 /*
4867 * Mark the blocks used for the inode table
4868 */
4869 if (fs->group_desc[i].bg_inode_table) {
4870 for (j = 0, b = fs->group_desc[i].bg_inode_table;
4871 j < fs->inode_blocks_per_group;
4872 j++, b++) {
4873 if (ext2fs_test_block_bitmap(ctx->block_found_map,
4874 b)) {
4875 pctx.blk = b;
4876 if (fix_problem(ctx,
4877 PR_1_ITABLE_CONFLICT, &pctx)) {
4878 ctx->invalid_inode_table_flag[i]++;
4879 ctx->invalid_bitmaps++;
4880 }
4881 } else {
4882 ext2fs_mark_block_bitmap(ctx->block_found_map,
4883 b);
4884 }
4885 }
4886 }
4887
4888 /*
4889 * Mark block used for the block bitmap
4890 */
4891 if (fs->group_desc[i].bg_block_bitmap) {
4892 if (ext2fs_test_block_bitmap(ctx->block_found_map,
4893 fs->group_desc[i].bg_block_bitmap)) {
4894 pctx.blk = fs->group_desc[i].bg_block_bitmap;
4895 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
4896 ctx->invalid_block_bitmap_flag[i]++;
4897 ctx->invalid_bitmaps++;
4898 }
4899 } else {
4900 ext2fs_mark_block_bitmap(ctx->block_found_map,
4901 fs->group_desc[i].bg_block_bitmap);
4902 }
4903
4904 }
4905 /*
4906 * Mark block used for the inode bitmap
4907 */
4908 if (fs->group_desc[i].bg_inode_bitmap) {
4909 if (ext2fs_test_block_bitmap(ctx->block_found_map,
4910 fs->group_desc[i].bg_inode_bitmap)) {
4911 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
4912 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
4913 ctx->invalid_inode_bitmap_flag[i]++;
4914 ctx->invalid_bitmaps++;
4915 }
4916 } else {
4917 ext2fs_mark_block_bitmap(ctx->block_found_map,
4918 fs->group_desc[i].bg_inode_bitmap);
4919 }
4920 }
4921 block += fs->super->s_blocks_per_group;
4922 }
4923}
4924
4925/*
4926 * Thes subroutines short circuits ext2fs_get_blocks and
4927 * ext2fs_check_directory; we use them since we already have the inode
4928 * structure, so there's no point in letting the ext2fs library read
4929 * the inode again.
4930 */
4931static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
4932 blk_t *blocks)
4933{
4934 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4935 int i;
4936
4937 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
4938 return EXT2_ET_CALLBACK_NOTHANDLED;
4939
4940 for (i=0; i < EXT2_N_BLOCKS; i++)
4941 blocks[i] = ctx->stashed_inode->i_block[i];
4942 return 0;
4943}
4944
4945static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
4946 struct ext2_inode *inode)
4947{
4948 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4949
4950 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
4951 return EXT2_ET_CALLBACK_NOTHANDLED;
4952 *inode = *ctx->stashed_inode;
4953 return 0;
4954}
4955
4956static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
4957 struct ext2_inode *inode)
4958{
4959 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4960
4961 if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
4962 *ctx->stashed_inode = *inode;
4963 return EXT2_ET_CALLBACK_NOTHANDLED;
4964}
4965
4966static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
4967{
4968 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4969
4970 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
4971 return EXT2_ET_CALLBACK_NOTHANDLED;
4972
4973 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
4974 return EXT2_ET_NO_DIRECTORY;
4975 return 0;
4976}
4977
4978void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
4979{
4980 ext2_filsys fs = ctx->fs;
4981
4982 if (bool) {
4983 fs->get_blocks = pass1_get_blocks;
4984 fs->check_directory = pass1_check_directory;
4985 fs->read_inode = pass1_read_inode;
4986 fs->write_inode = pass1_write_inode;
4987 ctx->stashed_ino = 0;
4988 } else {
4989 fs->get_blocks = 0;
4990 fs->check_directory = 0;
4991 fs->read_inode = 0;
4992 fs->write_inode = 0;
4993 }
4994}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004995
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004996/*
4997 * pass1b.c --- Pass #1b of e2fsck
4998 *
4999 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
5000 * only invoked if pass 1 discovered blocks which are in use by more
5001 * than one inode.
5002 *
5003 * Pass1B scans the data blocks of all the inodes again, generating a
5004 * complete list of duplicate blocks and which inodes have claimed
5005 * them.
5006 *
5007 * Pass1C does a tree-traversal of the filesystem, to determine the
5008 * parent directories of these inodes. This step is necessary so that
5009 * e2fsck can print out the pathnames of affected inodes.
5010 *
5011 * Pass1D is a reconciliation pass. For each inode with duplicate
5012 * blocks, the user is prompted if s/he would like to clone the file
5013 * (so that the file gets a fresh copy of the duplicated blocks) or
5014 * simply to delete the file.
5015 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005016 */
5017
5018
5019/* Needed for architectures where sizeof(int) != sizeof(void *) */
5020#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
5021#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
5022
5023/* Define an extension to the ext2 library's block count information */
5024#define BLOCK_COUNT_EXTATTR (-5)
5025
5026struct block_el {
5027 blk_t block;
5028 struct block_el *next;
5029};
5030
5031struct inode_el {
5032 ext2_ino_t inode;
5033 struct inode_el *next;
5034};
5035
5036struct dup_block {
5037 int num_bad;
5038 struct inode_el *inode_list;
5039};
5040
5041/*
5042 * This structure stores information about a particular inode which
5043 * is sharing blocks with other inodes. This information is collected
5044 * to display to the user, so that the user knows what files he or she
5045 * is dealing with, when trying to decide how to resolve the conflict
5046 * of multiply-claimed blocks.
5047 */
5048struct dup_inode {
5049 ext2_ino_t dir;
5050 int num_dupblocks;
5051 struct ext2_inode inode;
5052 struct block_el *block_list;
5053};
5054
5055static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
5056 e2_blkcnt_t blockcnt, blk_t ref_blk,
5057 int ref_offset, void *priv_data);
5058static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
5059 struct dup_inode *dp, char *block_buf);
5060static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
5061 struct dup_inode *dp, char* block_buf);
5062static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
5063
5064static void pass1b(e2fsck_t ctx, char *block_buf);
5065static void pass1c(e2fsck_t ctx, char *block_buf);
5066static void pass1d(e2fsck_t ctx, char *block_buf);
5067
5068static int dup_inode_count = 0;
5069
5070static dict_t blk_dict, ino_dict;
5071
5072static ext2fs_inode_bitmap inode_dup_map;
5073
5074static int dict_int_cmp(const void *a, const void *b)
5075{
5076 intptr_t ia, ib;
5077
5078 ia = (intptr_t)a;
5079 ib = (intptr_t)b;
5080
5081 return (ia-ib);
5082}
5083
5084/*
5085 * Add a duplicate block record
5086 */
5087static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
5088 struct ext2_inode *inode)
5089{
5090 dnode_t *n;
5091 struct dup_block *db;
5092 struct dup_inode *di;
5093 struct block_el *blk_el;
5094 struct inode_el *ino_el;
5095
5096 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
5097 if (n)
5098 db = (struct dup_block *) dnode_get(n);
5099 else {
5100 db = (struct dup_block *) e2fsck_allocate_memory(ctx,
5101 sizeof(struct dup_block), "duplicate block header");
5102 db->num_bad = 0;
5103 db->inode_list = 0;
5104 dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
5105 }
5106 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
5107 sizeof(struct inode_el), "inode element");
5108 ino_el->inode = ino;
5109 ino_el->next = db->inode_list;
5110 db->inode_list = ino_el;
5111 db->num_bad++;
5112
5113 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
5114 if (n)
5115 di = (struct dup_inode *) dnode_get(n);
5116 else {
5117 di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
5118 sizeof(struct dup_inode), "duplicate inode header");
5119 di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0 ;
5120 di->num_dupblocks = 0;
5121 di->block_list = 0;
5122 di->inode = *inode;
5123 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
5124 }
5125 blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
5126 sizeof(struct block_el), "block element");
5127 blk_el->block = blk;
5128 blk_el->next = di->block_list;
5129 di->block_list = blk_el;
5130 di->num_dupblocks++;
5131}
5132
5133/*
5134 * Free a duplicate inode record
5135 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00005136static void inode_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005137{
5138 struct dup_inode *di;
5139 struct block_el *p, *next;
5140
5141 di = (struct dup_inode *) dnode_get(node);
5142 for (p = di->block_list; p; p = next) {
5143 next = p->next;
5144 free(p);
5145 }
5146 free(node);
5147}
5148
5149/*
5150 * Free a duplicate block record
5151 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00005152static void block_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005153{
5154 struct dup_block *db;
5155 struct inode_el *p, *next;
5156
5157 db = (struct dup_block *) dnode_get(node);
5158 for (p = db->inode_list; p; p = next) {
5159 next = p->next;
5160 free(p);
5161 }
5162 free(node);
5163}
5164
5165
5166/*
5167 * Main procedure for handling duplicate blocks
5168 */
5169void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
5170{
5171 ext2_filsys fs = ctx->fs;
5172 struct problem_context pctx;
5173
5174 clear_problem_context(&pctx);
5175
5176 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
5177 _("multiply claimed inode map"), &inode_dup_map);
5178 if (pctx.errcode) {
5179 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
5180 ctx->flags |= E2F_FLAG_ABORT;
5181 return;
5182 }
5183
5184 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
5185 dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00005186 dict_set_allocator(&ino_dict, inode_dnode_free);
5187 dict_set_allocator(&blk_dict, block_dnode_free);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005188
5189 pass1b(ctx, block_buf);
5190 pass1c(ctx, block_buf);
5191 pass1d(ctx, block_buf);
5192
5193 /*
5194 * Time to free all of the accumulated data structures that we
5195 * don't need anymore.
5196 */
5197 dict_free_nodes(&ino_dict);
5198 dict_free_nodes(&blk_dict);
5199}
5200
5201/*
5202 * Scan the inodes looking for inodes that contain duplicate blocks.
5203 */
5204struct process_block_struct_1b {
5205 e2fsck_t ctx;
5206 ext2_ino_t ino;
5207 int dup_blocks;
5208 struct ext2_inode *inode;
5209 struct problem_context *pctx;
5210};
5211
5212static void pass1b(e2fsck_t ctx, char *block_buf)
5213{
5214 ext2_filsys fs = ctx->fs;
5215 ext2_ino_t ino;
5216 struct ext2_inode inode;
5217 ext2_inode_scan scan;
5218 struct process_block_struct_1b pb;
5219 struct problem_context pctx;
5220
5221 clear_problem_context(&pctx);
5222
5223 if (!(ctx->options & E2F_OPT_PREEN))
5224 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
5225 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
5226 &scan);
5227 if (pctx.errcode) {
5228 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
5229 ctx->flags |= E2F_FLAG_ABORT;
5230 return;
5231 }
5232 ctx->stashed_inode = &inode;
5233 pb.ctx = ctx;
5234 pb.pctx = &pctx;
5235 pctx.str = "pass1b";
5236 while (1) {
5237 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
5238 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
5239 continue;
5240 if (pctx.errcode) {
5241 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
5242 ctx->flags |= E2F_FLAG_ABORT;
5243 return;
5244 }
5245 if (!ino)
5246 break;
5247 pctx.ino = ctx->stashed_ino = ino;
5248 if ((ino != EXT2_BAD_INO) &&
5249 !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
5250 continue;
5251
5252 pb.ino = ino;
5253 pb.dup_blocks = 0;
5254 pb.inode = &inode;
5255
5256 if (ext2fs_inode_has_valid_blocks(&inode) ||
5257 (ino == EXT2_BAD_INO))
5258 pctx.errcode = ext2fs_block_iterate2(fs, ino,
5259 0, block_buf, process_pass1b_block, &pb);
5260 if (inode.i_file_acl)
5261 process_pass1b_block(fs, &inode.i_file_acl,
5262 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
5263 if (pb.dup_blocks) {
5264 end_problem_latch(ctx, PR_LATCH_DBLOCK);
5265 if (ino >= EXT2_FIRST_INODE(fs->super) ||
5266 ino == EXT2_ROOT_INO)
5267 dup_inode_count++;
5268 }
5269 if (pctx.errcode)
5270 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
5271 }
5272 ext2fs_close_inode_scan(scan);
5273 e2fsck_use_inode_shortcuts(ctx, 0);
5274}
5275
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005276static int process_pass1b_block(ext2_filsys fs FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005277 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005278 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
5279 blk_t ref_blk FSCK_ATTR((unused)),
5280 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005281 void *priv_data)
5282{
5283 struct process_block_struct_1b *p;
5284 e2fsck_t ctx;
5285
5286 if (HOLE_BLKADDR(*block_nr))
5287 return 0;
5288 p = (struct process_block_struct_1b *) priv_data;
5289 ctx = p->ctx;
5290
5291 if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
5292 return 0;
5293
5294 /* OK, this is a duplicate block */
5295 if (p->ino != EXT2_BAD_INO) {
5296 p->pctx->blk = *block_nr;
5297 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
5298 }
5299 p->dup_blocks++;
5300 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
5301
5302 add_dupe(ctx, p->ino, *block_nr, p->inode);
5303
5304 return 0;
5305}
5306
5307/*
5308 * Pass 1c: Scan directories for inodes with duplicate blocks. This
5309 * is used so that we can print pathnames when prompting the user for
5310 * what to do.
5311 */
5312struct search_dir_struct {
5313 int count;
5314 ext2_ino_t first_inode;
5315 ext2_ino_t max_inode;
5316};
5317
5318static int search_dirent_proc(ext2_ino_t dir, int entry,
5319 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005320 int offset FSCK_ATTR((unused)),
5321 int blocksize FSCK_ATTR((unused)),
5322 char *buf FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005323 void *priv_data)
5324{
5325 struct search_dir_struct *sd;
5326 struct dup_inode *p;
5327 dnode_t *n;
5328
5329 sd = (struct search_dir_struct *) priv_data;
5330
5331 if (dirent->inode > sd->max_inode)
5332 /* Should abort this inode, but not everything */
5333 return 0;
5334
5335 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
5336 !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
5337 return 0;
5338
5339 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
5340 if (!n)
5341 return 0;
5342 p = (struct dup_inode *) dnode_get(n);
5343 p->dir = dir;
5344 sd->count--;
5345
5346 return(sd->count ? 0 : DIRENT_ABORT);
5347}
5348
5349
5350static void pass1c(e2fsck_t ctx, char *block_buf)
5351{
5352 ext2_filsys fs = ctx->fs;
5353 struct search_dir_struct sd;
5354 struct problem_context pctx;
5355
5356 clear_problem_context(&pctx);
5357
5358 if (!(ctx->options & E2F_OPT_PREEN))
5359 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
5360
5361 /*
5362 * Search through all directories to translate inodes to names
5363 * (by searching for the containing directory for that inode.)
5364 */
5365 sd.count = dup_inode_count;
5366 sd.first_inode = EXT2_FIRST_INODE(fs->super);
5367 sd.max_inode = fs->super->s_inodes_count;
5368 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
5369 search_dirent_proc, &sd);
5370}
5371
5372static void pass1d(e2fsck_t ctx, char *block_buf)
5373{
5374 ext2_filsys fs = ctx->fs;
5375 struct dup_inode *p, *t;
5376 struct dup_block *q;
5377 ext2_ino_t *shared, ino;
5378 int shared_len;
5379 int i;
5380 int file_ok;
5381 int meta_data = 0;
5382 struct problem_context pctx;
5383 dnode_t *n, *m;
5384 struct block_el *s;
5385 struct inode_el *r;
5386
5387 clear_problem_context(&pctx);
5388
5389 if (!(ctx->options & E2F_OPT_PREEN))
5390 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
5391 e2fsck_read_bitmaps(ctx);
5392
5393 pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
5394 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
5395 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
5396 sizeof(ext2_ino_t) * dict_count(&ino_dict),
5397 "Shared inode list");
5398 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
5399 p = (struct dup_inode *) dnode_get(n);
5400 shared_len = 0;
5401 file_ok = 1;
5402 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
Mike Frysinger874af852006-03-08 07:03:27 +00005403 if (ino == EXT2_BAD_INO || ino == EXT2_RESIZE_INO)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005404 continue;
5405
5406 /*
5407 * Find all of the inodes which share blocks with this
5408 * one. First we find all of the duplicate blocks
5409 * belonging to this inode, and then search each block
5410 * get the list of inodes, and merge them together.
5411 */
5412 for (s = p->block_list; s; s = s->next) {
5413 m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
5414 if (!m)
5415 continue; /* Should never happen... */
5416 q = (struct dup_block *) dnode_get(m);
5417 if (q->num_bad > 1)
5418 file_ok = 0;
5419 if (check_if_fs_block(ctx, s->block)) {
5420 file_ok = 0;
5421 meta_data = 1;
5422 }
5423
5424 /*
5425 * Add all inodes used by this block to the
5426 * shared[] --- which is a unique list, so
5427 * if an inode is already in shared[], don't
5428 * add it again.
5429 */
5430 for (r = q->inode_list; r; r = r->next) {
5431 if (r->inode == ino)
5432 continue;
5433 for (i = 0; i < shared_len; i++)
5434 if (shared[i] == r->inode)
5435 break;
5436 if (i == shared_len) {
5437 shared[shared_len++] = r->inode;
5438 }
5439 }
5440 }
5441
5442 /*
5443 * Report the inode that we are working on
5444 */
5445 pctx.inode = &p->inode;
5446 pctx.ino = ino;
5447 pctx.dir = p->dir;
5448 pctx.blkcount = p->num_dupblocks;
5449 pctx.num = meta_data ? shared_len+1 : shared_len;
5450 fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
5451 pctx.blkcount = 0;
5452 pctx.num = 0;
5453
5454 if (meta_data)
5455 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
5456
5457 for (i = 0; i < shared_len; i++) {
5458 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
5459 if (!m)
5460 continue; /* should never happen */
5461 t = (struct dup_inode *) dnode_get(m);
5462 /*
5463 * Report the inode that we are sharing with
5464 */
5465 pctx.inode = &t->inode;
5466 pctx.ino = shared[i];
5467 pctx.dir = t->dir;
5468 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
5469 }
5470 if (file_ok) {
5471 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
5472 continue;
5473 }
5474 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
5475 pctx.errcode = clone_file(ctx, ino, p, block_buf);
5476 if (pctx.errcode)
5477 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
5478 else
5479 continue;
5480 }
5481 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
5482 delete_file(ctx, ino, p, block_buf);
5483 else
5484 ext2fs_unmark_valid(fs);
5485 }
5486 ext2fs_free_mem(&shared);
5487}
5488
5489/*
5490 * Drop the refcount on the dup_block structure, and clear the entry
5491 * in the block_dup_map if appropriate.
5492 */
5493static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
5494{
5495 p->num_bad--;
5496 if (p->num_bad <= 0 ||
5497 (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
5498 ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
5499}
5500
5501static int delete_file_block(ext2_filsys fs,
5502 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005503 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
5504 blk_t ref_block FSCK_ATTR((unused)),
5505 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005506 void *priv_data)
5507{
5508 struct process_block_struct_1b *pb;
5509 struct dup_block *p;
5510 dnode_t *n;
5511 e2fsck_t ctx;
5512
5513 pb = (struct process_block_struct_1b *) priv_data;
5514 ctx = pb->ctx;
5515
5516 if (HOLE_BLKADDR(*block_nr))
5517 return 0;
5518
5519 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
5520 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
5521 if (n) {
5522 p = (struct dup_block *) dnode_get(n);
5523 decrement_badcount(ctx, *block_nr, p);
5524 } else
5525 com_err("delete_file_block", 0,
5526 _("internal error; can't find dup_blk for %d\n"),
5527 *block_nr);
5528 } else {
5529 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
5530 ext2fs_block_alloc_stats(fs, *block_nr, -1);
5531 }
5532
5533 return 0;
5534}
5535
5536static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
5537 struct dup_inode *dp, char* block_buf)
5538{
5539 ext2_filsys fs = ctx->fs;
5540 struct process_block_struct_1b pb;
5541 struct ext2_inode inode;
5542 struct problem_context pctx;
5543 unsigned int count;
5544
5545 clear_problem_context(&pctx);
5546 pctx.ino = pb.ino = ino;
5547 pb.dup_blocks = dp->num_dupblocks;
5548 pb.ctx = ctx;
5549 pctx.str = "delete_file";
5550
5551 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
5552 if (ext2fs_inode_has_valid_blocks(&inode))
5553 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
5554 delete_file_block, &pb);
5555 if (pctx.errcode)
5556 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
5557 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5558 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5559 if (ctx->inode_bad_map)
5560 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
5561 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
5562
5563 /* Inode may have changed by block_iterate, so reread it */
5564 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
5565 inode.i_links_count = 0;
5566 inode.i_dtime = time(0);
5567 if (inode.i_file_acl &&
5568 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
5569 count = 1;
5570 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
5571 block_buf, -1, &count);
5572 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
5573 pctx.errcode = 0;
5574 count = 1;
5575 }
5576 if (pctx.errcode) {
5577 pctx.blk = inode.i_file_acl;
5578 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
5579 }
5580 /*
5581 * If the count is zero, then arrange to have the
5582 * block deleted. If the block is in the block_dup_map,
5583 * also call delete_file_block since it will take care
5584 * of keeping the accounting straight.
5585 */
5586 if ((count == 0) ||
5587 ext2fs_test_block_bitmap(ctx->block_dup_map,
5588 inode.i_file_acl))
5589 delete_file_block(fs, &inode.i_file_acl,
5590 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
5591 }
5592 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
5593}
5594
5595struct clone_struct {
5596 errcode_t errcode;
5597 ext2_ino_t dir;
5598 char *buf;
5599 e2fsck_t ctx;
5600};
5601
5602static int clone_file_block(ext2_filsys fs,
5603 blk_t *block_nr,
5604 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005605 blk_t ref_block FSCK_ATTR((unused)),
5606 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005607 void *priv_data)
5608{
5609 struct dup_block *p;
5610 blk_t new_block;
5611 errcode_t retval;
5612 struct clone_struct *cs = (struct clone_struct *) priv_data;
5613 dnode_t *n;
5614 e2fsck_t ctx;
5615
5616 ctx = cs->ctx;
5617
5618 if (HOLE_BLKADDR(*block_nr))
5619 return 0;
5620
5621 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
5622 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
5623 if (n) {
5624 p = (struct dup_block *) dnode_get(n);
5625 retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
5626 &new_block);
5627 if (retval) {
5628 cs->errcode = retval;
5629 return BLOCK_ABORT;
5630 }
5631 if (cs->dir && (blockcnt >= 0)) {
5632 retval = ext2fs_set_dir_block(fs->dblist,
5633 cs->dir, new_block, blockcnt);
5634 if (retval) {
5635 cs->errcode = retval;
5636 return BLOCK_ABORT;
5637 }
5638 }
Rob Landley3e72c592006-04-06 22:49:04 +00005639
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005640 retval = io_channel_read_blk(fs->io, *block_nr, 1,
5641 cs->buf);
5642 if (retval) {
5643 cs->errcode = retval;
5644 return BLOCK_ABORT;
5645 }
5646 retval = io_channel_write_blk(fs->io, new_block, 1,
5647 cs->buf);
5648 if (retval) {
5649 cs->errcode = retval;
5650 return BLOCK_ABORT;
5651 }
5652 decrement_badcount(ctx, *block_nr, p);
5653 *block_nr = new_block;
5654 ext2fs_mark_block_bitmap(ctx->block_found_map,
5655 new_block);
5656 ext2fs_mark_block_bitmap(fs->block_map, new_block);
5657 return BLOCK_CHANGED;
5658 } else
5659 com_err("clone_file_block", 0,
5660 _("internal error; can't find dup_blk for %d\n"),
5661 *block_nr);
5662 }
5663 return 0;
5664}
5665
5666static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
5667 struct dup_inode *dp, char* block_buf)
5668{
5669 ext2_filsys fs = ctx->fs;
5670 errcode_t retval;
5671 struct clone_struct cs;
5672 struct problem_context pctx;
5673 blk_t blk;
5674 dnode_t *n;
5675 struct inode_el *ino_el;
5676 struct dup_block *db;
5677 struct dup_inode *di;
5678
5679 clear_problem_context(&pctx);
5680 cs.errcode = 0;
5681 cs.dir = 0;
5682 cs.ctx = ctx;
5683 retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
5684 if (retval)
5685 return retval;
5686
5687 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
5688 cs.dir = ino;
5689
5690 pctx.ino = ino;
5691 pctx.str = "clone_file";
5692 if (ext2fs_inode_has_valid_blocks(&dp->inode))
5693 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
5694 clone_file_block, &cs);
5695 ext2fs_mark_bb_dirty(fs);
5696 if (pctx.errcode) {
5697 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
5698 retval = pctx.errcode;
5699 goto errout;
5700 }
5701 if (cs.errcode) {
5702 com_err("clone_file", cs.errcode,
5703 _("returned from clone_file_block"));
5704 retval = cs.errcode;
5705 goto errout;
5706 }
5707 /* The inode may have changed on disk, so we have to re-read it */
5708 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
5709 blk = dp->inode.i_file_acl;
5710 if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
5711 BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
5712 BLOCK_CHANGED)) {
5713 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
5714 /*
5715 * If we cloned the EA block, find all other inodes
5716 * which refered to that EA block, and modify
5717 * them to point to the new EA block.
5718 */
5719 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
5720 db = (struct dup_block *) dnode_get(n);
5721 for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
5722 if (ino_el->inode == ino)
5723 continue;
5724 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
5725 di = (struct dup_inode *) dnode_get(n);
5726 if (di->inode.i_file_acl == blk) {
5727 di->inode.i_file_acl = dp->inode.i_file_acl;
5728 e2fsck_write_inode(ctx, ino_el->inode,
5729 &di->inode, "clone file EA");
5730 decrement_badcount(ctx, blk, db);
5731 }
5732 }
5733 }
5734 retval = 0;
5735errout:
5736 ext2fs_free_mem(&cs.buf);
5737 return retval;
5738}
5739
5740/*
5741 * This routine returns 1 if a block overlaps with one of the superblocks,
5742 * group descriptors, inode bitmaps, or block bitmaps.
5743 */
5744static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
5745{
5746 ext2_filsys fs = ctx->fs;
5747 blk_t block;
5748 dgrp_t i;
5749
5750 block = fs->super->s_first_data_block;
5751 for (i = 0; i < fs->group_desc_count; i++) {
5752
5753 /* Check superblocks/block group descriptros */
5754 if (ext2fs_bg_has_super(fs, i)) {
5755 if (test_block >= block &&
5756 (test_block <= block + fs->desc_blocks))
5757 return 1;
5758 }
5759
5760 /* Check the inode table */
5761 if ((fs->group_desc[i].bg_inode_table) &&
5762 (test_block >= fs->group_desc[i].bg_inode_table) &&
5763 (test_block < (fs->group_desc[i].bg_inode_table +
5764 fs->inode_blocks_per_group)))
5765 return 1;
5766
5767 /* Check the bitmap blocks */
5768 if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
5769 (test_block == fs->group_desc[i].bg_inode_bitmap))
5770 return 1;
5771
5772 block += fs->super->s_blocks_per_group;
5773 }
5774 return 0;
5775}
5776/*
5777 * pass2.c --- check directory structure
5778 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005779 * Pass 2 of e2fsck iterates through all active directory inodes, and
5780 * applies to following tests to each directory entry in the directory
5781 * blocks in the inodes:
5782 *
5783 * - The length of the directory entry (rec_len) should be at
5784 * least 8 bytes, and no more than the remaining space
5785 * left in the directory block.
5786 * - The length of the name in the directory entry (name_len)
5787 * should be less than (rec_len - 8).
5788 * - The inode number in the directory entry should be within
5789 * legal bounds.
5790 * - The inode number should refer to a in-use inode.
5791 * - The first entry should be '.', and its inode should be
5792 * the inode of the directory.
5793 * - The second entry should be '..'.
5794 *
5795 * To minimize disk seek time, the directory blocks are processed in
5796 * sorted order of block numbers.
5797 *
5798 * Pass 2 also collects the following information:
5799 * - The inode numbers of the subdirectories for each directory.
5800 *
5801 * Pass 2 relies on the following information from previous passes:
5802 * - The directory information collected in pass 1.
5803 * - The inode_used_map bitmap
5804 * - The inode_bad_map bitmap
5805 * - The inode_dir_map bitmap
5806 *
5807 * Pass 2 frees the following data structures
5808 * - The inode_bad_map bitmap
5809 * - The inode_reg_map bitmap
5810 */
5811
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005812/*
5813 * Keeps track of how many times an inode is referenced.
5814 */
5815static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
5816static int check_dir_block(ext2_filsys fs,
5817 struct ext2_db_entry *dir_blocks_info,
5818 void *priv_data);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00005819static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info,
5820 struct problem_context *pctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005821static int update_dir_block(ext2_filsys fs,
5822 blk_t *block_nr,
5823 e2_blkcnt_t blockcnt,
5824 blk_t ref_block,
5825 int ref_offset,
5826 void *priv_data);
5827static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
5828static int htree_depth(struct dx_dir_info *dx_dir,
5829 struct dx_dirblock_info *dx_db);
5830static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
5831
5832struct check_dir_struct {
5833 char *buf;
5834 struct problem_context pctx;
5835 int count, max;
5836 e2fsck_t ctx;
5837};
5838
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00005839static void e2fsck_pass2(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005840{
5841 struct ext2_super_block *sb = ctx->fs->super;
5842 struct problem_context pctx;
5843 ext2_filsys fs = ctx->fs;
5844 char *buf;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005845 struct dir_info *dir;
5846 struct check_dir_struct cd;
5847 struct dx_dir_info *dx_dir;
5848 struct dx_dirblock_info *dx_db, *dx_parent;
5849 int b;
5850 int i, depth;
5851 problem_t code;
5852 int bad_dir;
5853
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005854 clear_problem_context(&cd.pctx);
5855
Rob Landley3e72c592006-04-06 22:49:04 +00005856 /* Pass 2 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005857
5858 if (!(ctx->options & E2F_OPT_PREEN))
5859 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
5860
5861 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
5862 0, ctx->inode_link_info,
5863 &ctx->inode_count);
5864 if (cd.pctx.errcode) {
5865 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
5866 ctx->flags |= E2F_FLAG_ABORT;
5867 return;
5868 }
5869 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
5870 "directory scan buffer");
5871
5872 /*
5873 * Set up the parent pointer for the root directory, if
5874 * present. (If the root directory is not present, we will
5875 * create it in pass 3.)
5876 */
5877 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
5878 if (dir)
5879 dir->parent = EXT2_ROOT_INO;
5880
5881 cd.buf = buf;
5882 cd.ctx = ctx;
5883 cd.count = 1;
5884 cd.max = ext2fs_dblist_count(fs->dblist);
5885
5886 if (ctx->progress)
5887 (void) (ctx->progress)(ctx, 2, 0, cd.max);
5888
5889 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
5890 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
5891
5892 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
5893 &cd);
5894 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5895 return;
5896 if (cd.pctx.errcode) {
5897 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
5898 ctx->flags |= E2F_FLAG_ABORT;
5899 return;
5900 }
5901
5902#ifdef ENABLE_HTREE
5903 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
5904 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5905 return;
5906 if (dx_dir->numblocks == 0)
5907 continue;
5908 clear_problem_context(&pctx);
5909 bad_dir = 0;
5910 pctx.dir = dx_dir->ino;
5911 dx_db = dx_dir->dx_block;
5912 if (dx_db->flags & DX_FLAG_REFERENCED)
5913 dx_db->flags |= DX_FLAG_DUP_REF;
5914 else
5915 dx_db->flags |= DX_FLAG_REFERENCED;
5916 /*
5917 * Find all of the first and last leaf blocks, and
5918 * update their parent's min and max hash values
5919 */
5920 for (b=0, dx_db = dx_dir->dx_block;
5921 b < dx_dir->numblocks;
5922 b++, dx_db++) {
5923 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
5924 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
5925 continue;
5926 dx_parent = &dx_dir->dx_block[dx_db->parent];
5927 /*
5928 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
5929 */
5930 if (dx_db->flags & DX_FLAG_FIRST)
5931 dx_parent->min_hash = dx_db->min_hash;
5932 /*
5933 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
5934 */
5935 if (dx_db->flags & DX_FLAG_LAST)
5936 dx_parent->max_hash = dx_db->max_hash;
5937 }
5938
5939 for (b=0, dx_db = dx_dir->dx_block;
5940 b < dx_dir->numblocks;
5941 b++, dx_db++) {
5942 pctx.blkcount = b;
5943 pctx.group = dx_db->parent;
5944 code = 0;
5945 if (!(dx_db->flags & DX_FLAG_FIRST) &&
5946 (dx_db->min_hash < dx_db->node_min_hash)) {
5947 pctx.blk = dx_db->min_hash;
5948 pctx.blk2 = dx_db->node_min_hash;
5949 code = PR_2_HTREE_MIN_HASH;
5950 fix_problem(ctx, code, &pctx);
5951 bad_dir++;
5952 }
5953 if (dx_db->type == DX_DIRBLOCK_LEAF) {
5954 depth = htree_depth(dx_dir, dx_db);
5955 if (depth != dx_dir->depth) {
5956 code = PR_2_HTREE_BAD_DEPTH;
5957 fix_problem(ctx, code, &pctx);
5958 bad_dir++;
5959 }
5960 }
5961 /*
5962 * This test doesn't apply for the root block
5963 * at block #0
5964 */
5965 if (b &&
5966 (dx_db->max_hash > dx_db->node_max_hash)) {
5967 pctx.blk = dx_db->max_hash;
5968 pctx.blk2 = dx_db->node_max_hash;
5969 code = PR_2_HTREE_MAX_HASH;
5970 fix_problem(ctx, code, &pctx);
5971 bad_dir++;
5972 }
5973 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
5974 code = PR_2_HTREE_NOTREF;
5975 fix_problem(ctx, code, &pctx);
5976 bad_dir++;
5977 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
5978 code = PR_2_HTREE_DUPREF;
5979 fix_problem(ctx, code, &pctx);
5980 bad_dir++;
5981 }
5982 if (code == 0)
5983 continue;
5984 }
5985 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
5986 clear_htree(ctx, dx_dir->ino);
5987 dx_dir->numblocks = 0;
5988 }
5989 }
5990#endif
5991 ext2fs_free_mem(&buf);
5992 ext2fs_free_dblist(fs->dblist);
5993
Rob Landleye7c43b62006-03-01 16:39:45 +00005994 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
5995 ctx->inode_bad_map = 0;
5996 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
5997 ctx->inode_reg_map = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005998
5999 clear_problem_context(&pctx);
6000 if (ctx->large_files) {
6001 if (!(sb->s_feature_ro_compat &
6002 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
6003 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
6004 sb->s_feature_ro_compat |=
6005 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
6006 ext2fs_mark_super_dirty(fs);
6007 }
6008 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
6009 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
6010 ext2fs_update_dynamic_rev(fs);
6011 ext2fs_mark_super_dirty(fs);
6012 }
6013 } else if (!ctx->large_files &&
6014 (sb->s_feature_ro_compat &
6015 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
6016 if (fs->flags & EXT2_FLAG_RW) {
6017 sb->s_feature_ro_compat &=
6018 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
6019 ext2fs_mark_super_dirty(fs);
6020 }
6021 }
6022
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006023}
6024
6025#define MAX_DEPTH 32000
6026static int htree_depth(struct dx_dir_info *dx_dir,
6027 struct dx_dirblock_info *dx_db)
6028{
6029 int depth = 0;
6030
6031 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
6032 dx_db = &dx_dir->dx_block[dx_db->parent];
6033 depth++;
6034 }
6035 return depth;
6036}
6037
6038static int dict_de_cmp(const void *a, const void *b)
6039{
6040 const struct ext2_dir_entry *de_a, *de_b;
6041 int a_len, b_len;
6042
6043 de_a = (const struct ext2_dir_entry *) a;
6044 a_len = de_a->name_len & 0xFF;
6045 de_b = (const struct ext2_dir_entry *) b;
6046 b_len = de_b->name_len & 0xFF;
6047
6048 if (a_len != b_len)
6049 return (a_len - b_len);
6050
6051 return strncmp(de_a->name, de_b->name, a_len);
6052}
6053
6054/*
6055 * This is special sort function that makes sure that directory blocks
6056 * with a dirblock of zero are sorted to the beginning of the list.
6057 * This guarantees that the root node of the htree directories are
6058 * processed first, so we know what hash version to use.
6059 */
6060static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
6061{
6062 const struct ext2_db_entry *db_a =
6063 (const struct ext2_db_entry *) a;
6064 const struct ext2_db_entry *db_b =
6065 (const struct ext2_db_entry *) b;
6066
6067 if (db_a->blockcnt && !db_b->blockcnt)
6068 return 1;
6069
6070 if (!db_a->blockcnt && db_b->blockcnt)
6071 return -1;
6072
6073 if (db_a->blk != db_b->blk)
6074 return (int) (db_a->blk - db_b->blk);
6075
6076 if (db_a->ino != db_b->ino)
6077 return (int) (db_a->ino - db_b->ino);
6078
6079 return (int) (db_a->blockcnt - db_b->blockcnt);
6080}
6081
6082
6083/*
6084 * Make sure the first entry in the directory is '.', and that the
6085 * directory entry is sane.
6086 */
6087static int check_dot(e2fsck_t ctx,
6088 struct ext2_dir_entry *dirent,
6089 ext2_ino_t ino, struct problem_context *pctx)
6090{
6091 struct ext2_dir_entry *nextdir;
6092 int status = 0;
6093 int created = 0;
6094 int new_len;
6095 int problem = 0;
6096
6097 if (!dirent->inode)
6098 problem = PR_2_MISSING_DOT;
6099 else if (((dirent->name_len & 0xFF) != 1) ||
6100 (dirent->name[0] != '.'))
6101 problem = PR_2_1ST_NOT_DOT;
6102 else if (dirent->name[1] != '\0')
6103 problem = PR_2_DOT_NULL_TERM;
6104
6105 if (problem) {
6106 if (fix_problem(ctx, problem, pctx)) {
6107 if (dirent->rec_len < 12)
6108 dirent->rec_len = 12;
6109 dirent->inode = ino;
6110 dirent->name_len = 1;
6111 dirent->name[0] = '.';
6112 dirent->name[1] = '\0';
6113 status = 1;
6114 created = 1;
6115 }
6116 }
6117 if (dirent->inode != ino) {
6118 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
6119 dirent->inode = ino;
6120 status = 1;
6121 }
6122 }
6123 if (dirent->rec_len > 12) {
6124 new_len = dirent->rec_len - 12;
6125 if (new_len > 12) {
6126 if (created ||
6127 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
6128 nextdir = (struct ext2_dir_entry *)
6129 ((char *) dirent + 12);
6130 dirent->rec_len = 12;
6131 nextdir->rec_len = new_len;
6132 nextdir->inode = 0;
6133 nextdir->name_len = 0;
6134 status = 1;
6135 }
6136 }
6137 }
6138 return status;
6139}
6140
6141/*
6142 * Make sure the second entry in the directory is '..', and that the
6143 * directory entry is sane. We do not check the inode number of '..'
6144 * here; this gets done in pass 3.
6145 */
6146static int check_dotdot(e2fsck_t ctx,
6147 struct ext2_dir_entry *dirent,
6148 struct dir_info *dir, struct problem_context *pctx)
6149{
6150 int problem = 0;
6151
6152 if (!dirent->inode)
6153 problem = PR_2_MISSING_DOT_DOT;
6154 else if (((dirent->name_len & 0xFF) != 2) ||
6155 (dirent->name[0] != '.') ||
6156 (dirent->name[1] != '.'))
6157 problem = PR_2_2ND_NOT_DOT_DOT;
6158 else if (dirent->name[2] != '\0')
6159 problem = PR_2_DOT_DOT_NULL_TERM;
6160
6161 if (problem) {
6162 if (fix_problem(ctx, problem, pctx)) {
6163 if (dirent->rec_len < 12)
6164 dirent->rec_len = 12;
6165 /*
6166 * Note: we don't have the parent inode just
6167 * yet, so we will fill it in with the root
6168 * inode. This will get fixed in pass 3.
6169 */
6170 dirent->inode = EXT2_ROOT_INO;
6171 dirent->name_len = 2;
6172 dirent->name[0] = '.';
6173 dirent->name[1] = '.';
6174 dirent->name[2] = '\0';
6175 return 1;
6176 }
6177 return 0;
6178 }
6179 dir->dotdot = dirent->inode;
6180 return 0;
6181}
6182
6183/*
6184 * Check to make sure a directory entry doesn't contain any illegal
6185 * characters.
6186 */
6187static int check_name(e2fsck_t ctx,
6188 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006189 struct problem_context *pctx)
6190{
6191 int i;
6192 int fixup = -1;
6193 int ret = 0;
6194
6195 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
6196 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
6197 if (fixup < 0) {
6198 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
6199 }
6200 if (fixup) {
6201 dirent->name[i] = '.';
6202 ret = 1;
6203 }
6204 }
6205 }
6206 return ret;
6207}
6208
6209/*
6210 * Check the directory filetype (if present)
6211 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006212
6213/*
6214 * Given a mode, return the ext2 file type
6215 */
6216static int ext2_file_type(unsigned int mode)
6217{
6218 if (LINUX_S_ISREG(mode))
6219 return EXT2_FT_REG_FILE;
6220
6221 if (LINUX_S_ISDIR(mode))
6222 return EXT2_FT_DIR;
6223
6224 if (LINUX_S_ISCHR(mode))
6225 return EXT2_FT_CHRDEV;
6226
6227 if (LINUX_S_ISBLK(mode))
6228 return EXT2_FT_BLKDEV;
6229
6230 if (LINUX_S_ISLNK(mode))
6231 return EXT2_FT_SYMLINK;
6232
6233 if (LINUX_S_ISFIFO(mode))
6234 return EXT2_FT_FIFO;
6235
6236 if (LINUX_S_ISSOCK(mode))
6237 return EXT2_FT_SOCK;
6238
6239 return 0;
6240}
6241
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006242static _INLINE_ int check_filetype(e2fsck_t ctx,
6243 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006244 struct problem_context *pctx)
6245{
6246 int filetype = dirent->name_len >> 8;
6247 int should_be = EXT2_FT_UNKNOWN;
6248 struct ext2_inode inode;
6249
6250 if (!(ctx->fs->super->s_feature_incompat &
6251 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
6252 if (filetype == 0 ||
6253 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
6254 return 0;
6255 dirent->name_len = dirent->name_len & 0xFF;
6256 return 1;
6257 }
6258
6259 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
6260 should_be = EXT2_FT_DIR;
6261 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
6262 dirent->inode)) {
6263 should_be = EXT2_FT_REG_FILE;
6264 } else if (ctx->inode_bad_map &&
6265 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
6266 dirent->inode))
6267 should_be = 0;
6268 else {
6269 e2fsck_read_inode(ctx, dirent->inode, &inode,
6270 "check_filetype");
6271 should_be = ext2_file_type(inode.i_mode);
6272 }
6273 if (filetype == should_be)
6274 return 0;
6275 pctx->num = should_be;
6276
6277 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
6278 pctx) == 0)
6279 return 0;
6280
6281 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
6282 return 1;
6283}
6284
6285#ifdef ENABLE_HTREE
6286static void parse_int_node(ext2_filsys fs,
6287 struct ext2_db_entry *db,
6288 struct check_dir_struct *cd,
6289 struct dx_dir_info *dx_dir,
6290 char *block_buf)
6291{
6292 struct ext2_dx_root_info *root;
6293 struct ext2_dx_entry *ent;
6294 struct ext2_dx_countlimit *limit;
6295 struct dx_dirblock_info *dx_db;
6296 int i, expect_limit, count;
6297 blk_t blk;
6298 ext2_dirhash_t min_hash = 0xffffffff;
6299 ext2_dirhash_t max_hash = 0;
6300 ext2_dirhash_t hash = 0, prev_hash;
6301
6302 if (db->blockcnt == 0) {
6303 root = (struct ext2_dx_root_info *) (block_buf + 24);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006304 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
6305 } else {
6306 ent = (struct ext2_dx_entry *) (block_buf+8);
6307 }
6308 limit = (struct ext2_dx_countlimit *) ent;
6309
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006310 count = ext2fs_le16_to_cpu(limit->count);
6311 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
6312 sizeof(struct ext2_dx_entry);
6313 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
6314 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
6315 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
6316 goto clear_and_exit;
6317 }
6318 if (count > expect_limit) {
6319 cd->pctx.num = count;
6320 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
6321 goto clear_and_exit;
6322 count = expect_limit;
6323 }
6324
6325 for (i=0; i < count; i++) {
6326 prev_hash = hash;
6327 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006328 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
6329 /* Check to make sure the block is valid */
6330 if (blk > (blk_t) dx_dir->numblocks) {
6331 cd->pctx.blk = blk;
6332 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
6333 &cd->pctx))
6334 goto clear_and_exit;
6335 }
6336 if (hash < prev_hash &&
6337 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
6338 goto clear_and_exit;
6339 dx_db = &dx_dir->dx_block[blk];
6340 if (dx_db->flags & DX_FLAG_REFERENCED) {
6341 dx_db->flags |= DX_FLAG_DUP_REF;
6342 } else {
6343 dx_db->flags |= DX_FLAG_REFERENCED;
6344 dx_db->parent = db->blockcnt;
6345 }
6346 if (hash < min_hash)
6347 min_hash = hash;
6348 if (hash > max_hash)
6349 max_hash = hash;
6350 dx_db->node_min_hash = hash;
6351 if ((i+1) < count)
6352 dx_db->node_max_hash =
6353 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
6354 else {
6355 dx_db->node_max_hash = 0xfffffffe;
6356 dx_db->flags |= DX_FLAG_LAST;
6357 }
6358 if (i == 0)
6359 dx_db->flags |= DX_FLAG_FIRST;
6360 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006361 dx_db = &dx_dir->dx_block[db->blockcnt];
6362 dx_db->min_hash = min_hash;
6363 dx_db->max_hash = max_hash;
6364 return;
6365
6366clear_and_exit:
6367 clear_htree(cd->ctx, cd->pctx.ino);
6368 dx_dir->numblocks = 0;
6369}
6370#endif /* ENABLE_HTREE */
6371
6372/*
6373 * Given a busted directory, try to salvage it somehow.
6374 *
6375 */
6376static void salvage_directory(ext2_filsys fs,
6377 struct ext2_dir_entry *dirent,
6378 struct ext2_dir_entry *prev,
6379 unsigned int *offset)
6380{
6381 char *cp = (char *) dirent;
6382 int left = fs->blocksize - *offset - dirent->rec_len;
6383 int name_len = dirent->name_len & 0xFF;
6384
6385 /*
6386 * Special case of directory entry of size 8: copy what's left
6387 * of the directory block up to cover up the invalid hole.
6388 */
6389 if ((left >= 12) && (dirent->rec_len == 8)) {
6390 memmove(cp, cp+8, left);
6391 memset(cp + left, 0, 8);
6392 return;
6393 }
6394 /*
6395 * If the directory entry overruns the end of the directory
6396 * block, and the name is small enough to fit, then adjust the
6397 * record length.
6398 */
6399 if ((left < 0) &&
6400 (name_len + 8 <= dirent->rec_len + left) &&
6401 dirent->inode <= fs->super->s_inodes_count &&
6402 strnlen(dirent->name, name_len) == name_len) {
6403 dirent->rec_len += left;
6404 return;
6405 }
6406 /*
6407 * If the directory entry is a multiple of four, so it is
6408 * valid, let the previous directory entry absorb the invalid
6409 * one.
6410 */
6411 if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
6412 prev->rec_len += dirent->rec_len;
6413 *offset += dirent->rec_len;
6414 return;
6415 }
6416 /*
6417 * Default salvage method --- kill all of the directory
6418 * entries for the rest of the block. We will either try to
6419 * absorb it into the previous directory entry, or create a
6420 * new empty directory entry the rest of the directory block.
6421 */
6422 if (prev) {
6423 prev->rec_len += fs->blocksize - *offset;
6424 *offset = fs->blocksize;
6425 } else {
6426 dirent->rec_len = fs->blocksize - *offset;
6427 dirent->name_len = 0;
6428 dirent->inode = 0;
6429 }
6430}
6431
6432static int check_dir_block(ext2_filsys fs,
6433 struct ext2_db_entry *db,
6434 void *priv_data)
6435{
6436 struct dir_info *subdir, *dir;
6437 struct dx_dir_info *dx_dir;
6438#ifdef ENABLE_HTREE
6439 struct dx_dirblock_info *dx_db = 0;
6440#endif /* ENABLE_HTREE */
6441 struct ext2_dir_entry *dirent, *prev;
6442 ext2_dirhash_t hash;
6443 unsigned int offset = 0;
6444 int dir_modified = 0;
6445 int dot_state;
6446 blk_t block_nr = db->blk;
6447 ext2_ino_t ino = db->ino;
6448 __u16 links;
6449 struct check_dir_struct *cd;
6450 char *buf;
6451 e2fsck_t ctx;
6452 int problem;
6453 struct ext2_dx_root_info *root;
6454 struct ext2_dx_countlimit *limit;
6455 static dict_t de_dict;
6456 struct problem_context pctx;
6457 int dups_found = 0;
6458
6459 cd = (struct check_dir_struct *) priv_data;
6460 buf = cd->buf;
6461 ctx = cd->ctx;
6462
6463 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6464 return DIRENT_ABORT;
6465
6466 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
6467 return DIRENT_ABORT;
6468
6469 /*
6470 * Make sure the inode is still in use (could have been
6471 * deleted in the duplicate/bad blocks pass.
6472 */
6473 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
6474 return 0;
6475
6476 cd->pctx.ino = ino;
6477 cd->pctx.blk = block_nr;
6478 cd->pctx.blkcount = db->blockcnt;
6479 cd->pctx.ino2 = 0;
6480 cd->pctx.dirent = 0;
6481 cd->pctx.num = 0;
6482
6483 if (db->blk == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006484 if (allocate_dir_block(ctx, db, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006485 return 0;
6486 block_nr = db->blk;
6487 }
6488
6489 if (db->blockcnt)
6490 dot_state = 2;
6491 else
6492 dot_state = 0;
6493
6494 if (ctx->dirs_to_hash &&
6495 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
6496 dups_found++;
6497
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006498 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
6499 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
6500 cd->pctx.errcode = 0; /* We'll handle this ourselves */
6501 if (cd->pctx.errcode) {
6502 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
6503 ctx->flags |= E2F_FLAG_ABORT;
6504 return DIRENT_ABORT;
6505 }
6506 memset(buf, 0, fs->blocksize);
6507 }
6508#ifdef ENABLE_HTREE
6509 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
6510 if (dx_dir && dx_dir->numblocks) {
6511 if (db->blockcnt >= dx_dir->numblocks) {
6512 printf("XXX should never happen!!!\n");
6513 abort();
6514 }
6515 dx_db = &dx_dir->dx_block[db->blockcnt];
6516 dx_db->type = DX_DIRBLOCK_LEAF;
6517 dx_db->phys = block_nr;
6518 dx_db->min_hash = ~0;
6519 dx_db->max_hash = 0;
6520
6521 dirent = (struct ext2_dir_entry *) buf;
6522 limit = (struct ext2_dx_countlimit *) (buf+8);
6523 if (db->blockcnt == 0) {
6524 root = (struct ext2_dx_root_info *) (buf + 24);
6525 dx_db->type = DX_DIRBLOCK_ROOT;
6526 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
6527 if ((root->reserved_zero ||
6528 root->info_length < 8 ||
6529 root->indirect_levels > 1) &&
6530 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
6531 clear_htree(ctx, ino);
6532 dx_dir->numblocks = 0;
6533 dx_db = 0;
6534 }
6535 dx_dir->hashversion = root->hash_version;
6536 dx_dir->depth = root->indirect_levels + 1;
6537 } else if ((dirent->inode == 0) &&
6538 (dirent->rec_len == fs->blocksize) &&
6539 (dirent->name_len == 0) &&
6540 (ext2fs_le16_to_cpu(limit->limit) ==
6541 ((fs->blocksize-8) /
6542 sizeof(struct ext2_dx_entry))))
6543 dx_db->type = DX_DIRBLOCK_NODE;
6544 }
6545#endif /* ENABLE_HTREE */
6546
6547 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
6548 prev = 0;
6549 do {
6550 problem = 0;
6551 dirent = (struct ext2_dir_entry *) (buf + offset);
6552 cd->pctx.dirent = dirent;
6553 cd->pctx.num = offset;
6554 if (((offset + dirent->rec_len) > fs->blocksize) ||
6555 (dirent->rec_len < 12) ||
6556 ((dirent->rec_len % 4) != 0) ||
6557 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
6558 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
6559 salvage_directory(fs, dirent, prev, &offset);
6560 dir_modified++;
6561 continue;
6562 } else
6563 goto abort_free_dict;
6564 }
6565 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
6566 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
6567 dirent->name_len = EXT2_NAME_LEN;
6568 dir_modified++;
6569 }
6570 }
6571
6572 if (dot_state == 0) {
6573 if (check_dot(ctx, dirent, ino, &cd->pctx))
6574 dir_modified++;
6575 } else if (dot_state == 1) {
6576 dir = e2fsck_get_dir_info(ctx, ino);
6577 if (!dir) {
6578 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
6579 goto abort_free_dict;
6580 }
6581 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
6582 dir_modified++;
6583 } else if (dirent->inode == ino) {
6584 problem = PR_2_LINK_DOT;
6585 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
6586 dirent->inode = 0;
6587 dir_modified++;
6588 goto next;
6589 }
6590 }
6591 if (!dirent->inode)
6592 goto next;
6593
6594 /*
6595 * Make sure the inode listed is a legal one.
6596 */
6597 if (((dirent->inode != EXT2_ROOT_INO) &&
6598 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
6599 (dirent->inode > fs->super->s_inodes_count)) {
6600 problem = PR_2_BAD_INO;
6601 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
6602 dirent->inode))) {
6603 /*
6604 * If the inode is unused, offer to clear it.
6605 */
6606 problem = PR_2_UNUSED_INODE;
6607 } else if (ctx->inode_bb_map &&
6608 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
6609 dirent->inode))) {
6610 /*
6611 * If the inode is in a bad block, offer to
6612 * clear it.
6613 */
6614 problem = PR_2_BB_INODE;
6615 } else if ((dot_state > 1) &&
6616 ((dirent->name_len & 0xFF) == 1) &&
6617 (dirent->name[0] == '.')) {
6618 /*
6619 * If there's a '.' entry in anything other
6620 * than the first directory entry, it's a
6621 * duplicate entry that should be removed.
6622 */
6623 problem = PR_2_DUP_DOT;
6624 } else if ((dot_state > 1) &&
6625 ((dirent->name_len & 0xFF) == 2) &&
6626 (dirent->name[0] == '.') &&
6627 (dirent->name[1] == '.')) {
6628 /*
6629 * If there's a '..' entry in anything other
6630 * than the second directory entry, it's a
6631 * duplicate entry that should be removed.
6632 */
6633 problem = PR_2_DUP_DOT_DOT;
6634 } else if ((dot_state > 1) &&
6635 (dirent->inode == EXT2_ROOT_INO)) {
6636 /*
6637 * Don't allow links to the root directory.
6638 * We check this specially to make sure we
6639 * catch this error case even if the root
6640 * directory hasn't been created yet.
6641 */
6642 problem = PR_2_LINK_ROOT;
6643 } else if ((dot_state > 1) &&
6644 (dirent->name_len & 0xFF) == 0) {
6645 /*
6646 * Don't allow zero-length directory names.
6647 */
6648 problem = PR_2_NULL_NAME;
6649 }
6650
6651 if (problem) {
6652 if (fix_problem(ctx, problem, &cd->pctx)) {
6653 dirent->inode = 0;
6654 dir_modified++;
6655 goto next;
6656 } else {
6657 ext2fs_unmark_valid(fs);
6658 if (problem == PR_2_BAD_INO)
6659 goto next;
6660 }
6661 }
6662
6663 /*
6664 * If the inode was marked as having bad fields in
6665 * pass1, process it and offer to fix/clear it.
6666 * (We wait until now so that we can display the
6667 * pathname to the user.)
6668 */
6669 if (ctx->inode_bad_map &&
6670 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
6671 dirent->inode)) {
6672 if (e2fsck_process_bad_inode(ctx, ino,
6673 dirent->inode,
6674 buf + fs->blocksize)) {
6675 dirent->inode = 0;
6676 dir_modified++;
6677 goto next;
6678 }
6679 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6680 return DIRENT_ABORT;
6681 }
6682
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006683 if (check_name(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006684 dir_modified++;
6685
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006686 if (check_filetype(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006687 dir_modified++;
6688
6689#ifdef ENABLE_HTREE
6690 if (dx_db) {
6691 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
6692 (dirent->name_len & 0xFF),
6693 fs->super->s_hash_seed, &hash, 0);
6694 if (hash < dx_db->min_hash)
6695 dx_db->min_hash = hash;
6696 if (hash > dx_db->max_hash)
6697 dx_db->max_hash = hash;
6698 }
6699#endif
6700
6701 /*
6702 * If this is a directory, then mark its parent in its
6703 * dir_info structure. If the parent field is already
6704 * filled in, then this directory has more than one
6705 * hard link. We assume the first link is correct,
6706 * and ask the user if he/she wants to clear this one.
6707 */
6708 if ((dot_state > 1) &&
6709 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
6710 dirent->inode))) {
6711 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
6712 if (!subdir) {
6713 cd->pctx.ino = dirent->inode;
6714 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
6715 goto abort_free_dict;
6716 }
6717 if (subdir->parent) {
6718 cd->pctx.ino2 = subdir->parent;
6719 if (fix_problem(ctx, PR_2_LINK_DIR,
6720 &cd->pctx)) {
6721 dirent->inode = 0;
6722 dir_modified++;
6723 goto next;
6724 }
6725 cd->pctx.ino2 = 0;
6726 } else
6727 subdir->parent = ino;
6728 }
6729
6730 if (dups_found) {
6731 ;
6732 } else if (dict_lookup(&de_dict, dirent)) {
6733 clear_problem_context(&pctx);
6734 pctx.ino = ino;
6735 pctx.dirent = dirent;
6736 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
6737 if (!ctx->dirs_to_hash)
6738 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
6739 if (ctx->dirs_to_hash)
6740 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
6741 dups_found++;
6742 } else
6743 dict_alloc_insert(&de_dict, dirent, dirent);
6744
6745 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
6746 &links);
6747 if (links > 1)
6748 ctx->fs_links_count++;
6749 ctx->fs_total_count++;
6750 next:
6751 prev = dirent;
6752 offset += dirent->rec_len;
6753 dot_state++;
6754 } while (offset < fs->blocksize);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006755#ifdef ENABLE_HTREE
6756 if (dx_db) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006757 cd->pctx.dir = cd->pctx.ino;
6758 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
6759 (dx_db->type == DX_DIRBLOCK_NODE))
6760 parse_int_node(fs, db, cd, dx_dir, buf);
6761 }
6762#endif /* ENABLE_HTREE */
6763 if (offset != fs->blocksize) {
6764 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
6765 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
6766 dirent->rec_len = cd->pctx.num;
6767 dir_modified++;
6768 }
6769 }
6770 if (dir_modified) {
6771 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
6772 if (cd->pctx.errcode) {
6773 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
6774 &cd->pctx))
6775 goto abort_free_dict;
6776 }
6777 ext2fs_mark_changed(fs);
6778 }
6779 dict_free_nodes(&de_dict);
6780 return 0;
6781abort_free_dict:
6782 dict_free_nodes(&de_dict);
6783 ctx->flags |= E2F_FLAG_ABORT;
6784 return DIRENT_ABORT;
6785}
6786
6787/*
6788 * This function is called to deallocate a block, and is an interator
6789 * functioned called by deallocate inode via ext2fs_iterate_block().
6790 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006791static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006792 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
6793 blk_t ref_block FSCK_ATTR((unused)),
6794 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006795 void *priv_data)
6796{
6797 e2fsck_t ctx = (e2fsck_t) priv_data;
6798
6799 if (HOLE_BLKADDR(*block_nr))
6800 return 0;
6801 if ((*block_nr < fs->super->s_first_data_block) ||
6802 (*block_nr >= fs->super->s_blocks_count))
6803 return 0;
6804 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
6805 ext2fs_block_alloc_stats(fs, *block_nr, -1);
6806 return 0;
6807}
6808
6809/*
6810 * This fuction deallocates an inode
6811 */
6812static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
6813{
6814 ext2_filsys fs = ctx->fs;
6815 struct ext2_inode inode;
6816 struct problem_context pctx;
6817 __u32 count;
6818
6819 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
6820 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
6821 inode.i_links_count = 0;
6822 inode.i_dtime = time(0);
6823 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
6824 clear_problem_context(&pctx);
6825 pctx.ino = ino;
6826
6827 /*
6828 * Fix up the bitmaps...
6829 */
6830 e2fsck_read_bitmaps(ctx);
6831 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
6832 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
6833 if (ctx->inode_bad_map)
6834 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
6835 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
6836
6837 if (inode.i_file_acl &&
6838 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
6839 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
6840 block_buf, -1, &count);
6841 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
6842 pctx.errcode = 0;
6843 count = 1;
6844 }
6845 if (pctx.errcode) {
6846 pctx.blk = inode.i_file_acl;
6847 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
6848 ctx->flags |= E2F_FLAG_ABORT;
6849 return;
6850 }
6851 if (count == 0) {
6852 ext2fs_unmark_block_bitmap(ctx->block_found_map,
6853 inode.i_file_acl);
6854 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
6855 }
6856 inode.i_file_acl = 0;
6857 }
6858
6859 if (!ext2fs_inode_has_valid_blocks(&inode))
6860 return;
6861
6862 if (LINUX_S_ISREG(inode.i_mode) &&
6863 (inode.i_size_high || inode.i_size & 0x80000000UL))
6864 ctx->large_files--;
6865
6866 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
6867 deallocate_inode_block, ctx);
6868 if (pctx.errcode) {
6869 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
6870 ctx->flags |= E2F_FLAG_ABORT;
6871 return;
6872 }
6873}
6874
6875/*
6876 * This fuction clears the htree flag on an inode
6877 */
6878static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
6879{
6880 struct ext2_inode inode;
6881
6882 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
6883 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
6884 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
6885 if (ctx->dirs_to_hash)
6886 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
6887}
6888
6889
6890static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
6891 ext2_ino_t ino, char *buf)
6892{
6893 ext2_filsys fs = ctx->fs;
6894 struct ext2_inode inode;
6895 int inode_modified = 0;
6896 int not_fixed = 0;
6897 unsigned char *frag, *fsize;
6898 struct problem_context pctx;
6899 int problem = 0;
6900
6901 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
6902
6903 clear_problem_context(&pctx);
6904 pctx.ino = ino;
6905 pctx.dir = dir;
6906 pctx.inode = &inode;
6907
6908 if (inode.i_file_acl &&
6909 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
6910 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
6911 inode.i_file_acl = 0;
6912#ifdef EXT2FS_ENABLE_SWAPFS
6913 /*
6914 * This is a special kludge to deal with long symlinks
6915 * on big endian systems. i_blocks had already been
6916 * decremented earlier in pass 1, but since i_file_acl
6917 * hadn't yet been cleared, ext2fs_read_inode()
6918 * assumed that the file was short symlink and would
6919 * not have byte swapped i_block[0]. Hence, we have
6920 * to byte-swap it here.
6921 */
6922 if (LINUX_S_ISLNK(inode.i_mode) &&
6923 (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
6924 (inode.i_blocks == fs->blocksize >> 9))
6925 inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
6926#endif
6927 inode_modified++;
6928 } else
6929 not_fixed++;
6930
6931 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
6932 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
6933 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
6934 !(LINUX_S_ISSOCK(inode.i_mode)))
6935 problem = PR_2_BAD_MODE;
6936 else if (LINUX_S_ISCHR(inode.i_mode)
6937 && !e2fsck_pass1_check_device_inode(fs, &inode))
6938 problem = PR_2_BAD_CHAR_DEV;
6939 else if (LINUX_S_ISBLK(inode.i_mode)
6940 && !e2fsck_pass1_check_device_inode(fs, &inode))
6941 problem = PR_2_BAD_BLOCK_DEV;
6942 else if (LINUX_S_ISFIFO(inode.i_mode)
6943 && !e2fsck_pass1_check_device_inode(fs, &inode))
6944 problem = PR_2_BAD_FIFO;
6945 else if (LINUX_S_ISSOCK(inode.i_mode)
6946 && !e2fsck_pass1_check_device_inode(fs, &inode))
6947 problem = PR_2_BAD_SOCKET;
6948 else if (LINUX_S_ISLNK(inode.i_mode)
6949 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
6950 problem = PR_2_INVALID_SYMLINK;
6951 }
6952
6953 if (problem) {
6954 if (fix_problem(ctx, problem, &pctx)) {
6955 deallocate_inode(ctx, ino, 0);
6956 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6957 return 0;
6958 return 1;
6959 } else
6960 not_fixed++;
6961 problem = 0;
6962 }
6963
6964 if (inode.i_faddr) {
6965 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
6966 inode.i_faddr = 0;
6967 inode_modified++;
6968 } else
6969 not_fixed++;
6970 }
6971
6972 switch (fs->super->s_creator_os) {
6973 case EXT2_OS_LINUX:
6974 frag = &inode.osd2.linux2.l_i_frag;
6975 fsize = &inode.osd2.linux2.l_i_fsize;
6976 break;
6977 case EXT2_OS_HURD:
6978 frag = &inode.osd2.hurd2.h_i_frag;
6979 fsize = &inode.osd2.hurd2.h_i_fsize;
6980 break;
6981 case EXT2_OS_MASIX:
6982 frag = &inode.osd2.masix2.m_i_frag;
6983 fsize = &inode.osd2.masix2.m_i_fsize;
6984 break;
6985 default:
6986 frag = fsize = 0;
6987 }
6988 if (frag && *frag) {
6989 pctx.num = *frag;
6990 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
6991 *frag = 0;
6992 inode_modified++;
6993 } else
6994 not_fixed++;
6995 pctx.num = 0;
6996 }
6997 if (fsize && *fsize) {
6998 pctx.num = *fsize;
6999 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
7000 *fsize = 0;
7001 inode_modified++;
7002 } else
7003 not_fixed++;
7004 pctx.num = 0;
7005 }
7006
7007 if (inode.i_file_acl &&
7008 ((inode.i_file_acl < fs->super->s_first_data_block) ||
7009 (inode.i_file_acl >= fs->super->s_blocks_count))) {
7010 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
7011 inode.i_file_acl = 0;
7012 inode_modified++;
7013 } else
7014 not_fixed++;
7015 }
7016 if (inode.i_dir_acl &&
7017 LINUX_S_ISDIR(inode.i_mode)) {
7018 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
7019 inode.i_dir_acl = 0;
7020 inode_modified++;
7021 } else
7022 not_fixed++;
7023 }
7024
7025 if (inode_modified)
7026 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
7027 if (!not_fixed)
7028 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
7029 return 0;
7030}
7031
7032
7033/*
7034 * allocate_dir_block --- this function allocates a new directory
7035 * block for a particular inode; this is done if a directory has
7036 * a "hole" in it, or if a directory has a illegal block number
7037 * that was zeroed out and now needs to be replaced.
7038 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007039static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007040 struct problem_context *pctx)
7041{
7042 ext2_filsys fs = ctx->fs;
7043 blk_t blk;
7044 char *block;
7045 struct ext2_inode inode;
7046
7047 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
7048 return 1;
7049
7050 /*
7051 * Read the inode and block bitmaps in; we'll be messing with
7052 * them.
7053 */
7054 e2fsck_read_bitmaps(ctx);
7055
7056 /*
7057 * First, find a free block
7058 */
7059 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
7060 if (pctx->errcode) {
7061 pctx->str = "ext2fs_new_block";
7062 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
7063 return 1;
7064 }
7065 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
7066 ext2fs_mark_block_bitmap(fs->block_map, blk);
7067 ext2fs_mark_bb_dirty(fs);
7068
7069 /*
7070 * Now let's create the actual data block for the inode
7071 */
7072 if (db->blockcnt)
7073 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
7074 else
7075 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
7076 EXT2_ROOT_INO, &block);
7077
7078 if (pctx->errcode) {
7079 pctx->str = "ext2fs_new_dir_block";
7080 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
7081 return 1;
7082 }
7083
7084 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
7085 ext2fs_free_mem(&block);
7086 if (pctx->errcode) {
7087 pctx->str = "ext2fs_write_dir_block";
7088 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
7089 return 1;
7090 }
7091
7092 /*
7093 * Update the inode block count
7094 */
7095 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
7096 inode.i_blocks += fs->blocksize / 512;
7097 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
7098 inode.i_size = (db->blockcnt+1) * fs->blocksize;
7099 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
7100
7101 /*
7102 * Finally, update the block pointers for the inode
7103 */
7104 db->blk = blk;
7105 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
7106 0, update_dir_block, db);
7107 if (pctx->errcode) {
7108 pctx->str = "ext2fs_block_iterate";
7109 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
7110 return 1;
7111 }
7112
7113 return 0;
7114}
7115
7116/*
7117 * This is a helper function for allocate_dir_block().
7118 */
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00007119static int update_dir_block(ext2_filsys fs FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007120 blk_t *block_nr,
7121 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00007122 blk_t ref_block FSCK_ATTR((unused)),
7123 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007124 void *priv_data)
7125{
7126 struct ext2_db_entry *db;
7127
7128 db = (struct ext2_db_entry *) priv_data;
7129 if (db->blockcnt == (int) blockcnt) {
7130 *block_nr = db->blk;
7131 return BLOCK_CHANGED;
7132 }
7133 return 0;
7134}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007135
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007136/*
7137 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
7138 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007139 * Pass #3 assures that all directories are connected to the
7140 * filesystem tree, using the following algorithm:
7141 *
7142 * First, the root directory is checked to make sure it exists; if
7143 * not, e2fsck will offer to create a new one. It is then marked as
7144 * "done".
7145 *
7146 * Then, pass3 interates over all directory inodes; for each directory
7147 * it attempts to trace up the filesystem tree, using dirinfo.parent
7148 * until it reaches a directory which has been marked "done". If it
7149 * can not do so, then the directory must be disconnected, and e2fsck
7150 * will offer to reconnect it to /lost+found. While it is chasing
7151 * parent pointers up the filesystem tree, if pass3 sees a directory
7152 * twice, then it has detected a filesystem loop, and it will again
7153 * offer to reconnect the directory to /lost+found in to break the
7154 * filesystem loop.
7155 *
7156 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
7157 * reconnect inodes to /lost+found; this subroutine is also used by
7158 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
7159 * is responsible for creating /lost+found if it does not exist.
7160 *
7161 * Pass 3 frees the following data structures:
7162 * - The dirinfo directory information cache.
7163 */
7164
7165static void check_root(e2fsck_t ctx);
7166static int check_directory(e2fsck_t ctx, struct dir_info *dir,
7167 struct problem_context *pctx);
7168static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
7169
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007170static ext2fs_inode_bitmap inode_loop_detect;
7171static ext2fs_inode_bitmap inode_done_map;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007172
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007173static void e2fsck_pass3(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007174{
7175 ext2_filsys fs = ctx->fs;
7176 int i;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007177 struct problem_context pctx;
7178 struct dir_info *dir;
7179 unsigned long maxdirs, count;
7180
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007181 clear_problem_context(&pctx);
7182
Rob Landley3e72c592006-04-06 22:49:04 +00007183 /* Pass 3 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007184
7185 if (!(ctx->options & E2F_OPT_PREEN))
7186 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
7187
7188 /*
7189 * Allocate some bitmaps to do loop detection.
7190 */
7191 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
7192 &inode_done_map);
7193 if (pctx.errcode) {
7194 pctx.num = 2;
7195 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
7196 ctx->flags |= E2F_FLAG_ABORT;
7197 goto abort_exit;
7198 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007199 check_root(ctx);
7200 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7201 goto abort_exit;
7202
7203 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
7204
7205 maxdirs = e2fsck_get_num_dirinfo(ctx);
7206 count = 1;
7207
7208 if (ctx->progress)
7209 if ((ctx->progress)(ctx, 3, 0, maxdirs))
7210 goto abort_exit;
7211
7212 for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
7213 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7214 goto abort_exit;
7215 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
7216 goto abort_exit;
7217 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
7218 if (check_directory(ctx, dir, &pctx))
7219 goto abort_exit;
7220 }
7221
7222 /*
7223 * Force the creation of /lost+found if not present
7224 */
7225 if ((ctx->flags & E2F_OPT_READONLY) == 0)
7226 e2fsck_get_lost_and_found(ctx, 1);
7227
7228 /*
7229 * If there are any directories that need to be indexed or
7230 * optimized, do it here.
7231 */
7232 e2fsck_rehash_directories(ctx);
7233
7234abort_exit:
7235 e2fsck_free_dir_info(ctx);
Rob Landleye7c43b62006-03-01 16:39:45 +00007236 ext2fs_free_inode_bitmap(inode_loop_detect);
7237 inode_loop_detect = 0;
7238 ext2fs_free_inode_bitmap(inode_done_map);
7239 inode_done_map = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007240}
7241
7242/*
7243 * This makes sure the root inode is present; if not, we ask if the
7244 * user wants us to create it. Not creating it is a fatal error.
7245 */
7246static void check_root(e2fsck_t ctx)
7247{
7248 ext2_filsys fs = ctx->fs;
7249 blk_t blk;
7250 struct ext2_inode inode;
7251 char * block;
7252 struct problem_context pctx;
7253
7254 clear_problem_context(&pctx);
7255
7256 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
7257 /*
7258 * If the root inode is not a directory, die here. The
7259 * user must have answered 'no' in pass1 when we
7260 * offered to clear it.
7261 */
7262 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
7263 EXT2_ROOT_INO))) {
7264 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
7265 ctx->flags |= E2F_FLAG_ABORT;
7266 }
7267 return;
7268 }
7269
7270 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
7271 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
7272 ctx->flags |= E2F_FLAG_ABORT;
7273 return;
7274 }
7275
7276 e2fsck_read_bitmaps(ctx);
7277
7278 /*
7279 * First, find a free block
7280 */
7281 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
7282 if (pctx.errcode) {
7283 pctx.str = "ext2fs_new_block";
7284 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
7285 ctx->flags |= E2F_FLAG_ABORT;
7286 return;
7287 }
7288 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
7289 ext2fs_mark_block_bitmap(fs->block_map, blk);
7290 ext2fs_mark_bb_dirty(fs);
7291
7292 /*
7293 * Now let's create the actual data block for the inode
7294 */
7295 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
7296 &block);
7297 if (pctx.errcode) {
7298 pctx.str = "ext2fs_new_dir_block";
7299 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
7300 ctx->flags |= E2F_FLAG_ABORT;
7301 return;
7302 }
7303
7304 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
7305 if (pctx.errcode) {
7306 pctx.str = "ext2fs_write_dir_block";
7307 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
7308 ctx->flags |= E2F_FLAG_ABORT;
7309 return;
7310 }
7311 ext2fs_free_mem(&block);
7312
7313 /*
7314 * Set up the inode structure
7315 */
7316 memset(&inode, 0, sizeof(inode));
7317 inode.i_mode = 040755;
7318 inode.i_size = fs->blocksize;
7319 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
7320 inode.i_links_count = 2;
7321 inode.i_blocks = fs->blocksize / 512;
7322 inode.i_block[0] = blk;
7323
7324 /*
7325 * Write out the inode.
7326 */
7327 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
7328 if (pctx.errcode) {
7329 pctx.str = "ext2fs_write_inode";
7330 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
7331 ctx->flags |= E2F_FLAG_ABORT;
7332 return;
7333 }
7334
7335 /*
7336 * Miscellaneous bookkeeping...
7337 */
7338 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
7339 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
7340 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
7341
7342 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
7343 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
7344 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
7345 ext2fs_mark_ib_dirty(fs);
7346}
7347
7348/*
7349 * This subroutine is responsible for making sure that a particular
7350 * directory is connected to the root; if it isn't we trace it up as
7351 * far as we can go, and then offer to connect the resulting parent to
7352 * the lost+found. We have to do loop detection; if we ever discover
7353 * a loop, we treat that as a disconnected directory and offer to
7354 * reparent it to lost+found.
7355 *
7356 * However, loop detection is expensive, because for very large
7357 * filesystems, the inode_loop_detect bitmap is huge, and clearing it
7358 * is non-trivial. Loops in filesystems are also a rare error case,
7359 * and we shouldn't optimize for error cases. So we try two passes of
7360 * the algorithm. The first time, we ignore loop detection and merely
7361 * increment a counter; if the counter exceeds some extreme threshold,
7362 * then we try again with the loop detection bitmap enabled.
7363 */
7364static int check_directory(e2fsck_t ctx, struct dir_info *dir,
7365 struct problem_context *pctx)
7366{
7367 ext2_filsys fs = ctx->fs;
7368 struct dir_info *p = dir;
7369 int loop_pass = 0, parent_count = 0;
7370
7371 if (!p)
7372 return 0;
7373
7374 while (1) {
7375 /*
7376 * Mark this inode as being "done"; by the time we
7377 * return from this function, the inode we either be
7378 * verified as being connected to the directory tree,
7379 * or we will have offered to reconnect this to
7380 * lost+found.
7381 *
7382 * If it was marked done already, then we've reached a
7383 * parent we've already checked.
7384 */
7385 if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
7386 break;
7387
7388 /*
7389 * If this directory doesn't have a parent, or we've
7390 * seen the parent once already, then offer to
7391 * reparent it to lost+found
7392 */
7393 if (!p->parent ||
7394 (loop_pass &&
7395 (ext2fs_test_inode_bitmap(inode_loop_detect,
7396 p->parent)))) {
7397 pctx->ino = p->ino;
7398 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
7399 if (e2fsck_reconnect_file(ctx, pctx->ino))
7400 ext2fs_unmark_valid(fs);
7401 else {
7402 p = e2fsck_get_dir_info(ctx, pctx->ino);
7403 p->parent = ctx->lost_and_found;
7404 fix_dotdot(ctx, p, ctx->lost_and_found);
7405 }
7406 }
7407 break;
7408 }
7409 p = e2fsck_get_dir_info(ctx, p->parent);
7410 if (!p) {
7411 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
7412 return 0;
7413 }
7414 if (loop_pass) {
7415 ext2fs_mark_inode_bitmap(inode_loop_detect,
7416 p->ino);
7417 } else if (parent_count++ > 2048) {
7418 /*
7419 * If we've run into a path depth that's
7420 * greater than 2048, try again with the inode
7421 * loop bitmap turned on and start from the
7422 * top.
7423 */
7424 loop_pass = 1;
7425 if (inode_loop_detect)
7426 ext2fs_clear_inode_bitmap(inode_loop_detect);
7427 else {
7428 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
7429 if (pctx->errcode) {
7430 pctx->num = 1;
7431 fix_problem(ctx,
7432 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
7433 ctx->flags |= E2F_FLAG_ABORT;
7434 return -1;
7435 }
7436 }
7437 p = dir;
7438 }
7439 }
7440
7441 /*
7442 * Make sure that .. and the parent directory are the same;
7443 * offer to fix it if not.
7444 */
7445 if (dir->parent != dir->dotdot) {
7446 pctx->ino = dir->ino;
7447 pctx->ino2 = dir->dotdot;
7448 pctx->dir = dir->parent;
7449 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
7450 fix_dotdot(ctx, dir, dir->parent);
7451 }
7452 return 0;
7453}
7454
7455/*
7456 * This routine gets the lost_and_found inode, making it a directory
7457 * if necessary
7458 */
7459ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
7460{
7461 ext2_filsys fs = ctx->fs;
7462 ext2_ino_t ino;
7463 blk_t blk;
7464 errcode_t retval;
7465 struct ext2_inode inode;
7466 char * block;
7467 static const char name[] = "lost+found";
7468 struct problem_context pctx;
7469 struct dir_info *dirinfo;
7470
7471 if (ctx->lost_and_found)
7472 return ctx->lost_and_found;
7473
7474 clear_problem_context(&pctx);
7475
7476 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
7477 sizeof(name)-1, 0, &ino);
7478 if (retval && !fix)
7479 return 0;
7480 if (!retval) {
7481 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
7482 ctx->lost_and_found = ino;
7483 return ino;
7484 }
7485
7486 /* Lost+found isn't a directory! */
7487 if (!fix)
7488 return 0;
7489 pctx.ino = ino;
7490 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
7491 return 0;
7492
7493 /* OK, unlink the old /lost+found file. */
7494 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
7495 if (pctx.errcode) {
7496 pctx.str = "ext2fs_unlink";
7497 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
7498 return 0;
7499 }
7500 dirinfo = e2fsck_get_dir_info(ctx, ino);
7501 if (dirinfo)
7502 dirinfo->parent = 0;
7503 e2fsck_adjust_inode_count(ctx, ino, -1);
7504 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
7505 pctx.errcode = retval;
7506 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
7507 }
7508 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
7509 return 0;
7510
7511 /*
7512 * Read the inode and block bitmaps in; we'll be messing with
7513 * them.
7514 */
7515 e2fsck_read_bitmaps(ctx);
7516
7517 /*
7518 * First, find a free block
7519 */
7520 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
7521 if (retval) {
7522 pctx.errcode = retval;
7523 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
7524 return 0;
7525 }
7526 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
7527 ext2fs_block_alloc_stats(fs, blk, +1);
7528
7529 /*
7530 * Next find a free inode.
7531 */
7532 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
7533 ctx->inode_used_map, &ino);
7534 if (retval) {
7535 pctx.errcode = retval;
7536 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
7537 return 0;
7538 }
7539 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
7540 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
7541 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
7542
7543 /*
7544 * Now let's create the actual data block for the inode
7545 */
7546 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
7547 if (retval) {
7548 pctx.errcode = retval;
7549 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
7550 return 0;
7551 }
7552
7553 retval = ext2fs_write_dir_block(fs, blk, block);
7554 ext2fs_free_mem(&block);
7555 if (retval) {
7556 pctx.errcode = retval;
7557 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
7558 return 0;
7559 }
7560
7561 /*
7562 * Set up the inode structure
7563 */
7564 memset(&inode, 0, sizeof(inode));
7565 inode.i_mode = 040700;
7566 inode.i_size = fs->blocksize;
7567 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
7568 inode.i_links_count = 2;
7569 inode.i_blocks = fs->blocksize / 512;
7570 inode.i_block[0] = blk;
7571
7572 /*
7573 * Next, write out the inode.
7574 */
7575 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
7576 if (pctx.errcode) {
7577 pctx.str = "ext2fs_write_inode";
7578 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
7579 return 0;
7580 }
7581 /*
7582 * Finally, create the directory link
7583 */
7584 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
7585 if (pctx.errcode) {
7586 pctx.str = "ext2fs_link";
7587 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
7588 return 0;
7589 }
7590
7591 /*
7592 * Miscellaneous bookkeeping that needs to be kept straight.
7593 */
7594 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
7595 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
7596 ext2fs_icount_store(ctx->inode_count, ino, 2);
7597 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
7598 ctx->lost_and_found = ino;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007599 return ino;
7600}
7601
7602/*
7603 * This routine will connect a file to lost+found
7604 */
7605int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
7606{
7607 ext2_filsys fs = ctx->fs;
7608 errcode_t retval;
7609 char name[80];
7610 struct problem_context pctx;
7611 struct ext2_inode inode;
7612 int file_type = 0;
7613
7614 clear_problem_context(&pctx);
7615 pctx.ino = ino;
7616
7617 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
7618 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
7619 ctx->bad_lost_and_found++;
7620 }
7621 if (ctx->bad_lost_and_found) {
7622 fix_problem(ctx, PR_3_NO_LPF, &pctx);
7623 return 1;
7624 }
7625
7626 sprintf(name, "#%u", ino);
7627 if (ext2fs_read_inode(fs, ino, &inode) == 0)
7628 file_type = ext2_file_type(inode.i_mode);
7629 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
7630 if (retval == EXT2_ET_DIR_NO_SPACE) {
7631 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
7632 return 1;
7633 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
7634 1, 0);
7635 if (retval) {
7636 pctx.errcode = retval;
7637 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
7638 return 1;
7639 }
7640 retval = ext2fs_link(fs, ctx->lost_and_found, name,
7641 ino, file_type);
7642 }
7643 if (retval) {
7644 pctx.errcode = retval;
7645 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
7646 return 1;
7647 }
7648 e2fsck_adjust_inode_count(ctx, ino, 1);
7649
7650 return 0;
7651}
7652
7653/*
7654 * Utility routine to adjust the inode counts on an inode.
7655 */
7656errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
7657{
7658 ext2_filsys fs = ctx->fs;
7659 errcode_t retval;
7660 struct ext2_inode inode;
7661
7662 if (!ino)
7663 return 0;
7664
7665 retval = ext2fs_read_inode(fs, ino, &inode);
7666 if (retval)
7667 return retval;
7668
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007669 if (adj == 1) {
7670 ext2fs_icount_increment(ctx->inode_count, ino, 0);
7671 if (inode.i_links_count == (__u16) ~0)
7672 return 0;
7673 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
7674 inode.i_links_count++;
7675 } else if (adj == -1) {
7676 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
7677 if (inode.i_links_count == 0)
7678 return 0;
7679 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
7680 inode.i_links_count--;
7681 }
7682
7683 retval = ext2fs_write_inode(fs, ino, &inode);
7684 if (retval)
7685 return retval;
7686
7687 return 0;
7688}
7689
7690/*
7691 * Fix parent --- this routine fixes up the parent of a directory.
7692 */
7693struct fix_dotdot_struct {
7694 ext2_filsys fs;
7695 ext2_ino_t parent;
7696 int done;
7697 e2fsck_t ctx;
7698};
7699
7700static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00007701 int offset FSCK_ATTR((unused)),
7702 int blocksize FSCK_ATTR((unused)),
7703 char *buf FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007704 void *priv_data)
7705{
7706 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
7707 errcode_t retval;
7708 struct problem_context pctx;
7709
7710 if ((dirent->name_len & 0xFF) != 2)
7711 return 0;
7712 if (strncmp(dirent->name, "..", 2))
7713 return 0;
7714
7715 clear_problem_context(&pctx);
7716
7717 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
7718 if (retval) {
7719 pctx.errcode = retval;
7720 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
7721 }
7722 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
7723 if (retval) {
7724 pctx.errcode = retval;
7725 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
7726 }
7727 dirent->inode = fp->parent;
7728
7729 fp->done++;
7730 return DIRENT_ABORT | DIRENT_CHANGED;
7731}
7732
7733static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
7734{
7735 ext2_filsys fs = ctx->fs;
7736 errcode_t retval;
7737 struct fix_dotdot_struct fp;
7738 struct problem_context pctx;
7739
7740 fp.fs = fs;
7741 fp.parent = parent;
7742 fp.done = 0;
7743 fp.ctx = ctx;
7744
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007745 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
7746 0, fix_dotdot_proc, &fp);
7747 if (retval || !fp.done) {
7748 clear_problem_context(&pctx);
7749 pctx.ino = dir->ino;
7750 pctx.errcode = retval;
7751 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
7752 PR_3_FIX_PARENT_NOFIND, &pctx);
7753 ext2fs_unmark_valid(fs);
7754 }
7755 dir->dotdot = parent;
7756
7757 return;
7758}
7759
7760/*
7761 * These routines are responsible for expanding a /lost+found if it is
7762 * too small.
7763 */
7764
7765struct expand_dir_struct {
7766 int num;
7767 int guaranteed_size;
7768 int newblocks;
7769 int last_block;
7770 errcode_t err;
7771 e2fsck_t ctx;
7772};
7773
7774static int expand_dir_proc(ext2_filsys fs,
7775 blk_t *blocknr,
7776 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00007777 blk_t ref_block FSCK_ATTR((unused)),
7778 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007779 void *priv_data)
7780{
7781 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
7782 blk_t new_blk;
7783 static blk_t last_blk = 0;
7784 char *block;
7785 errcode_t retval;
7786 e2fsck_t ctx;
7787
7788 ctx = es->ctx;
7789
7790 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
7791 return BLOCK_ABORT;
7792
7793 if (blockcnt > 0)
7794 es->last_block = blockcnt;
7795 if (*blocknr) {
7796 last_blk = *blocknr;
7797 return 0;
7798 }
7799 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
7800 &new_blk);
7801 if (retval) {
7802 es->err = retval;
7803 return BLOCK_ABORT;
7804 }
7805 if (blockcnt > 0) {
7806 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
7807 if (retval) {
7808 es->err = retval;
7809 return BLOCK_ABORT;
7810 }
7811 es->num--;
7812 retval = ext2fs_write_dir_block(fs, new_blk, block);
7813 } else {
7814 retval = ext2fs_get_mem(fs->blocksize, &block);
7815 if (retval) {
7816 es->err = retval;
7817 return BLOCK_ABORT;
7818 }
7819 memset(block, 0, fs->blocksize);
7820 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
7821 }
7822 if (retval) {
7823 es->err = retval;
7824 return BLOCK_ABORT;
7825 }
7826 ext2fs_free_mem(&block);
7827 *blocknr = new_blk;
7828 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
7829 ext2fs_block_alloc_stats(fs, new_blk, +1);
7830 es->newblocks++;
7831
7832 if (es->num == 0)
7833 return (BLOCK_CHANGED | BLOCK_ABORT);
7834 else
7835 return BLOCK_CHANGED;
7836}
7837
7838errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
7839 int num, int guaranteed_size)
7840{
7841 ext2_filsys fs = ctx->fs;
7842 errcode_t retval;
7843 struct expand_dir_struct es;
7844 struct ext2_inode inode;
7845
7846 if (!(fs->flags & EXT2_FLAG_RW))
7847 return EXT2_ET_RO_FILSYS;
7848
7849 /*
7850 * Read the inode and block bitmaps in; we'll be messing with
7851 * them.
7852 */
7853 e2fsck_read_bitmaps(ctx);
7854
7855 retval = ext2fs_check_directory(fs, dir);
7856 if (retval)
7857 return retval;
7858
7859 es.num = num;
7860 es.guaranteed_size = guaranteed_size;
7861 es.last_block = 0;
7862 es.err = 0;
7863 es.newblocks = 0;
7864 es.ctx = ctx;
7865
7866 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
7867 0, expand_dir_proc, &es);
7868
7869 if (es.err)
7870 return es.err;
7871
7872 /*
7873 * Update the size and block count fields in the inode.
7874 */
7875 retval = ext2fs_read_inode(fs, dir, &inode);
7876 if (retval)
7877 return retval;
7878
7879 inode.i_size = (es.last_block + 1) * fs->blocksize;
7880 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
7881
7882 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
7883
7884 return 0;
7885}
7886
7887/*
7888 * pass4.c -- pass #4 of e2fsck: Check reference counts
7889 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007890 * Pass 4 frees the following data structures:
7891 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
7892 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
7893 */
7894
7895/*
7896 * This routine is called when an inode is not connected to the
7897 * directory tree.
7898 *
7899 * This subroutine returns 1 then the caller shouldn't bother with the
7900 * rest of the pass 4 tests.
7901 */
7902static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
7903{
7904 ext2_filsys fs = ctx->fs;
7905 struct ext2_inode inode;
7906 struct problem_context pctx;
7907
7908 e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
7909 clear_problem_context(&pctx);
7910 pctx.ino = i;
7911 pctx.inode = &inode;
7912
7913 /*
7914 * Offer to delete any zero-length files that does not have
7915 * blocks. If there is an EA block, it might have useful
7916 * information, so we won't prompt to delete it, but let it be
7917 * reconnected to lost+found.
7918 */
7919 if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
7920 LINUX_S_ISDIR(inode.i_mode))) {
7921 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
7922 ext2fs_icount_store(ctx->inode_link_info, i, 0);
7923 inode.i_links_count = 0;
7924 inode.i_dtime = time(0);
7925 e2fsck_write_inode(ctx, i, &inode,
7926 "disconnect_inode");
7927 /*
7928 * Fix up the bitmaps...
7929 */
7930 e2fsck_read_bitmaps(ctx);
7931 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
7932 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
7933 ext2fs_inode_alloc_stats2(fs, i, -1,
7934 LINUX_S_ISDIR(inode.i_mode));
7935 return 0;
7936 }
7937 }
7938
7939 /*
7940 * Prompt to reconnect.
7941 */
7942 if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
7943 if (e2fsck_reconnect_file(ctx, i))
7944 ext2fs_unmark_valid(fs);
7945 } else {
7946 /*
7947 * If we don't attach the inode, then skip the
7948 * i_links_test since there's no point in trying to
7949 * force i_links_count to zero.
7950 */
7951 ext2fs_unmark_valid(fs);
7952 return 1;
7953 }
7954 return 0;
7955}
7956
7957
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007958static void e2fsck_pass4(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007959{
7960 ext2_filsys fs = ctx->fs;
7961 ext2_ino_t i;
7962 struct ext2_inode inode;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007963 struct problem_context pctx;
7964 __u16 link_count, link_counted;
7965 char *buf = 0;
7966 int group, maxgroup;
7967
Rob Landley3e72c592006-04-06 22:49:04 +00007968 /* Pass 4 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007969
7970 clear_problem_context(&pctx);
7971
7972 if (!(ctx->options & E2F_OPT_PREEN))
7973 fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
7974
7975 group = 0;
7976 maxgroup = fs->group_desc_count;
7977 if (ctx->progress)
7978 if ((ctx->progress)(ctx, 4, 0, maxgroup))
7979 return;
7980
7981 for (i=1; i <= fs->super->s_inodes_count; i++) {
7982 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7983 return;
7984 if ((i % fs->super->s_inodes_per_group) == 0) {
7985 group++;
7986 if (ctx->progress)
7987 if ((ctx->progress)(ctx, 4, group, maxgroup))
7988 return;
7989 }
7990 if (i == EXT2_BAD_INO ||
7991 (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
7992 continue;
7993 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
7994 (ctx->inode_imagic_map &&
7995 ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) ||
7996 (ctx->inode_bb_map &&
7997 ext2fs_test_inode_bitmap(ctx->inode_bb_map, i)))
7998 continue;
7999 ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
8000 ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
8001 if (link_counted == 0) {
8002 if (!buf)
8003 buf = e2fsck_allocate_memory(ctx,
8004 fs->blocksize, "bad_inode buffer");
8005 if (e2fsck_process_bad_inode(ctx, 0, i, buf))
8006 continue;
8007 if (disconnect_inode(ctx, i))
8008 continue;
8009 ext2fs_icount_fetch(ctx->inode_link_info, i,
8010 &link_count);
8011 ext2fs_icount_fetch(ctx->inode_count, i,
8012 &link_counted);
8013 }
8014 if (link_counted != link_count) {
8015 e2fsck_read_inode(ctx, i, &inode, "pass4");
8016 pctx.ino = i;
8017 pctx.inode = &inode;
8018 if (link_count != inode.i_links_count) {
8019 pctx.num = link_count;
8020 fix_problem(ctx,
8021 PR_4_INCONSISTENT_COUNT, &pctx);
8022 }
8023 pctx.num = link_counted;
8024 if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
8025 inode.i_links_count = link_counted;
8026 e2fsck_write_inode(ctx, i, &inode, "pass4");
8027 }
8028 }
8029 }
8030 ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
8031 ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
8032 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
8033 ctx->inode_bb_map = 0;
8034 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
8035 ctx->inode_imagic_map = 0;
Rob Landleye7c43b62006-03-01 16:39:45 +00008036 ext2fs_free_mem(&buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008037}
8038
8039/*
8040 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008041 */
8042
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008043#define NO_BLK ((blk_t) -1)
8044
8045static void print_bitmap_problem(e2fsck_t ctx, int problem,
8046 struct problem_context *pctx)
8047{
8048 switch (problem) {
8049 case PR_5_BLOCK_UNUSED:
8050 if (pctx->blk == pctx->blk2)
8051 pctx->blk2 = 0;
8052 else
8053 problem = PR_5_BLOCK_RANGE_UNUSED;
8054 break;
8055 case PR_5_BLOCK_USED:
8056 if (pctx->blk == pctx->blk2)
8057 pctx->blk2 = 0;
8058 else
8059 problem = PR_5_BLOCK_RANGE_USED;
8060 break;
8061 case PR_5_INODE_UNUSED:
8062 if (pctx->ino == pctx->ino2)
8063 pctx->ino2 = 0;
8064 else
8065 problem = PR_5_INODE_RANGE_UNUSED;
8066 break;
8067 case PR_5_INODE_USED:
8068 if (pctx->ino == pctx->ino2)
8069 pctx->ino2 = 0;
8070 else
8071 problem = PR_5_INODE_RANGE_USED;
8072 break;
8073 }
8074 fix_problem(ctx, problem, pctx);
8075 pctx->blk = pctx->blk2 = NO_BLK;
8076 pctx->ino = pctx->ino2 = 0;
8077}
8078
8079static void check_block_bitmaps(e2fsck_t ctx)
8080{
8081 ext2_filsys fs = ctx->fs;
8082 blk_t i;
8083 int *free_array;
8084 int group = 0;
8085 unsigned int blocks = 0;
8086 unsigned int free_blocks = 0;
8087 int group_free = 0;
8088 int actual, bitmap;
8089 struct problem_context pctx;
8090 int problem, save_problem, fixit, had_problem;
8091 errcode_t retval;
8092
8093 clear_problem_context(&pctx);
8094 free_array = (int *) e2fsck_allocate_memory(ctx,
8095 fs->group_desc_count * sizeof(int), "free block count array");
8096
8097 if ((fs->super->s_first_data_block <
8098 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
8099 (fs->super->s_blocks_count-1 >
8100 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
8101 pctx.num = 1;
8102 pctx.blk = fs->super->s_first_data_block;
8103 pctx.blk2 = fs->super->s_blocks_count -1;
8104 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
8105 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
8106 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
8107
8108 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8109 return;
8110 }
8111
8112 if ((fs->super->s_first_data_block <
8113 ext2fs_get_block_bitmap_start(fs->block_map)) ||
8114 (fs->super->s_blocks_count-1 >
8115 ext2fs_get_block_bitmap_end(fs->block_map))) {
8116 pctx.num = 2;
8117 pctx.blk = fs->super->s_first_data_block;
8118 pctx.blk2 = fs->super->s_blocks_count -1;
8119 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
8120 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
8121 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
8122
8123 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8124 return;
8125 }
8126
8127redo_counts:
8128 had_problem = 0;
8129 save_problem = 0;
8130 pctx.blk = pctx.blk2 = NO_BLK;
8131 for (i = fs->super->s_first_data_block;
8132 i < fs->super->s_blocks_count;
8133 i++) {
8134 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
8135 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
8136
8137 if (actual == bitmap)
8138 goto do_counts;
8139
8140 if (!actual && bitmap) {
8141 /*
8142 * Block not used, but marked in use in the bitmap.
8143 */
8144 problem = PR_5_BLOCK_UNUSED;
8145 } else {
8146 /*
8147 * Block used, but not marked in use in the bitmap.
8148 */
8149 problem = PR_5_BLOCK_USED;
8150 }
8151 if (pctx.blk == NO_BLK) {
8152 pctx.blk = pctx.blk2 = i;
8153 save_problem = problem;
8154 } else {
8155 if ((problem == save_problem) &&
8156 (pctx.blk2 == i-1))
8157 pctx.blk2++;
8158 else {
8159 print_bitmap_problem(ctx, save_problem, &pctx);
8160 pctx.blk = pctx.blk2 = i;
8161 save_problem = problem;
8162 }
8163 }
8164 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
8165 had_problem++;
8166
8167 do_counts:
8168 if (!bitmap) {
8169 group_free++;
8170 free_blocks++;
8171 }
8172 blocks ++;
8173 if ((blocks == fs->super->s_blocks_per_group) ||
8174 (i == fs->super->s_blocks_count-1)) {
8175 free_array[group] = group_free;
8176 group ++;
8177 blocks = 0;
8178 group_free = 0;
8179 if (ctx->progress)
8180 if ((ctx->progress)(ctx, 5, group,
8181 fs->group_desc_count*2))
8182 return;
8183 }
8184 }
8185 if (pctx.blk != NO_BLK)
8186 print_bitmap_problem(ctx, save_problem, &pctx);
8187 if (had_problem)
8188 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
8189 else
8190 fixit = -1;
8191 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
8192
8193 if (fixit == 1) {
8194 ext2fs_free_block_bitmap(fs->block_map);
8195 retval = ext2fs_copy_bitmap(ctx->block_found_map,
8196 &fs->block_map);
8197 if (retval) {
8198 clear_problem_context(&pctx);
8199 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
8200 ctx->flags |= E2F_FLAG_ABORT;
8201 return;
8202 }
8203 ext2fs_set_bitmap_padding(fs->block_map);
8204 ext2fs_mark_bb_dirty(fs);
8205
8206 /* Redo the counts */
8207 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
8208 memset(free_array, 0, fs->group_desc_count * sizeof(int));
8209 goto redo_counts;
8210 } else if (fixit == 0)
8211 ext2fs_unmark_valid(fs);
8212
8213 for (i = 0; i < fs->group_desc_count; i++) {
8214 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
8215 pctx.group = i;
8216 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
8217 pctx.blk2 = free_array[i];
8218
8219 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
8220 &pctx)) {
8221 fs->group_desc[i].bg_free_blocks_count =
8222 free_array[i];
8223 ext2fs_mark_super_dirty(fs);
8224 } else
8225 ext2fs_unmark_valid(fs);
8226 }
8227 }
8228 if (free_blocks != fs->super->s_free_blocks_count) {
8229 pctx.group = 0;
8230 pctx.blk = fs->super->s_free_blocks_count;
8231 pctx.blk2 = free_blocks;
8232
8233 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
8234 fs->super->s_free_blocks_count = free_blocks;
8235 ext2fs_mark_super_dirty(fs);
8236 } else
8237 ext2fs_unmark_valid(fs);
8238 }
8239 ext2fs_free_mem(&free_array);
8240}
8241
8242static void check_inode_bitmaps(e2fsck_t ctx)
8243{
8244 ext2_filsys fs = ctx->fs;
8245 ext2_ino_t i;
8246 unsigned int free_inodes = 0;
8247 int group_free = 0;
8248 int dirs_count = 0;
8249 int group = 0;
8250 unsigned int inodes = 0;
8251 int *free_array;
8252 int *dir_array;
8253 int actual, bitmap;
8254 errcode_t retval;
8255 struct problem_context pctx;
8256 int problem, save_problem, fixit, had_problem;
8257
8258 clear_problem_context(&pctx);
8259 free_array = (int *) e2fsck_allocate_memory(ctx,
8260 fs->group_desc_count * sizeof(int), "free inode count array");
8261
8262 dir_array = (int *) e2fsck_allocate_memory(ctx,
8263 fs->group_desc_count * sizeof(int), "directory count array");
8264
8265 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
8266 (fs->super->s_inodes_count >
8267 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
8268 pctx.num = 3;
8269 pctx.blk = 1;
8270 pctx.blk2 = fs->super->s_inodes_count;
8271 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
8272 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
8273 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
8274
8275 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8276 return;
8277 }
8278 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
8279 (fs->super->s_inodes_count >
8280 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
8281 pctx.num = 4;
8282 pctx.blk = 1;
8283 pctx.blk2 = fs->super->s_inodes_count;
8284 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
8285 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
8286 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
8287
8288 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8289 return;
8290 }
8291
8292redo_counts:
8293 had_problem = 0;
8294 save_problem = 0;
8295 pctx.ino = pctx.ino2 = 0;
8296 for (i = 1; i <= fs->super->s_inodes_count; i++) {
8297 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
8298 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
8299
8300 if (actual == bitmap)
8301 goto do_counts;
8302
8303 if (!actual && bitmap) {
8304 /*
8305 * Inode wasn't used, but marked in bitmap
8306 */
8307 problem = PR_5_INODE_UNUSED;
8308 } else /* if (actual && !bitmap) */ {
8309 /*
8310 * Inode used, but not in bitmap
8311 */
8312 problem = PR_5_INODE_USED;
8313 }
8314 if (pctx.ino == 0) {
8315 pctx.ino = pctx.ino2 = i;
8316 save_problem = problem;
8317 } else {
8318 if ((problem == save_problem) &&
8319 (pctx.ino2 == i-1))
8320 pctx.ino2++;
8321 else {
8322 print_bitmap_problem(ctx, save_problem, &pctx);
8323 pctx.ino = pctx.ino2 = i;
8324 save_problem = problem;
8325 }
8326 }
8327 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
8328 had_problem++;
8329
8330do_counts:
8331 if (!bitmap) {
8332 group_free++;
8333 free_inodes++;
8334 } else {
8335 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
8336 dirs_count++;
8337 }
8338 inodes++;
8339 if ((inodes == fs->super->s_inodes_per_group) ||
8340 (i == fs->super->s_inodes_count)) {
8341 free_array[group] = group_free;
8342 dir_array[group] = dirs_count;
8343 group ++;
8344 inodes = 0;
8345 group_free = 0;
8346 dirs_count = 0;
8347 if (ctx->progress)
8348 if ((ctx->progress)(ctx, 5,
8349 group + fs->group_desc_count,
8350 fs->group_desc_count*2))
8351 return;
8352 }
8353 }
8354 if (pctx.ino)
8355 print_bitmap_problem(ctx, save_problem, &pctx);
8356
8357 if (had_problem)
8358 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
8359 else
8360 fixit = -1;
8361 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
8362
8363 if (fixit == 1) {
8364 ext2fs_free_inode_bitmap(fs->inode_map);
8365 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
8366 &fs->inode_map);
8367 if (retval) {
8368 clear_problem_context(&pctx);
8369 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
8370 ctx->flags |= E2F_FLAG_ABORT;
8371 return;
8372 }
8373 ext2fs_set_bitmap_padding(fs->inode_map);
8374 ext2fs_mark_ib_dirty(fs);
8375
8376 /* redo counts */
8377 inodes = 0; free_inodes = 0; group_free = 0;
8378 dirs_count = 0; group = 0;
8379 memset(free_array, 0, fs->group_desc_count * sizeof(int));
8380 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
8381 goto redo_counts;
8382 } else if (fixit == 0)
8383 ext2fs_unmark_valid(fs);
8384
8385 for (i = 0; i < fs->group_desc_count; i++) {
8386 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
8387 pctx.group = i;
8388 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
8389 pctx.ino2 = free_array[i];
8390 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
8391 &pctx)) {
8392 fs->group_desc[i].bg_free_inodes_count =
8393 free_array[i];
8394 ext2fs_mark_super_dirty(fs);
8395 } else
8396 ext2fs_unmark_valid(fs);
8397 }
8398 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
8399 pctx.group = i;
8400 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
8401 pctx.ino2 = dir_array[i];
8402
8403 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
8404 &pctx)) {
8405 fs->group_desc[i].bg_used_dirs_count =
8406 dir_array[i];
8407 ext2fs_mark_super_dirty(fs);
8408 } else
8409 ext2fs_unmark_valid(fs);
8410 }
8411 }
8412 if (free_inodes != fs->super->s_free_inodes_count) {
8413 pctx.group = -1;
8414 pctx.ino = fs->super->s_free_inodes_count;
8415 pctx.ino2 = free_inodes;
8416
8417 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
8418 fs->super->s_free_inodes_count = free_inodes;
8419 ext2fs_mark_super_dirty(fs);
8420 } else
8421 ext2fs_unmark_valid(fs);
8422 }
8423 ext2fs_free_mem(&free_array);
8424 ext2fs_free_mem(&dir_array);
8425}
8426
8427static void check_inode_end(e2fsck_t ctx)
8428{
8429 ext2_filsys fs = ctx->fs;
8430 ext2_ino_t end, save_inodes_count, i;
8431 struct problem_context pctx;
8432
8433 clear_problem_context(&pctx);
8434
8435 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
8436 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
8437 &save_inodes_count);
8438 if (pctx.errcode) {
8439 pctx.num = 1;
8440 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8441 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8442 return;
8443 }
8444 if (save_inodes_count == end)
8445 return;
8446
8447 for (i = save_inodes_count + 1; i <= end; i++) {
8448 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
8449 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
8450 for (i = save_inodes_count + 1; i <= end; i++)
8451 ext2fs_mark_inode_bitmap(fs->inode_map,
8452 i);
8453 ext2fs_mark_ib_dirty(fs);
8454 } else
8455 ext2fs_unmark_valid(fs);
8456 break;
8457 }
8458 }
8459
8460 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
8461 save_inodes_count, 0);
8462 if (pctx.errcode) {
8463 pctx.num = 2;
8464 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8465 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8466 return;
8467 }
8468}
8469
8470static void check_block_end(e2fsck_t ctx)
8471{
8472 ext2_filsys fs = ctx->fs;
8473 blk_t end, save_blocks_count, i;
8474 struct problem_context pctx;
8475
8476 clear_problem_context(&pctx);
8477
8478 end = fs->block_map->start +
8479 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
8480 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
8481 &save_blocks_count);
8482 if (pctx.errcode) {
8483 pctx.num = 3;
8484 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8485 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8486 return;
8487 }
8488 if (save_blocks_count == end)
8489 return;
8490
8491 for (i = save_blocks_count + 1; i <= end; i++) {
8492 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
8493 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
8494 for (i = save_blocks_count + 1; i <= end; i++)
8495 ext2fs_mark_block_bitmap(fs->block_map,
8496 i);
8497 ext2fs_mark_bb_dirty(fs);
8498 } else
8499 ext2fs_unmark_valid(fs);
8500 break;
8501 }
8502 }
8503
8504 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
8505 save_blocks_count, 0);
8506 if (pctx.errcode) {
8507 pctx.num = 4;
8508 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8509 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8510 return;
8511 }
8512}
8513
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008514static void e2fsck_pass5(e2fsck_t ctx)
8515{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008516 struct problem_context pctx;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008517
Rob Landley3e72c592006-04-06 22:49:04 +00008518 /* Pass 5 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008519
8520 clear_problem_context(&pctx);
8521
8522 if (!(ctx->options & E2F_OPT_PREEN))
8523 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
8524
8525 if (ctx->progress)
8526 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
8527 return;
8528
8529 e2fsck_read_bitmaps(ctx);
8530
8531 check_block_bitmaps(ctx);
8532 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8533 return;
8534 check_inode_bitmaps(ctx);
8535 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8536 return;
8537 check_inode_end(ctx);
8538 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8539 return;
8540 check_block_end(ctx);
8541 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8542 return;
8543
8544 ext2fs_free_inode_bitmap(ctx->inode_used_map);
8545 ctx->inode_used_map = 0;
8546 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
8547 ctx->inode_dir_map = 0;
8548 ext2fs_free_block_bitmap(ctx->block_found_map);
8549 ctx->block_found_map = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008550}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008551
8552/*
8553 * problem.c --- report filesystem problems to the user
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008554 */
8555
8556#define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */
8557#define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */
8558#define PR_NO_DEFAULT 0x000004 /* Default to no */
8559#define PR_MSG_ONLY 0x000008 /* Print message only */
8560
8561/* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */
8562
8563#define PR_FATAL 0x001000 /* Fatal error */
8564#define PR_AFTER_CODE 0x002000 /* After asking the first question, */
8565 /* ask another */
8566#define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */
8567#define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */
8568#define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */
8569#define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */
8570#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
8571
8572
8573#define PROMPT_NONE 0
8574#define PROMPT_FIX 1
8575#define PROMPT_CLEAR 2
8576#define PROMPT_RELOCATE 3
8577#define PROMPT_ALLOCATE 4
8578#define PROMPT_EXPAND 5
8579#define PROMPT_CONNECT 6
8580#define PROMPT_CREATE 7
8581#define PROMPT_SALVAGE 8
8582#define PROMPT_TRUNCATE 9
8583#define PROMPT_CLEAR_INODE 10
8584#define PROMPT_ABORT 11
8585#define PROMPT_SPLIT 12
8586#define PROMPT_CONTINUE 13
8587#define PROMPT_CLONE 14
8588#define PROMPT_DELETE 15
8589#define PROMPT_SUPPRESS 16
8590#define PROMPT_UNLINK 17
8591#define PROMPT_CLEAR_HTREE 18
8592#define PROMPT_RECREATE 19
8593#define PROMPT_NULL 20
8594
8595struct e2fsck_problem {
8596 problem_t e2p_code;
8597 const char * e2p_description;
8598 char prompt;
8599 int flags;
8600 problem_t second_code;
8601};
8602
8603struct latch_descr {
8604 int latch_code;
8605 problem_t question;
8606 problem_t end_message;
8607 int flags;
8608};
8609
8610/*
8611 * These are the prompts which are used to ask the user if they want
8612 * to fix a problem.
8613 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008614static const char * const prompt[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008615 N_("(no prompt)"), /* 0 */
8616 N_("Fix"), /* 1 */
8617 N_("Clear"), /* 2 */
8618 N_("Relocate"), /* 3 */
8619 N_("Allocate"), /* 4 */
8620 N_("Expand"), /* 5 */
8621 N_("Connect to /lost+found"), /* 6 */
8622 N_("Create"), /* 7 */
8623 N_("Salvage"), /* 8 */
8624 N_("Truncate"), /* 9 */
8625 N_("Clear inode"), /* 10 */
8626 N_("Abort"), /* 11 */
8627 N_("Split"), /* 12 */
8628 N_("Continue"), /* 13 */
Mike Frysinger874af852006-03-08 07:03:27 +00008629 N_("Clone multiply-claimed blocks"), /* 14 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008630 N_("Delete file"), /* 15 */
8631 N_("Suppress messages"),/* 16 */
8632 N_("Unlink"), /* 17 */
8633 N_("Clear HTree index"),/* 18 */
8634 N_("Recreate"), /* 19 */
8635 "", /* 20 */
8636};
8637
8638/*
8639 * These messages are printed when we are preen mode and we will be
8640 * automatically fixing the problem.
8641 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008642static const char * const preen_msg[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008643 N_("(NONE)"), /* 0 */
8644 N_("FIXED"), /* 1 */
8645 N_("CLEARED"), /* 2 */
8646 N_("RELOCATED"), /* 3 */
8647 N_("ALLOCATED"), /* 4 */
8648 N_("EXPANDED"), /* 5 */
8649 N_("RECONNECTED"), /* 6 */
8650 N_("CREATED"), /* 7 */
8651 N_("SALVAGED"), /* 8 */
8652 N_("TRUNCATED"), /* 9 */
8653 N_("INODE CLEARED"), /* 10 */
8654 N_("ABORTED"), /* 11 */
8655 N_("SPLIT"), /* 12 */
8656 N_("CONTINUING"), /* 13 */
Mike Frysinger874af852006-03-08 07:03:27 +00008657 N_("MULTIPLY-CLAIMED BLOCKS CLONED"), /* 14 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008658 N_("FILE DELETED"), /* 15 */
8659 N_("SUPPRESSED"), /* 16 */
8660 N_("UNLINKED"), /* 17 */
8661 N_("HTREE INDEX CLEARED"),/* 18 */
8662 N_("WILL RECREATE"), /* 19 */
8663 "", /* 20 */
8664};
8665
8666static const struct e2fsck_problem problem_table[] = {
8667
8668 /* Pre-Pass 1 errors */
8669
8670 /* Block bitmap not in group */
8671 { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
8672 PROMPT_RELOCATE, PR_LATCH_RELOC },
8673
8674 /* Inode bitmap not in group */
8675 { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
8676 PROMPT_RELOCATE, PR_LATCH_RELOC },
8677
8678 /* Inode table not in group */
8679 { PR_0_ITABLE_NOT_GROUP,
8680 N_("@i table for @g %g is not in @g. (@b %b)\n"
8681 "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
8682 PROMPT_RELOCATE, PR_LATCH_RELOC },
8683
8684 /* Superblock corrupt */
8685 { PR_0_SB_CORRUPT,
8686 N_("\nThe @S could not be read or does not describe a correct ext2\n"
8687 "@f. If the @v is valid and it really contains an ext2\n"
8688 "@f (and not swap or ufs or something else), then the @S\n"
8689 "is corrupt, and you might try running e2fsck with an alternate @S:\n"
8690 " e2fsck -b %S <@v>\n\n"),
8691 PROMPT_NONE, PR_FATAL },
8692
8693 /* Filesystem size is wrong */
8694 { PR_0_FS_SIZE_WRONG,
8695 N_("The @f size (according to the @S) is %b @bs\n"
8696 "The physical size of the @v is %c @bs\n"
8697 "Either the @S or the partition table is likely to be corrupt!\n"),
8698 PROMPT_ABORT, 0 },
8699
8700 /* Fragments not supported */
8701 { PR_0_NO_FRAGMENTS,
8702 N_("@S @b_size = %b, fragsize = %c.\n"
8703 "This version of e2fsck does not support fragment sizes different\n"
8704 "from the @b size.\n"),
8705 PROMPT_NONE, PR_FATAL },
8706
8707 /* Bad blocks_per_group */
8708 { PR_0_BLOCKS_PER_GROUP,
8709 N_("@S @bs_per_group = %b, should have been %c\n"),
8710 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
8711
8712 /* Bad first_data_block */
8713 { PR_0_FIRST_DATA_BLOCK,
8714 N_("@S first_data_@b = %b, should have been %c\n"),
8715 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
8716
8717 /* Adding UUID to filesystem */
8718 { PR_0_ADD_UUID,
8719 N_("@f did not have a UUID; generating one.\n\n"),
8720 PROMPT_NONE, 0 },
8721
8722 /* Relocate hint */
8723 { PR_0_RELOCATE_HINT,
Mike Frysinger874af852006-03-08 07:03:27 +00008724 N_("Note: if several inode or block bitmap blocks or part\n"
8725 "of the inode table require relocation, you may wish to try\n"
8726 "running e2fsck with the '-b %S' option first. The problem\n"
8727 "may lie only with the primary block group descriptors, and\n"
8728 "the backup block group descriptors may be OK.\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008729 PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
8730
8731 /* Miscellaneous superblock corruption */
8732 { PR_0_MISC_CORRUPT_SUPER,
8733 N_("Corruption found in @S. (%s = %N).\n"),
8734 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
8735
8736 /* Error determing physical device size of filesystem */
8737 { PR_0_GETSIZE_ERROR,
8738 N_("Error determining size of the physical @v: %m\n"),
8739 PROMPT_NONE, PR_FATAL },
8740
8741 /* Inode count in superblock is incorrect */
8742 { PR_0_INODE_COUNT_WRONG,
Mike Frysinger874af852006-03-08 07:03:27 +00008743 N_("@i count in @S is %i, @s %j.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008744 PROMPT_FIX, 0 },
8745
8746 { PR_0_HURD_CLEAR_FILETYPE,
8747 N_("The Hurd does not support the filetype feature.\n"),
8748 PROMPT_CLEAR, 0 },
8749
8750 /* Journal inode is invalid */
8751 { PR_0_JOURNAL_BAD_INODE,
Mike Frysinger874af852006-03-08 07:03:27 +00008752 N_("@S has an @n ext3 @j (@i %i).\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008753 PROMPT_CLEAR, PR_PREEN_OK },
8754
8755 /* The external journal has (unsupported) multiple filesystems */
8756 { PR_0_JOURNAL_UNSUPP_MULTIFS,
8757 N_("External @j has multiple @f users (unsupported).\n"),
8758 PROMPT_NONE, PR_FATAL },
8759
8760 /* Can't find external journal */
8761 { PR_0_CANT_FIND_JOURNAL,
8762 N_("Can't find external @j\n"),
8763 PROMPT_NONE, PR_FATAL },
8764
8765 /* External journal has bad superblock */
8766 { PR_0_EXT_JOURNAL_BAD_SUPER,
8767 N_("External @j has bad @S\n"),
8768 PROMPT_NONE, PR_FATAL },
8769
8770 /* Superblock has a bad journal UUID */
8771 { PR_0_JOURNAL_BAD_UUID,
8772 N_("External @j does not support this @f\n"),
8773 PROMPT_NONE, PR_FATAL },
8774
8775 /* Journal has an unknown superblock type */
8776 { PR_0_JOURNAL_UNSUPP_SUPER,
8777 N_("Ext3 @j @S is unknown type %N (unsupported).\n"
8778 "It is likely that your copy of e2fsck is old and/or doesn't "
8779 "support this @j format.\n"
8780 "It is also possible the @j @S is corrupt.\n"),
8781 PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
8782
8783 /* Journal superblock is corrupt */
8784 { PR_0_JOURNAL_BAD_SUPER,
8785 N_("Ext3 @j @S is corrupt.\n"),
8786 PROMPT_FIX, PR_PREEN_OK },
8787
8788 /* Superblock flag should be cleared */
8789 { PR_0_JOURNAL_HAS_JOURNAL,
8790 N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
8791 PROMPT_CLEAR, PR_PREEN_OK },
8792
8793 /* Superblock flag is incorrect */
8794 { PR_0_JOURNAL_RECOVER_SET,
8795 N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
8796 PROMPT_CLEAR, PR_PREEN_OK },
8797
8798 /* Journal has data, but recovery flag is clear */
8799 { PR_0_JOURNAL_RECOVERY_CLEAR,
Mike Frysinger874af852006-03-08 07:03:27 +00008800 N_("ext3 recovery flag is clear, but @j has data.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008801 PROMPT_NONE, 0 },
8802
8803 /* Ask if we should clear the journal */
8804 { PR_0_JOURNAL_RESET_JOURNAL,
8805 N_("Clear @j"),
8806 PROMPT_NULL, PR_PREEN_NOMSG },
8807
8808 /* Ask if we should run the journal anyway */
8809 { PR_0_JOURNAL_RUN,
8810 N_("Run @j anyway"),
8811 PROMPT_NULL, 0 },
8812
8813 /* Run the journal by default */
8814 { PR_0_JOURNAL_RUN_DEFAULT,
8815 N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
8816 PROMPT_NONE, 0 },
8817
8818 /* Clearing orphan inode */
8819 { PR_0_ORPHAN_CLEAR_INODE,
8820 N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
8821 PROMPT_NONE, 0 },
8822
8823 /* Illegal block found in orphaned inode */
8824 { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
8825 N_("@I @b #%B (%b) found in @o @i %i.\n"),
8826 PROMPT_NONE, 0 },
8827
8828 /* Already cleared block found in orphaned inode */
8829 { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
8830 N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
8831 PROMPT_NONE, 0 },
8832
8833 /* Illegal orphan inode in superblock */
8834 { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
8835 N_("@I @o @i %i in @S.\n"),
8836 PROMPT_NONE, 0 },
8837
8838 /* Illegal inode in orphaned inode list */
8839 { PR_0_ORPHAN_ILLEGAL_INODE,
8840 N_("@I @i %i in @o @i list.\n"),
8841 PROMPT_NONE, 0 },
8842
8843 /* Filesystem revision is 0, but feature flags are set */
8844 { PR_0_FS_REV_LEVEL,
Mike Frysinger874af852006-03-08 07:03:27 +00008845 N_("@f has feature flag(s) set, but is a revision 0 @f. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008846 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
8847
8848 /* Journal superblock has an unknown read-only feature flag set */
8849 { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
8850 N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
8851 PROMPT_ABORT, 0 },
8852
8853 /* Journal superblock has an unknown incompatible feature flag set */
8854 { PR_0_JOURNAL_UNSUPP_INCOMPAT,
8855 N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
8856 PROMPT_ABORT, 0 },
8857
8858 /* Journal has unsupported version number */
8859 { PR_0_JOURNAL_UNSUPP_VERSION,
8860 N_("@j version not supported by this e2fsck.\n"),
8861 PROMPT_ABORT, 0 },
8862
8863 /* Moving journal to hidden file */
8864 { PR_0_MOVE_JOURNAL,
Mike Frysinger874af852006-03-08 07:03:27 +00008865 N_("Moving @j from /%s to hidden @i.\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008866 PROMPT_NONE, 0 },
8867
8868 /* Error moving journal to hidden file */
8869 { PR_0_ERR_MOVE_JOURNAL,
8870 N_("Error moving @j: %m\n\n"),
8871 PROMPT_NONE, 0 },
8872
8873 /* Clearing V2 journal superblock */
8874 { PR_0_CLEAR_V2_JOURNAL,
Mike Frysinger874af852006-03-08 07:03:27 +00008875 N_("Found @n V2 @j @S fields (from V1 @j).\n"
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008876 "Clearing fields beyond the V1 @j @S...\n\n"),
8877 PROMPT_NONE, 0 },
8878
8879 /* Backup journal inode blocks */
8880 { PR_0_BACKUP_JNL,
8881 N_("Backing up @j @i @b information.\n\n"),
8882 PROMPT_NONE, 0 },
8883
8884 /* Reserved blocks w/o resize_inode */
8885 { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
8886 N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
8887 "is %N; @s zero. "),
8888 PROMPT_FIX, 0 },
8889
8890 /* Resize_inode not enabled, but resize inode is non-zero */
8891 { PR_0_CLEAR_RESIZE_INODE,
Mike Frysinger874af852006-03-08 07:03:27 +00008892 N_("Resize_@i not enabled, but the resize @i is non-zero. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008893 PROMPT_CLEAR, 0 },
8894
8895 /* Resize inode invalid */
8896 { PR_0_RESIZE_INODE_INVALID,
8897 N_("Resize @i not valid. "),
8898 PROMPT_RECREATE, 0 },
8899
8900 /* Pass 1 errors */
8901
8902 /* Pass 1: Checking inodes, blocks, and sizes */
8903 { PR_1_PASS_HEADER,
8904 N_("Pass 1: Checking @is, @bs, and sizes\n"),
8905 PROMPT_NONE, 0 },
8906
8907 /* Root directory is not an inode */
8908 { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
8909 PROMPT_CLEAR, 0 },
8910
8911 /* Root directory has dtime set */
8912 { PR_1_ROOT_DTIME,
8913 N_("@r has dtime set (probably due to old mke2fs). "),
8914 PROMPT_FIX, PR_PREEN_OK },
8915
8916 /* Reserved inode has bad mode */
8917 { PR_1_RESERVED_BAD_MODE,
Mike Frysinger874af852006-03-08 07:03:27 +00008918 N_("Reserved @i %i (%Q) has @n mode. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008919 PROMPT_CLEAR, PR_PREEN_OK },
8920
8921 /* Deleted inode has zero dtime */
8922 { PR_1_ZERO_DTIME,
8923 N_("@D @i %i has zero dtime. "),
8924 PROMPT_FIX, PR_PREEN_OK },
8925
8926 /* Inode in use, but dtime set */
8927 { PR_1_SET_DTIME,
8928 N_("@i %i is in use, but has dtime set. "),
8929 PROMPT_FIX, PR_PREEN_OK },
8930
8931 /* Zero-length directory */
8932 { PR_1_ZERO_LENGTH_DIR,
8933 N_("@i %i is a @z @d. "),
8934 PROMPT_CLEAR, PR_PREEN_OK },
8935
8936 /* Block bitmap conflicts with some other fs block */
8937 { PR_1_BB_CONFLICT,
8938 N_("@g %g's @b @B at %b @C.\n"),
8939 PROMPT_RELOCATE, 0 },
8940
8941 /* Inode bitmap conflicts with some other fs block */
8942 { PR_1_IB_CONFLICT,
8943 N_("@g %g's @i @B at %b @C.\n"),
8944 PROMPT_RELOCATE, 0 },
8945
8946 /* Inode table conflicts with some other fs block */
8947 { PR_1_ITABLE_CONFLICT,
8948 N_("@g %g's @i table at %b @C.\n"),
8949 PROMPT_RELOCATE, 0 },
8950
8951 /* Block bitmap is on a bad block */
8952 { PR_1_BB_BAD_BLOCK,
8953 N_("@g %g's @b @B (%b) is bad. "),
8954 PROMPT_RELOCATE, 0 },
8955
8956 /* Inode bitmap is on a bad block */
8957 { PR_1_IB_BAD_BLOCK,
8958 N_("@g %g's @i @B (%b) is bad. "),
8959 PROMPT_RELOCATE, 0 },
8960
8961 /* Inode has incorrect i_size */
8962 { PR_1_BAD_I_SIZE,
8963 N_("@i %i, i_size is %Is, @s %N. "),
8964 PROMPT_FIX, PR_PREEN_OK },
8965
8966 /* Inode has incorrect i_blocks */
8967 { PR_1_BAD_I_BLOCKS,
8968 N_("@i %i, i_@bs is %Ib, @s %N. "),
8969 PROMPT_FIX, PR_PREEN_OK },
8970
8971 /* Illegal blocknumber in inode */
8972 { PR_1_ILLEGAL_BLOCK_NUM,
8973 N_("@I @b #%B (%b) in @i %i. "),
8974 PROMPT_CLEAR, PR_LATCH_BLOCK },
8975
8976 /* Block number overlaps fs metadata */
8977 { PR_1_BLOCK_OVERLAPS_METADATA,
8978 N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
8979 PROMPT_CLEAR, PR_LATCH_BLOCK },
8980
8981 /* Inode has illegal blocks (latch question) */
8982 { PR_1_INODE_BLOCK_LATCH,
8983 N_("@i %i has illegal @b(s). "),
8984 PROMPT_CLEAR, 0 },
8985
8986 /* Too many bad blocks in inode */
8987 { PR_1_TOO_MANY_BAD_BLOCKS,
8988 N_("Too many illegal @bs in @i %i.\n"),
8989 PROMPT_CLEAR_INODE, PR_NO_OK },
8990
8991 /* Illegal block number in bad block inode */
8992 { PR_1_BB_ILLEGAL_BLOCK_NUM,
8993 N_("@I @b #%B (%b) in bad @b @i. "),
8994 PROMPT_CLEAR, PR_LATCH_BBLOCK },
8995
8996 /* Bad block inode has illegal blocks (latch question) */
8997 { PR_1_INODE_BBLOCK_LATCH,
8998 N_("Bad @b @i has illegal @b(s). "),
8999 PROMPT_CLEAR, 0 },
9000
9001 /* Duplicate or bad blocks in use! */
9002 { PR_1_DUP_BLOCKS_PREENSTOP,
9003 N_("Duplicate or bad @b in use!\n"),
9004 PROMPT_NONE, 0 },
9005
9006 /* Bad block used as bad block indirect block */
9007 { PR_1_BBINODE_BAD_METABLOCK,
9008 N_("Bad @b %b used as bad @b @i indirect @b. "),
9009 PROMPT_CLEAR, PR_LATCH_BBLOCK },
9010
9011 /* Inconsistency can't be fixed prompt */
9012 { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
9013 N_("\nThe bad @b @i has probably been corrupted. You probably\n"
9014 "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
9015 "in the @f.\n"),
9016 PROMPT_CONTINUE, PR_PREEN_NOMSG },
9017
9018 /* Bad primary block */
9019 { PR_1_BAD_PRIMARY_BLOCK,
9020 N_("\nIf the @b is really bad, the @f can not be fixed.\n"),
9021 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
9022
9023 /* Bad primary block prompt */
9024 { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
Mike Frysinger874af852006-03-08 07:03:27 +00009025 N_("You can remove this @b from the bad @b list and hope\n"
9026 "that the @b is really OK. But there are no guarantees.\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009027 PROMPT_CLEAR, PR_PREEN_NOMSG },
9028
9029 /* Bad primary superblock */
9030 { PR_1_BAD_PRIMARY_SUPERBLOCK,
9031 N_("The primary @S (%b) is on the bad @b list.\n"),
9032 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
9033
9034 /* Bad primary block group descriptors */
9035 { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
9036 N_("Block %b in the primary @g descriptors "
9037 "is on the bad @b list\n"),
9038 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
9039
9040 /* Bad superblock in group */
9041 { PR_1_BAD_SUPERBLOCK,
9042 N_("Warning: Group %g's @S (%b) is bad.\n"),
9043 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
9044
9045 /* Bad block group descriptors in group */
9046 { PR_1_BAD_GROUP_DESCRIPTORS,
9047 N_("Warning: Group %g's copy of the @g descriptors has a bad "
9048 "@b (%b).\n"),
9049 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
9050
9051 /* Block claimed for no reason */
9052 { PR_1_PROGERR_CLAIMED_BLOCK,
9053 N_("Programming error? @b #%b claimed for no reason in "
9054 "process_bad_@b.\n"),
9055 PROMPT_NONE, PR_PREEN_OK },
9056
9057 /* Error allocating blocks for relocating metadata */
9058 { PR_1_RELOC_BLOCK_ALLOCATE,
9059 N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
9060 PROMPT_NONE, PR_PREEN_OK },
9061
9062 /* Error allocating block buffer during relocation process */
9063 { PR_1_RELOC_MEMORY_ALLOCATE,
9064 N_("@A @b buffer for relocating %s\n"),
9065 PROMPT_NONE, PR_PREEN_OK },
9066
9067 /* Relocating metadata group information from X to Y */
9068 { PR_1_RELOC_FROM_TO,
9069 N_("Relocating @g %g's %s from %b to %c...\n"),
9070 PROMPT_NONE, PR_PREEN_OK },
9071
9072 /* Relocating metatdata group information to X */
9073 { PR_1_RELOC_TO,
9074 N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
9075 PROMPT_NONE, PR_PREEN_OK },
9076
9077 /* Block read error during relocation process */
9078 { PR_1_RELOC_READ_ERR,
9079 N_("Warning: could not read @b %b of %s: %m\n"),
9080 PROMPT_NONE, PR_PREEN_OK },
9081
9082 /* Block write error during relocation process */
9083 { PR_1_RELOC_WRITE_ERR,
9084 N_("Warning: could not write @b %b for %s: %m\n"),
9085 PROMPT_NONE, PR_PREEN_OK },
9086
9087 /* Error allocating inode bitmap */
9088 { PR_1_ALLOCATE_IBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +00009089 N_("@A @i @B (%N): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009090 PROMPT_NONE, PR_FATAL },
9091
9092 /* Error allocating block bitmap */
9093 { PR_1_ALLOCATE_BBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +00009094 N_("@A @b @B (%N): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009095 PROMPT_NONE, PR_FATAL },
9096
9097 /* Error allocating icount structure */
9098 { PR_1_ALLOCATE_ICOUNT,
9099 N_("@A icount link information: %m\n"),
9100 PROMPT_NONE, PR_FATAL },
9101
9102 /* Error allocating dbcount */
9103 { PR_1_ALLOCATE_DBCOUNT,
9104 N_("@A @d @b array: %m\n"),
9105 PROMPT_NONE, PR_FATAL },
9106
9107 /* Error while scanning inodes */
9108 { PR_1_ISCAN_ERROR,
9109 N_("Error while scanning @is (%i): %m\n"),
9110 PROMPT_NONE, PR_FATAL },
9111
9112 /* Error while iterating over blocks */
9113 { PR_1_BLOCK_ITERATE,
9114 N_("Error while iterating over @bs in @i %i: %m\n"),
9115 PROMPT_NONE, PR_FATAL },
9116
9117 /* Error while storing inode count information */
9118 { PR_1_ICOUNT_STORE,
9119 N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
9120 PROMPT_NONE, PR_FATAL },
9121
9122 /* Error while storing directory block information */
9123 { PR_1_ADD_DBLOCK,
9124 N_("Error storing @d @b information "
9125 "(@i=%i, @b=%b, num=%N): %m\n"),
9126 PROMPT_NONE, PR_FATAL },
9127
9128 /* Error while reading inode (for clearing) */
9129 { PR_1_READ_INODE,
9130 N_("Error reading @i %i: %m\n"),
9131 PROMPT_NONE, PR_FATAL },
9132
9133 /* Suppress messages prompt */
9134 { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
9135
9136 /* Imagic flag set on an inode when filesystem doesn't support it */
9137 { PR_1_SET_IMAGIC,
9138 N_("@i %i has imagic flag set. "),
9139 PROMPT_CLEAR, 0 },
9140
9141 /* Immutable flag set on a device or socket inode */
9142 { PR_1_SET_IMMUTABLE,
9143 N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
9144 "or append-only flag set. "),
9145 PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
9146
9147 /* Compression flag set on an inode when filesystem doesn't support it */
9148 { PR_1_COMPR_SET,
9149 N_("@i %i has @cion flag set on @f without @cion support. "),
9150 PROMPT_CLEAR, 0 },
9151
9152 /* Non-zero size for device, fifo or socket inode */
9153 { PR_1_SET_NONZSIZE,
Mike Frysinger874af852006-03-08 07:03:27 +00009154 N_("Special (@v/socket/fifo) @i %i has non-zero size. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009155 PROMPT_FIX, PR_PREEN_OK },
9156
9157 /* Filesystem revision is 0, but feature flags are set */
9158 { PR_1_FS_REV_LEVEL,
Mike Frysinger874af852006-03-08 07:03:27 +00009159 N_("@f has feature flag(s) set, but is a revision 0 @f. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009160 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
9161
9162 /* Journal inode is not in use, but contains data */
9163 { PR_1_JOURNAL_INODE_NOT_CLEAR,
Mike Frysinger874af852006-03-08 07:03:27 +00009164 N_("@j @i is not in use, but contains data. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009165 PROMPT_CLEAR, PR_PREEN_OK },
9166
9167 /* Journal has bad mode */
9168 { PR_1_JOURNAL_BAD_MODE,
9169 N_("@j is not regular file. "),
9170 PROMPT_FIX, PR_PREEN_OK },
9171
9172 /* Deal with inodes that were part of orphan linked list */
9173 { PR_1_LOW_DTIME,
Mike Frysinger874af852006-03-08 07:03:27 +00009174 N_("@i %i was part of the @o @i list. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009175 PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
9176
9177 /* Deal with inodes that were part of corrupted orphan linked
9178 list (latch question) */
9179 { PR_1_ORPHAN_LIST_REFUGEES,
9180 N_("@is that were part of a corrupted orphan linked list found. "),
9181 PROMPT_FIX, 0 },
9182
9183 /* Error allocating refcount structure */
9184 { PR_1_ALLOCATE_REFCOUNT,
Mike Frysinger874af852006-03-08 07:03:27 +00009185 N_("@A refcount structure (%N): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009186 PROMPT_NONE, PR_FATAL },
9187
9188 /* Error reading extended attribute block */
9189 { PR_1_READ_EA_BLOCK,
9190 N_("Error reading @a @b %b for @i %i. "),
9191 PROMPT_CLEAR, 0 },
9192
9193 /* Invalid extended attribute block */
9194 { PR_1_BAD_EA_BLOCK,
9195 N_("@i %i has a bad @a @b %b. "),
9196 PROMPT_CLEAR, 0 },
9197
9198 /* Error reading Extended Attribute block while fixing refcount */
9199 { PR_1_EXTATTR_READ_ABORT,
9200 N_("Error reading @a @b %b (%m). "),
9201 PROMPT_ABORT, 0 },
9202
9203 /* Extended attribute reference count incorrect */
9204 { PR_1_EXTATTR_REFCOUNT,
Mike Frysinger874af852006-03-08 07:03:27 +00009205 N_("@a @b %b has reference count %B, @s %N. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009206 PROMPT_FIX, 0 },
9207
9208 /* Error writing Extended Attribute block while fixing refcount */
9209 { PR_1_EXTATTR_WRITE,
9210 N_("Error writing @a @b %b (%m). "),
9211 PROMPT_ABORT, 0 },
9212
9213 /* Multiple EA blocks not supported */
9214 { PR_1_EA_MULTI_BLOCK,
Mike Frysinger874af852006-03-08 07:03:27 +00009215 N_("@a @b %b has h_@bs > 1. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009216 PROMPT_CLEAR, 0},
9217
9218 /* Error allocating EA region allocation structure */
9219 { PR_1_EA_ALLOC_REGION,
Mike Frysinger874af852006-03-08 07:03:27 +00009220 N_("@A @a @b %b. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009221 PROMPT_ABORT, 0},
9222
9223 /* Error EA allocation collision */
9224 { PR_1_EA_ALLOC_COLLISION,
9225 N_("@a @b %b is corrupt (allocation collision). "),
9226 PROMPT_CLEAR, 0},
9227
9228 /* Bad extended attribute name */
9229 { PR_1_EA_BAD_NAME,
Mike Frysinger874af852006-03-08 07:03:27 +00009230 N_("@a @b %b is corrupt (@n name). "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009231 PROMPT_CLEAR, 0},
9232
9233 /* Bad extended attribute value */
9234 { PR_1_EA_BAD_VALUE,
Mike Frysinger874af852006-03-08 07:03:27 +00009235 N_("@a @b %b is corrupt (@n value). "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009236 PROMPT_CLEAR, 0},
9237
9238 /* Inode too big (latch question) */
9239 { PR_1_INODE_TOOBIG,
9240 N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
9241
9242 /* Directory too big */
9243 { PR_1_TOOBIG_DIR,
9244 N_("@b #%B (%b) causes @d to be too big. "),
9245 PROMPT_CLEAR, PR_LATCH_TOOBIG },
9246
9247 /* Regular file too big */
9248 { PR_1_TOOBIG_REG,
9249 N_("@b #%B (%b) causes file to be too big. "),
9250 PROMPT_CLEAR, PR_LATCH_TOOBIG },
9251
9252 /* Symlink too big */
9253 { PR_1_TOOBIG_SYMLINK,
9254 N_("@b #%B (%b) causes symlink to be too big. "),
9255 PROMPT_CLEAR, PR_LATCH_TOOBIG },
9256
9257 /* INDEX_FL flag set on a non-HTREE filesystem */
9258 { PR_1_HTREE_SET,
9259 N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
9260 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9261
9262 /* INDEX_FL flag set on a non-directory */
9263 { PR_1_HTREE_NODIR,
9264 N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
9265 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9266
9267 /* Invalid root node in HTREE directory */
9268 { PR_1_HTREE_BADROOT,
Mike Frysinger874af852006-03-08 07:03:27 +00009269 N_("@h %i has an @n root node.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009270 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9271
9272 /* Unsupported hash version in HTREE directory */
9273 { PR_1_HTREE_HASHV,
9274 N_("@h %i has an unsupported hash version (%N)\n"),
9275 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9276
9277 /* Incompatible flag in HTREE root node */
9278 { PR_1_HTREE_INCOMPAT,
9279 N_("@h %i uses an incompatible htree root node flag.\n"),
9280 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9281
9282 /* HTREE too deep */
9283 { PR_1_HTREE_DEPTH,
9284 N_("@h %i has a tree depth (%N) which is too big\n"),
9285 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9286
9287 /* Bad block has indirect block that conflicts with filesystem block */
9288 { PR_1_BB_FS_BLOCK,
9289 N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
9290 "@f metadata. "),
9291 PROMPT_CLEAR, PR_LATCH_BBLOCK },
9292
9293 /* Resize inode failed */
9294 { PR_1_RESIZE_INODE_CREATE,
9295 N_("Resize @i (re)creation failed: %m."),
9296 PROMPT_ABORT, 0 },
9297
9298 /* invalid inode->i_extra_isize */
9299 { PR_1_EXTRA_ISIZE,
Mike Frysinger874af852006-03-08 07:03:27 +00009300 N_("@i %i has a extra size (%IS) which is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009301 PROMPT_FIX, PR_PREEN_OK },
9302
9303 /* invalid ea entry->e_name_len */
9304 { PR_1_ATTR_NAME_LEN,
Mike Frysinger874af852006-03-08 07:03:27 +00009305 N_("@a in @i %i has a namelen (%N) which is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009306 PROMPT_CLEAR, PR_PREEN_OK },
9307
9308 /* invalid ea entry->e_value_size */
9309 { PR_1_ATTR_VALUE_SIZE,
Mike Frysinger874af852006-03-08 07:03:27 +00009310 N_("@a in @i %i has a value size (%N) which is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009311 PROMPT_CLEAR, PR_PREEN_OK },
9312
9313 /* invalid ea entry->e_value_offs */
9314 { PR_1_ATTR_VALUE_OFFSET,
Mike Frysinger874af852006-03-08 07:03:27 +00009315 N_("@a in @i %i has a value offset (%N) which is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009316 PROMPT_CLEAR, PR_PREEN_OK },
9317
9318 /* invalid ea entry->e_value_block */
9319 { PR_1_ATTR_VALUE_BLOCK,
Mike Frysinger874af852006-03-08 07:03:27 +00009320 N_("@a in @i %i has a value @b (%N) which is @n (must be 0)\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009321 PROMPT_CLEAR, PR_PREEN_OK },
9322
9323 /* invalid ea entry->e_hash */
9324 { PR_1_ATTR_HASH,
Mike Frysinger874af852006-03-08 07:03:27 +00009325 N_("@a in @i %i has a hash (%N) which is @n (must be 0)\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009326 PROMPT_CLEAR, PR_PREEN_OK },
9327
9328 /* Pass 1b errors */
9329
9330 /* Pass 1B: Rescan for duplicate/bad blocks */
9331 { PR_1B_PASS_HEADER,
Mike Frysinger874af852006-03-08 07:03:27 +00009332 N_("\nRunning additional passes to resolve @bs claimed by more than one @i...\n"
9333 "Pass 1B: Rescanning for @m @bs\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009334 PROMPT_NONE, 0 },
9335
9336 /* Duplicate/bad block(s) header */
9337 { PR_1B_DUP_BLOCK_HEADER,
Mike Frysinger874af852006-03-08 07:03:27 +00009338 N_("@m @b(s) in @i %i:"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009339 PROMPT_NONE, 0 },
9340
9341 /* Duplicate/bad block(s) in inode */
9342 { PR_1B_DUP_BLOCK,
9343 " %b",
9344 PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
9345
9346 /* Duplicate/bad block(s) end */
9347 { PR_1B_DUP_BLOCK_END,
9348 "\n",
9349 PROMPT_NONE, PR_PREEN_NOHDR },
9350
9351 /* Error while scanning inodes */
9352 { PR_1B_ISCAN_ERROR,
9353 N_("Error while scanning inodes (%i): %m\n"),
9354 PROMPT_NONE, PR_FATAL },
9355
9356 /* Error allocating inode bitmap */
9357 { PR_1B_ALLOCATE_IBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +00009358 N_("@A @i @B (@i_dup_map): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009359 PROMPT_NONE, PR_FATAL },
9360
9361 /* Error while iterating over blocks */
9362 { PR_1B_BLOCK_ITERATE,
9363 N_("Error while iterating over @bs in @i %i (%s): %m\n"),
9364 PROMPT_NONE, 0 },
9365
9366 /* Error adjusting EA refcount */
9367 { PR_1B_ADJ_EA_REFCOUNT,
Mike Frysinger874af852006-03-08 07:03:27 +00009368 N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009369 PROMPT_NONE, 0 },
9370
9371
Mike Frysinger874af852006-03-08 07:03:27 +00009372 /* Pass 1C: Scan directories for inodes with multiply-claimed blocks. */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009373 { PR_1C_PASS_HEADER,
Mike Frysinger874af852006-03-08 07:03:27 +00009374 N_("Pass 1C: Scanning directories for @is with @m @bs.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009375 PROMPT_NONE, 0 },
9376
9377
Mike Frysinger874af852006-03-08 07:03:27 +00009378 /* Pass 1D: Reconciling multiply-claimed blocks */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009379 { PR_1D_PASS_HEADER,
Mike Frysinger874af852006-03-08 07:03:27 +00009380 N_("Pass 1D: Reconciling @m @bs\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009381 PROMPT_NONE, 0 },
9382
9383 /* File has duplicate blocks */
9384 { PR_1D_DUP_FILE,
9385 N_("File %Q (@i #%i, mod time %IM) \n"
Mike Frysinger874af852006-03-08 07:03:27 +00009386 " has %B @m @b(s), shared with %N file(s):\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009387 PROMPT_NONE, 0 },
9388
9389 /* List of files sharing duplicate blocks */
9390 { PR_1D_DUP_FILE_LIST,
9391 N_("\t%Q (@i #%i, mod time %IM)\n"),
9392 PROMPT_NONE, 0 },
9393
9394 /* File sharing blocks with filesystem metadata */
9395 { PR_1D_SHARE_METADATA,
9396 N_("\t<@f metadata>\n"),
9397 PROMPT_NONE, 0 },
9398
9399 /* Report of how many duplicate/bad inodes */
9400 { PR_1D_NUM_DUP_INODES,
Mike Frysinger874af852006-03-08 07:03:27 +00009401 N_("(There are %N @is containing @m @bs.)\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009402 PROMPT_NONE, 0 },
9403
9404 /* Duplicated blocks already reassigned or cloned. */
9405 { PR_1D_DUP_BLOCKS_DEALT,
Mike Frysinger874af852006-03-08 07:03:27 +00009406 N_("@m @bs already reassigned or cloned.\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009407 PROMPT_NONE, 0 },
9408
9409 /* Clone duplicate/bad blocks? */
9410 { PR_1D_CLONE_QUESTION,
9411 "", PROMPT_CLONE, PR_NO_OK },
9412
9413 /* Delete file? */
9414 { PR_1D_DELETE_QUESTION,
9415 "", PROMPT_DELETE, 0 },
9416
9417 /* Couldn't clone file (error) */
9418 { PR_1D_CLONE_ERROR,
9419 N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
9420
9421 /* Pass 2 errors */
9422
9423 /* Pass 2: Checking directory structure */
9424 { PR_2_PASS_HEADER,
9425 N_("Pass 2: Checking @d structure\n"),
9426 PROMPT_NONE, 0 },
9427
9428 /* Bad inode number for '.' */
9429 { PR_2_BAD_INODE_DOT,
Mike Frysinger874af852006-03-08 07:03:27 +00009430 N_("@n @i number for '.' in @d @i %i.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009431 PROMPT_FIX, 0 },
9432
9433 /* Directory entry has bad inode number */
9434 { PR_2_BAD_INO,
Mike Frysinger874af852006-03-08 07:03:27 +00009435 N_("@E has @n @i #: %Di.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009436 PROMPT_CLEAR, 0 },
9437
9438 /* Directory entry has deleted or unused inode */
9439 { PR_2_UNUSED_INODE,
9440 N_("@E has @D/unused @i %Di. "),
9441 PROMPT_CLEAR, PR_PREEN_OK },
9442
9443 /* Directry entry is link to '.' */
9444 { PR_2_LINK_DOT,
9445 N_("@E @L to '.' "),
9446 PROMPT_CLEAR, 0 },
9447
9448 /* Directory entry points to inode now located in a bad block */
9449 { PR_2_BB_INODE,
9450 N_("@E points to @i (%Di) located in a bad @b.\n"),
9451 PROMPT_CLEAR, 0 },
9452
9453 /* Directory entry contains a link to a directory */
9454 { PR_2_LINK_DIR,
9455 N_("@E @L to @d %P (%Di).\n"),
9456 PROMPT_CLEAR, 0 },
9457
9458 /* Directory entry contains a link to the root directry */
9459 { PR_2_LINK_ROOT,
9460 N_("@E @L to the @r.\n"),
9461 PROMPT_CLEAR, 0 },
9462
9463 /* Directory entry has illegal characters in its name */
9464 { PR_2_BAD_NAME,
9465 N_("@E has illegal characters in its name.\n"),
9466 PROMPT_FIX, 0 },
9467
9468 /* Missing '.' in directory inode */
9469 { PR_2_MISSING_DOT,
9470 N_("Missing '.' in @d @i %i.\n"),
9471 PROMPT_FIX, 0 },
9472
9473 /* Missing '..' in directory inode */
9474 { PR_2_MISSING_DOT_DOT,
9475 N_("Missing '..' in @d @i %i.\n"),
9476 PROMPT_FIX, 0 },
9477
9478 /* First entry in directory inode doesn't contain '.' */
9479 { PR_2_1ST_NOT_DOT,
Mike Frysinger874af852006-03-08 07:03:27 +00009480 N_("First @e '%Dn' (@i=%Di) in @d @i %i (%p) @s '.'\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009481 PROMPT_FIX, 0 },
9482
9483 /* Second entry in directory inode doesn't contain '..' */
9484 { PR_2_2ND_NOT_DOT_DOT,
Mike Frysinger874af852006-03-08 07:03:27 +00009485 N_("Second @e '%Dn' (@i=%Di) in @d @i %i @s '..'\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009486 PROMPT_FIX, 0 },
9487
9488 /* i_faddr should be zero */
9489 { PR_2_FADDR_ZERO,
9490 N_("i_faddr @F %IF, @s zero.\n"),
9491 PROMPT_CLEAR, 0 },
9492
9493 /* i_file_acl should be zero */
9494 { PR_2_FILE_ACL_ZERO,
9495 N_("i_file_acl @F %If, @s zero.\n"),
9496 PROMPT_CLEAR, 0 },
9497
9498 /* i_dir_acl should be zero */
9499 { PR_2_DIR_ACL_ZERO,
9500 N_("i_dir_acl @F %Id, @s zero.\n"),
9501 PROMPT_CLEAR, 0 },
9502
9503 /* i_frag should be zero */
9504 { PR_2_FRAG_ZERO,
9505 N_("i_frag @F %N, @s zero.\n"),
9506 PROMPT_CLEAR, 0 },
9507
9508 /* i_fsize should be zero */
9509 { PR_2_FSIZE_ZERO,
9510 N_("i_fsize @F %N, @s zero.\n"),
9511 PROMPT_CLEAR, 0 },
9512
9513 /* inode has bad mode */
9514 { PR_2_BAD_MODE,
Mike Frysinger874af852006-03-08 07:03:27 +00009515 N_("@i %i (%Q) has @n mode (%Im).\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009516 PROMPT_CLEAR, 0 },
9517
9518 /* directory corrupted */
9519 { PR_2_DIR_CORRUPTED,
9520 N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
9521 PROMPT_SALVAGE, 0 },
9522
9523 /* filename too long */
9524 { PR_2_FILENAME_LONG,
9525 N_("@d @i %i, @b %B, offset %N: filename too long\n"),
9526 PROMPT_TRUNCATE, 0 },
9527
9528 /* Directory inode has a missing block (hole) */
9529 { PR_2_DIRECTORY_HOLE,
9530 N_("@d @i %i has an unallocated @b #%B. "),
9531 PROMPT_ALLOCATE, 0 },
9532
9533 /* '.' is not NULL terminated */
9534 { PR_2_DOT_NULL_TERM,
9535 N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
9536 PROMPT_FIX, 0 },
9537
9538 /* '..' is not NULL terminated */
9539 { PR_2_DOT_DOT_NULL_TERM,
9540 N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
9541 PROMPT_FIX, 0 },
9542
9543 /* Illegal character device inode */
9544 { PR_2_BAD_CHAR_DEV,
9545 N_("@i %i (%Q) is an @I character @v.\n"),
9546 PROMPT_CLEAR, 0 },
9547
9548 /* Illegal block device inode */
9549 { PR_2_BAD_BLOCK_DEV,
9550 N_("@i %i (%Q) is an @I @b @v.\n"),
9551 PROMPT_CLEAR, 0 },
9552
9553 /* Duplicate '.' entry */
9554 { PR_2_DUP_DOT,
9555 N_("@E is duplicate '.' @e.\n"),
9556 PROMPT_FIX, 0 },
9557
9558 /* Duplicate '..' entry */
9559 { PR_2_DUP_DOT_DOT,
9560 N_("@E is duplicate '..' @e.\n"),
9561 PROMPT_FIX, 0 },
9562
9563 /* Internal error: couldn't find dir_info */
9564 { PR_2_NO_DIRINFO,
9565 N_("Internal error: couldn't find dir_info for %i.\n"),
9566 PROMPT_NONE, PR_FATAL },
9567
9568 /* Final rec_len is wrong */
9569 { PR_2_FINAL_RECLEN,
Mike Frysinger874af852006-03-08 07:03:27 +00009570 N_("@E has rec_len of %Dr, @s %N.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009571 PROMPT_FIX, 0 },
9572
9573 /* Error allocating icount structure */
9574 { PR_2_ALLOCATE_ICOUNT,
9575 N_("@A icount structure: %m\n"),
9576 PROMPT_NONE, PR_FATAL },
9577
9578 /* Error iterating over directory blocks */
9579 { PR_2_DBLIST_ITERATE,
9580 N_("Error iterating over @d @bs: %m\n"),
9581 PROMPT_NONE, PR_FATAL },
9582
9583 /* Error reading directory block */
9584 { PR_2_READ_DIRBLOCK,
9585 N_("Error reading @d @b %b (@i %i): %m\n"),
9586 PROMPT_CONTINUE, 0 },
9587
9588 /* Error writing directory block */
9589 { PR_2_WRITE_DIRBLOCK,
9590 N_("Error writing @d @b %b (@i %i): %m\n"),
9591 PROMPT_CONTINUE, 0 },
9592
9593 /* Error allocating new directory block */
9594 { PR_2_ALLOC_DIRBOCK,
9595 N_("@A new @d @b for @i %i (%s): %m\n"),
9596 PROMPT_NONE, 0 },
9597
9598 /* Error deallocating inode */
9599 { PR_2_DEALLOC_INODE,
9600 N_("Error deallocating @i %i: %m\n"),
9601 PROMPT_NONE, PR_FATAL },
9602
9603 /* Directory entry for '.' is big. Split? */
9604 { PR_2_SPLIT_DOT,
9605 N_("@d @e for '.' is big. "),
9606 PROMPT_SPLIT, PR_NO_OK },
9607
9608 /* Illegal FIFO inode */
9609 { PR_2_BAD_FIFO,
9610 N_("@i %i (%Q) is an @I FIFO.\n"),
9611 PROMPT_CLEAR, 0 },
9612
9613 /* Illegal socket inode */
9614 { PR_2_BAD_SOCKET,
9615 N_("@i %i (%Q) is an @I socket.\n"),
9616 PROMPT_CLEAR, 0 },
9617
9618 /* Directory filetype not set */
9619 { PR_2_SET_FILETYPE,
9620 N_("Setting filetype for @E to %N.\n"),
9621 PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
9622
9623 /* Directory filetype incorrect */
9624 { PR_2_BAD_FILETYPE,
Mike Frysinger874af852006-03-08 07:03:27 +00009625 N_("@E has an incorrect filetype (was %Dt, @s %N).\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009626 PROMPT_FIX, 0 },
9627
9628 /* Directory filetype set on filesystem */
9629 { PR_2_CLEAR_FILETYPE,
9630 N_("@E has filetype set.\n"),
9631 PROMPT_CLEAR, PR_PREEN_OK },
9632
9633 /* Directory filename is null */
9634 { PR_2_NULL_NAME,
Mike Frysinger874af852006-03-08 07:03:27 +00009635 N_("@E has a @z name.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009636 PROMPT_CLEAR, 0 },
9637
9638 /* Invalid symlink */
9639 { PR_2_INVALID_SYMLINK,
Mike Frysinger874af852006-03-08 07:03:27 +00009640 N_("Symlink %Q (@i #%i) is @n.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009641 PROMPT_CLEAR, 0 },
9642
9643 /* i_file_acl (extended attribute block) is bad */
9644 { PR_2_FILE_ACL_BAD,
Mike Frysinger874af852006-03-08 07:03:27 +00009645 N_("@a @b @F @n (%If).\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009646 PROMPT_CLEAR, 0 },
9647
9648 /* Filesystem contains large files, but has no such flag in sb */
9649 { PR_2_FEATURE_LARGE_FILES,
9650 N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
9651 PROMPT_FIX, 0 },
9652
9653 /* Node in HTREE directory not referenced */
9654 { PR_2_HTREE_NOTREF,
9655 N_("@p @h %d: node (%B) not referenced\n"),
9656 PROMPT_NONE, 0 },
9657
9658 /* Node in HTREE directory referenced twice */
9659 { PR_2_HTREE_DUPREF,
9660 N_("@p @h %d: node (%B) referenced twice\n"),
9661 PROMPT_NONE, 0 },
9662
9663 /* Node in HTREE directory has bad min hash */
9664 { PR_2_HTREE_MIN_HASH,
9665 N_("@p @h %d: node (%B) has bad min hash\n"),
9666 PROMPT_NONE, 0 },
9667
9668 /* Node in HTREE directory has bad max hash */
9669 { PR_2_HTREE_MAX_HASH,
9670 N_("@p @h %d: node (%B) has bad max hash\n"),
9671 PROMPT_NONE, 0 },
9672
9673 /* Clear invalid HTREE directory */
9674 { PR_2_HTREE_CLEAR,
Mike Frysinger874af852006-03-08 07:03:27 +00009675 N_("@n @h %d (%q). "), PROMPT_CLEAR, 0 },
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009676
9677 /* Bad block in htree interior node */
9678 { PR_2_HTREE_BADBLK,
9679 N_("@p @h %d (%q): bad @b number %b.\n"),
9680 PROMPT_CLEAR_HTREE, 0 },
9681
9682 /* Error adjusting EA refcount */
9683 { PR_2_ADJ_EA_REFCOUNT,
Mike Frysinger874af852006-03-08 07:03:27 +00009684 N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009685 PROMPT_NONE, PR_FATAL },
9686
9687 /* Invalid HTREE root node */
9688 { PR_2_HTREE_BAD_ROOT,
Mike Frysinger874af852006-03-08 07:03:27 +00009689 N_("@p @h %d: root node is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009690 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9691
9692 /* Invalid HTREE limit */
9693 { PR_2_HTREE_BAD_LIMIT,
Mike Frysinger874af852006-03-08 07:03:27 +00009694 N_("@p @h %d: node (%B) has @n limit (%N)\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009695 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9696
9697 /* Invalid HTREE count */
9698 { PR_2_HTREE_BAD_COUNT,
Mike Frysinger874af852006-03-08 07:03:27 +00009699 N_("@p @h %d: node (%B) has @n count (%N)\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009700 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9701
9702 /* HTREE interior node has out-of-order hashes in table */
9703 { PR_2_HTREE_HASH_ORDER,
9704 N_("@p @h %d: node (%B) has an unordered hash table\n"),
9705 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9706
Mike Frysinger874af852006-03-08 07:03:27 +00009707 /* Node in HTREE directory has invalid depth */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009708 { PR_2_HTREE_BAD_DEPTH,
Mike Frysinger874af852006-03-08 07:03:27 +00009709 N_("@p @h %d: node (%B) has @n depth\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009710 PROMPT_NONE, 0 },
9711
9712 /* Duplicate directory entry found */
9713 { PR_2_DUPLICATE_DIRENT,
9714 N_("Duplicate @E found. "),
9715 PROMPT_CLEAR, 0 },
9716
9717 /* Non-unique filename found */
9718 { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
9719 N_("@E has a non-unique filename.\nRename to %s"),
9720 PROMPT_NULL, 0 },
9721
9722 /* Duplicate directory entry found */
9723 { PR_2_REPORT_DUP_DIRENT,
9724 N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
9725 PROMPT_NONE, 0 },
9726
9727 /* Pass 3 errors */
9728
9729 /* Pass 3: Checking directory connectivity */
9730 { PR_3_PASS_HEADER,
9731 N_("Pass 3: Checking @d connectivity\n"),
9732 PROMPT_NONE, 0 },
9733
9734 /* Root inode not allocated */
9735 { PR_3_NO_ROOT_INODE,
9736 N_("@r not allocated. "),
9737 PROMPT_ALLOCATE, 0 },
9738
9739 /* No room in lost+found */
9740 { PR_3_EXPAND_LF_DIR,
9741 N_("No room in @l @d. "),
9742 PROMPT_EXPAND, 0 },
9743
9744 /* Unconnected directory inode */
9745 { PR_3_UNCONNECTED_DIR,
9746 N_("Unconnected @d @i %i (%p)\n"),
9747 PROMPT_CONNECT, 0 },
9748
9749 /* /lost+found not found */
9750 { PR_3_NO_LF_DIR,
9751 N_("/@l not found. "),
9752 PROMPT_CREATE, PR_PREEN_OK },
9753
9754 /* .. entry is incorrect */
9755 { PR_3_BAD_DOT_DOT,
9756 N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
9757 PROMPT_FIX, 0 },
9758
9759 /* Bad or non-existent /lost+found. Cannot reconnect */
9760 { PR_3_NO_LPF,
9761 N_("Bad or non-existent /@l. Cannot reconnect.\n"),
9762 PROMPT_NONE, 0 },
9763
9764 /* Could not expand /lost+found */
9765 { PR_3_CANT_EXPAND_LPF,
9766 N_("Could not expand /@l: %m\n"),
9767 PROMPT_NONE, 0 },
9768
9769 /* Could not reconnect inode */
9770 { PR_3_CANT_RECONNECT,
9771 N_("Could not reconnect %i: %m\n"),
9772 PROMPT_NONE, 0 },
9773
9774 /* Error while trying to find /lost+found */
9775 { PR_3_ERR_FIND_LPF,
9776 N_("Error while trying to find /@l: %m\n"),
9777 PROMPT_NONE, 0 },
9778
9779 /* Error in ext2fs_new_block while creating /lost+found */
9780 { PR_3_ERR_LPF_NEW_BLOCK,
9781 N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
9782 PROMPT_NONE, 0 },
9783
9784 /* Error in ext2fs_new_inode while creating /lost+found */
9785 { PR_3_ERR_LPF_NEW_INODE,
9786 N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
9787 PROMPT_NONE, 0 },
9788
9789 /* Error in ext2fs_new_dir_block while creating /lost+found */
9790 { PR_3_ERR_LPF_NEW_DIR_BLOCK,
9791 N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
9792 PROMPT_NONE, 0 },
9793
9794 /* Error while writing directory block for /lost+found */
9795 { PR_3_ERR_LPF_WRITE_BLOCK,
9796 N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
9797 PROMPT_NONE, 0 },
9798
9799 /* Error while adjusting inode count */
9800 { PR_3_ADJUST_INODE,
9801 N_("Error while adjusting @i count on @i %i\n"),
9802 PROMPT_NONE, 0 },
9803
9804 /* Couldn't fix parent directory -- error */
9805 { PR_3_FIX_PARENT_ERR,
9806 N_("Couldn't fix parent of @i %i: %m\n\n"),
9807 PROMPT_NONE, 0 },
9808
9809 /* Couldn't fix parent directory -- couldn't find it */
9810 { PR_3_FIX_PARENT_NOFIND,
Mike Frysinger874af852006-03-08 07:03:27 +00009811 N_("Couldn't fix parent of @i %i: Couldn't find parent @d @e\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009812 PROMPT_NONE, 0 },
9813
9814 /* Error allocating inode bitmap */
9815 { PR_3_ALLOCATE_IBITMAP_ERROR,
9816 N_("@A @i @B (%N): %m\n"),
9817 PROMPT_NONE, PR_FATAL },
9818
9819 /* Error creating root directory */
9820 { PR_3_CREATE_ROOT_ERROR,
9821 N_("Error creating root @d (%s): %m\n"),
9822 PROMPT_NONE, PR_FATAL },
9823
9824 /* Error creating lost and found directory */
9825 { PR_3_CREATE_LPF_ERROR,
9826 N_("Error creating /@l @d (%s): %m\n"),
9827 PROMPT_NONE, PR_FATAL },
9828
9829 /* Root inode is not directory; aborting */
9830 { PR_3_ROOT_NOT_DIR_ABORT,
9831 N_("@r is not a @d; aborting.\n"),
9832 PROMPT_NONE, PR_FATAL },
9833
9834 /* Cannot proceed without a root inode. */
9835 { PR_3_NO_ROOT_INODE_ABORT,
9836 N_("Cannot proceed without a @r.\n"),
9837 PROMPT_NONE, PR_FATAL },
9838
9839 /* Internal error: couldn't find dir_info */
9840 { PR_3_NO_DIRINFO,
9841 N_("Internal error: couldn't find dir_info for %i.\n"),
9842 PROMPT_NONE, PR_FATAL },
9843
9844 /* Lost+found not a directory */
9845 { PR_3_LPF_NOTDIR,
9846 N_("/@l is not a @d (ino=%i)\n"),
9847 PROMPT_UNLINK, 0 },
9848
9849 /* Pass 3A Directory Optimization */
9850
9851 /* Pass 3A: Optimizing directories */
9852 { PR_3A_PASS_HEADER,
9853 N_("Pass 3A: Optimizing directories\n"),
9854 PROMPT_NONE, PR_PREEN_NOMSG },
9855
9856 /* Error iterating over directories */
9857 { PR_3A_OPTIMIZE_ITER,
9858 N_("Failed to create dirs_to_hash iterator: %m"),
9859 PROMPT_NONE, 0 },
9860
9861 /* Error rehash directory */
9862 { PR_3A_OPTIMIZE_DIR_ERR,
9863 N_("Failed to optimize directory %q (%d): %m"),
9864 PROMPT_NONE, 0 },
9865
9866 /* Rehashing dir header */
9867 { PR_3A_OPTIMIZE_DIR_HEADER,
9868 N_("Optimizing directories: "),
9869 PROMPT_NONE, PR_MSG_ONLY },
9870
9871 /* Rehashing directory %d */
9872 { PR_3A_OPTIMIZE_DIR,
9873 " %d",
9874 PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
9875
9876 /* Rehashing dir end */
9877 { PR_3A_OPTIMIZE_DIR_END,
9878 "\n",
9879 PROMPT_NONE, PR_PREEN_NOHDR },
9880
9881 /* Pass 4 errors */
9882
9883 /* Pass 4: Checking reference counts */
9884 { PR_4_PASS_HEADER,
9885 N_("Pass 4: Checking reference counts\n"),
9886 PROMPT_NONE, 0 },
9887
9888 /* Unattached zero-length inode */
9889 { PR_4_ZERO_LEN_INODE,
Mike Frysinger874af852006-03-08 07:03:27 +00009890 N_("@u @z @i %i. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009891 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
9892
9893 /* Unattached inode */
9894 { PR_4_UNATTACHED_INODE,
Mike Frysinger874af852006-03-08 07:03:27 +00009895 N_("@u @i %i\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009896 PROMPT_CONNECT, 0 },
9897
9898 /* Inode ref count wrong */
9899 { PR_4_BAD_REF_COUNT,
9900 N_("@i %i ref count is %Il, @s %N. "),
9901 PROMPT_FIX, PR_PREEN_OK },
9902
9903 { PR_4_INCONSISTENT_COUNT,
9904 N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
9905 "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
9906 "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
Mike Frysinger874af852006-03-08 07:03:27 +00009907 "They @s the same!\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009908 PROMPT_NONE, 0 },
9909
9910 /* Pass 5 errors */
9911
9912 /* Pass 5: Checking group summary information */
9913 { PR_5_PASS_HEADER,
9914 N_("Pass 5: Checking @g summary information\n"),
9915 PROMPT_NONE, 0 },
9916
9917 /* Padding at end of inode bitmap is not set. */
9918 { PR_5_INODE_BMAP_PADDING,
9919 N_("Padding at end of @i @B is not set. "),
9920 PROMPT_FIX, PR_PREEN_OK },
9921
9922 /* Padding at end of block bitmap is not set. */
9923 { PR_5_BLOCK_BMAP_PADDING,
9924 N_("Padding at end of @b @B is not set. "),
9925 PROMPT_FIX, PR_PREEN_OK },
9926
9927 /* Block bitmap differences header */
9928 { PR_5_BLOCK_BITMAP_HEADER,
9929 N_("@b @B differences: "),
9930 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
9931
9932 /* Block not used, but marked in bitmap */
9933 { PR_5_BLOCK_UNUSED,
9934 " -%b",
9935 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9936
9937 /* Block used, but not marked used in bitmap */
9938 { PR_5_BLOCK_USED,
9939 " +%b",
9940 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9941
9942 /* Block bitmap differences end */
9943 { PR_5_BLOCK_BITMAP_END,
9944 "\n",
9945 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9946
9947 /* Inode bitmap differences header */
9948 { PR_5_INODE_BITMAP_HEADER,
9949 N_("@i @B differences: "),
9950 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
9951
9952 /* Inode not used, but marked in bitmap */
9953 { PR_5_INODE_UNUSED,
9954 " -%i",
9955 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9956
9957 /* Inode used, but not marked used in bitmap */
9958 { PR_5_INODE_USED,
9959 " +%i",
9960 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9961
9962 /* Inode bitmap differences end */
9963 { PR_5_INODE_BITMAP_END,
9964 "\n",
9965 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9966
9967 /* Free inodes count for group wrong */
9968 { PR_5_FREE_INODE_COUNT_GROUP,
9969 N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
9970 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9971
9972 /* Directories count for group wrong */
9973 { PR_5_FREE_DIR_COUNT_GROUP,
9974 N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
9975 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9976
9977 /* Free inodes count wrong */
9978 { PR_5_FREE_INODE_COUNT,
9979 N_("Free @is count wrong (%i, counted=%j).\n"),
9980 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9981
9982 /* Free blocks count for group wrong */
9983 { PR_5_FREE_BLOCK_COUNT_GROUP,
9984 N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
9985 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9986
9987 /* Free blocks count wrong */
9988 { PR_5_FREE_BLOCK_COUNT,
9989 N_("Free @bs count wrong (%b, counted=%c).\n"),
9990 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9991
9992 /* Programming error: bitmap endpoints don't match */
9993 { PR_5_BMAP_ENDPOINTS,
9994 N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
9995 "match calculated @B endpoints (%i, %j)\n"),
9996 PROMPT_NONE, PR_FATAL },
9997
9998 /* Internal error: fudging end of bitmap */
9999 { PR_5_FUDGE_BITMAP_ERROR,
10000 N_("Internal error: fudging end of bitmap (%N)\n"),
10001 PROMPT_NONE, PR_FATAL },
10002
10003 /* Error copying in replacement inode bitmap */
10004 { PR_5_COPY_IBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +000010005 N_("Error copying in replacement @i @B: %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010006 PROMPT_NONE, PR_FATAL },
10007
10008 /* Error copying in replacement block bitmap */
10009 { PR_5_COPY_BBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +000010010 N_("Error copying in replacement @b @B: %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010011 PROMPT_NONE, PR_FATAL },
10012
10013 /* Block range not used, but marked in bitmap */
10014 { PR_5_BLOCK_RANGE_UNUSED,
10015 " -(%b--%c)",
10016 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
10017
10018 /* Block range used, but not marked used in bitmap */
10019 { PR_5_BLOCK_RANGE_USED,
10020 " +(%b--%c)",
10021 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
10022
10023 /* Inode range not used, but marked in bitmap */
10024 { PR_5_INODE_RANGE_UNUSED,
10025 " -(%i--%j)",
10026 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
10027
10028 /* Inode range used, but not marked used in bitmap */
10029 { PR_5_INODE_RANGE_USED,
10030 " +(%i--%j)",
10031 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
10032
10033 { 0 }
10034};
10035
10036/*
10037 * This is the latch flags register. It allows several problems to be
10038 * "latched" together. This means that the user has to answer but one
10039 * question for the set of problems, and all of the associated
10040 * problems will be either fixed or not fixed.
10041 */
10042static struct latch_descr pr_latch_info[] = {
10043 { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
10044 { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
10045 { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
10046 { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
10047 { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
10048 { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
10049 { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
10050 { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
10051 { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
10052 { -1, 0, 0 },
10053};
10054
10055static const struct e2fsck_problem *find_problem(problem_t code)
10056{
10057 int i;
10058
10059 for (i=0; problem_table[i].e2p_code; i++) {
10060 if (problem_table[i].e2p_code == code)
10061 return &problem_table[i];
10062 }
10063 return 0;
10064}
10065
10066static struct latch_descr *find_latch(int code)
10067{
10068 int i;
10069
10070 for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
10071 if (pr_latch_info[i].latch_code == code)
10072 return &pr_latch_info[i];
10073 }
10074 return 0;
10075}
10076
10077int end_problem_latch(e2fsck_t ctx, int mask)
10078{
10079 struct latch_descr *ldesc;
10080 struct problem_context pctx;
10081 int answer = -1;
10082
10083 ldesc = find_latch(mask);
10084 if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
10085 clear_problem_context(&pctx);
10086 answer = fix_problem(ctx, ldesc->end_message, &pctx);
10087 }
10088 ldesc->flags &= ~(PRL_VARIABLE);
10089 return answer;
10090}
10091
10092int set_latch_flags(int mask, int setflags, int clearflags)
10093{
10094 struct latch_descr *ldesc;
10095
10096 ldesc = find_latch(mask);
10097 if (!ldesc)
10098 return -1;
10099 ldesc->flags |= setflags;
10100 ldesc->flags &= ~clearflags;
10101 return 0;
10102}
10103
10104void clear_problem_context(struct problem_context *ctx)
10105{
10106 memset(ctx, 0, sizeof(struct problem_context));
10107 ctx->blkcount = -1;
10108 ctx->group = -1;
10109}
10110
10111int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
10112{
10113 ext2_filsys fs = ctx->fs;
10114 const struct e2fsck_problem *ptr;
10115 struct latch_descr *ldesc = 0;
10116 const char *message;
10117 int def_yn, answer, ans;
10118 int print_answer = 0;
10119 int suppress = 0;
10120
10121 ptr = find_problem(code);
10122 if (!ptr) {
10123 printf(_("Unhandled error code (0x%x)!\n"), code);
10124 return 0;
10125 }
10126 def_yn = 1;
10127 if ((ptr->flags & PR_NO_DEFAULT) ||
10128 ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
10129 (ctx->options & E2F_OPT_NO))
10130 def_yn= 0;
10131
10132 /*
10133 * Do special latch processing. This is where we ask the
10134 * latch question, if it exists
10135 */
10136 if (ptr->flags & PR_LATCH_MASK) {
10137 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
10138 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
10139 ans = fix_problem(ctx, ldesc->question, pctx);
10140 if (ans == 1)
10141 ldesc->flags |= PRL_YES;
10142 if (ans == 0)
10143 ldesc->flags |= PRL_NO;
10144 ldesc->flags |= PRL_LATCHED;
10145 }
10146 if (ldesc->flags & PRL_SUPPRESS)
10147 suppress++;
10148 }
10149 if ((ptr->flags & PR_PREEN_NOMSG) &&
10150 (ctx->options & E2F_OPT_PREEN))
10151 suppress++;
10152 if ((ptr->flags & PR_NO_NOMSG) &&
10153 (ctx->options & E2F_OPT_NO))
10154 suppress++;
10155 if (!suppress) {
10156 message = ptr->e2p_description;
10157 if ((ctx->options & E2F_OPT_PREEN) &&
10158 !(ptr->flags & PR_PREEN_NOHDR)) {
10159 printf("%s: ", ctx->device_name ?
10160 ctx->device_name : ctx->filesystem_name);
10161 }
10162 if (*message)
10163 print_e2fsck_message(ctx, _(message), pctx, 1);
10164 }
10165 if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
10166 preenhalt(ctx);
10167
10168 if (ptr->flags & PR_FATAL)
10169 fatal_error(ctx, 0);
10170
10171 if (ptr->prompt == PROMPT_NONE) {
10172 if (ptr->flags & PR_NOCOLLATE)
10173 answer = -1;
10174 else
10175 answer = def_yn;
10176 } else {
10177 if (ctx->options & E2F_OPT_PREEN) {
10178 answer = def_yn;
10179 if (!(ptr->flags & PR_PREEN_NOMSG))
10180 print_answer = 1;
10181 } else if ((ptr->flags & PR_LATCH_MASK) &&
10182 (ldesc->flags & (PRL_YES | PRL_NO))) {
10183 if (!suppress)
10184 print_answer = 1;
10185 if (ldesc->flags & PRL_YES)
10186 answer = 1;
10187 else
10188 answer = 0;
10189 } else
10190 answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
10191 if (!answer && !(ptr->flags & PR_NO_OK))
10192 ext2fs_unmark_valid(fs);
10193
10194 if (print_answer)
10195 printf("%s.\n", answer ?
10196 _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
10197
10198 }
10199
10200 if ((ptr->prompt == PROMPT_ABORT) && answer)
10201 fatal_error(ctx, 0);
10202
10203 if (ptr->flags & PR_AFTER_CODE)
10204 answer = fix_problem(ctx, ptr->second_code, pctx);
10205
10206 return answer;
10207}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010208
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010209/*
10210 * linux/fs/recovery.c
10211 *
10212 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010213 */
10214
10215/*
10216 * Maintain information about the progress of the recovery job, so that
10217 * the different passes can carry information between them.
10218 */
10219struct recovery_info
10220{
10221 tid_t start_transaction;
10222 tid_t end_transaction;
10223
10224 int nr_replays;
10225 int nr_revokes;
10226 int nr_revoke_hits;
10227};
10228
10229enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
10230static int do_one_pass(journal_t *journal,
10231 struct recovery_info *info, enum passtype pass);
10232static int scan_revoke_records(journal_t *, struct buffer_head *,
10233 tid_t, struct recovery_info *);
10234
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010235/*
10236 * Read a block from the journal
10237 */
10238
10239static int jread(struct buffer_head **bhp, journal_t *journal,
10240 unsigned int offset)
10241{
10242 int err;
10243 unsigned long blocknr;
10244 struct buffer_head *bh;
10245
10246 *bhp = NULL;
10247
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010248 err = journal_bmap(journal, offset, &blocknr);
10249
10250 if (err) {
Rob Landley43ac8882006-04-01 00:40:33 +000010251 printf ("JBD: bad block at offset %u\n", offset);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010252 return err;
10253 }
10254
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010255 bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010256 if (!bh)
10257 return -ENOMEM;
10258
10259 if (!buffer_uptodate(bh)) {
10260 /* If this is a brand new buffer, start readahead.
10261 Otherwise, we assume we are already reading it. */
10262 if (!buffer_req(bh))
10263 do_readahead(journal, offset);
10264 wait_on_buffer(bh);
10265 }
10266
10267 if (!buffer_uptodate(bh)) {
Rob Landley43ac8882006-04-01 00:40:33 +000010268 printf ("JBD: Failed to read block at offset %u\n", offset);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010269 brelse(bh);
10270 return -EIO;
10271 }
10272
10273 *bhp = bh;
10274 return 0;
10275}
10276
10277
10278/*
10279 * Count the number of in-use tags in a journal descriptor block.
10280 */
10281
10282static int count_tags(struct buffer_head *bh, int size)
10283{
10284 char * tagp;
10285 journal_block_tag_t * tag;
10286 int nr = 0;
10287
10288 tagp = &bh->b_data[sizeof(journal_header_t)];
10289
10290 while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
10291 tag = (journal_block_tag_t *) tagp;
10292
10293 nr++;
10294 tagp += sizeof(journal_block_tag_t);
10295 if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
10296 tagp += 16;
10297
10298 if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
10299 break;
10300 }
10301
10302 return nr;
10303}
10304
10305
10306/* Make sure we wrap around the log correctly! */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000010307#define wrap(journal, var) \
10308do { \
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010309 if (var >= (journal)->j_last) \
10310 var -= ((journal)->j_last - (journal)->j_first); \
10311} while (0)
10312
10313/**
10314 * int journal_recover(journal_t *journal) - recovers a on-disk journal
10315 * @journal: the journal to recover
10316 *
10317 * The primary function for recovering the log contents when mounting a
10318 * journaled device.
10319 *
10320 * Recovery is done in three passes. In the first pass, we look for the
10321 * end of the log. In the second, we assemble the list of revoke
10322 * blocks. In the third and final pass, we replay any un-revoked blocks
10323 * in the log.
10324 */
10325int journal_recover(journal_t *journal)
10326{
10327 int err;
10328 journal_superblock_t * sb;
10329
10330 struct recovery_info info;
10331
10332 memset(&info, 0, sizeof(info));
10333 sb = journal->j_superblock;
10334
10335 /*
10336 * The journal superblock's s_start field (the current log head)
10337 * is always zero if, and only if, the journal was cleanly
10338 * unmounted.
10339 */
10340
10341 if (!sb->s_start) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010342 journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
10343 return 0;
10344 }
10345
10346 err = do_one_pass(journal, &info, PASS_SCAN);
10347 if (!err)
10348 err = do_one_pass(journal, &info, PASS_REVOKE);
10349 if (!err)
10350 err = do_one_pass(journal, &info, PASS_REPLAY);
10351
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010352 /* Restart the log at the next transaction ID, thus invalidating
10353 * any existing commit records in the log. */
10354 journal->j_transaction_sequence = ++info.end_transaction;
10355
10356 journal_clear_revoke(journal);
10357 sync_blockdev(journal->j_fs_dev);
10358 return err;
10359}
10360
10361static int do_one_pass(journal_t *journal,
10362 struct recovery_info *info, enum passtype pass)
10363{
10364 unsigned int first_commit_ID, next_commit_ID;
10365 unsigned long next_log_block;
10366 int err, success = 0;
10367 journal_superblock_t * sb;
10368 journal_header_t * tmp;
10369 struct buffer_head * bh;
10370 unsigned int sequence;
10371 int blocktype;
10372
10373 /* Precompute the maximum metadata descriptors in a descriptor block */
10374 int MAX_BLOCKS_PER_DESC;
10375 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
10376 / sizeof(journal_block_tag_t));
10377
10378 /*
10379 * First thing is to establish what we expect to find in the log
10380 * (in terms of transaction IDs), and where (in terms of log
10381 * block offsets): query the superblock.
10382 */
10383
10384 sb = journal->j_superblock;
10385 next_commit_ID = ntohl(sb->s_sequence);
10386 next_log_block = ntohl(sb->s_start);
10387
10388 first_commit_ID = next_commit_ID;
10389 if (pass == PASS_SCAN)
10390 info->start_transaction = first_commit_ID;
10391
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010392 /*
10393 * Now we walk through the log, transaction by transaction,
10394 * making sure that each transaction has a commit block in the
10395 * expected place. Each complete transaction gets replayed back
10396 * into the main filesystem.
10397 */
10398
10399 while (1) {
10400 int flags;
10401 char * tagp;
10402 journal_block_tag_t * tag;
10403 struct buffer_head * obh;
10404 struct buffer_head * nbh;
10405
10406 /* If we already know where to stop the log traversal,
10407 * check right now that we haven't gone past the end of
10408 * the log. */
10409
10410 if (pass != PASS_SCAN)
10411 if (tid_geq(next_commit_ID, info->end_transaction))
10412 break;
10413
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010414 /* Skip over each chunk of the transaction looking
10415 * either the next descriptor block or the final commit
10416 * record. */
10417
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010418 err = jread(&bh, journal, next_log_block);
10419 if (err)
10420 goto failed;
10421
10422 next_log_block++;
10423 wrap(journal, next_log_block);
10424
10425 /* What kind of buffer is it?
10426 *
10427 * If it is a descriptor block, check that it has the
10428 * expected sequence number. Otherwise, we're all done
10429 * here. */
10430
10431 tmp = (journal_header_t *)bh->b_data;
10432
10433 if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
10434 brelse(bh);
10435 break;
10436 }
10437
10438 blocktype = ntohl(tmp->h_blocktype);
10439 sequence = ntohl(tmp->h_sequence);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010440
10441 if (sequence != next_commit_ID) {
10442 brelse(bh);
10443 break;
10444 }
10445
10446 /* OK, we have a valid descriptor block which matches
10447 * all of the sequence number checks. What are we going
10448 * to do with it? That depends on the pass... */
10449
10450 switch(blocktype) {
10451 case JFS_DESCRIPTOR_BLOCK:
10452 /* If it is a valid descriptor block, replay it
10453 * in pass REPLAY; otherwise, just skip over the
10454 * blocks it describes. */
10455 if (pass != PASS_REPLAY) {
10456 next_log_block +=
10457 count_tags(bh, journal->j_blocksize);
10458 wrap(journal, next_log_block);
10459 brelse(bh);
10460 continue;
10461 }
10462
10463 /* A descriptor block: we can now write all of
10464 * the data blocks. Yay, useful work is finally
10465 * getting done here! */
10466
10467 tagp = &bh->b_data[sizeof(journal_header_t)];
10468 while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
10469 <= journal->j_blocksize) {
10470 unsigned long io_block;
10471
10472 tag = (journal_block_tag_t *) tagp;
10473 flags = ntohl(tag->t_flags);
10474
10475 io_block = next_log_block++;
10476 wrap(journal, next_log_block);
10477 err = jread(&obh, journal, io_block);
10478 if (err) {
10479 /* Recover what we can, but
10480 * report failure at the end. */
10481 success = err;
Rob Landley43ac8882006-04-01 00:40:33 +000010482 printf ("JBD: IO error %d recovering "
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010483 "block %ld in log\n",
10484 err, io_block);
10485 } else {
10486 unsigned long blocknr;
10487
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010488 blocknr = ntohl(tag->t_blocknr);
10489
10490 /* If the block has been
10491 * revoked, then we're all done
10492 * here. */
10493 if (journal_test_revoke
10494 (journal, blocknr,
10495 next_commit_ID)) {
10496 brelse(obh);
10497 ++info->nr_revoke_hits;
10498 goto skip_write;
10499 }
10500
10501 /* Find a buffer for the new
10502 * data being restored */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010503 nbh = getblk(journal->j_fs_dev,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010504 blocknr,
10505 journal->j_blocksize);
10506 if (nbh == NULL) {
Rob Landley43ac8882006-04-01 00:40:33 +000010507 printf ("JBD: Out of memory "
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010508 "during recovery.\n");
10509 err = -ENOMEM;
10510 brelse(bh);
10511 brelse(obh);
10512 goto failed;
10513 }
10514
10515 lock_buffer(nbh);
10516 memcpy(nbh->b_data, obh->b_data,
10517 journal->j_blocksize);
10518 if (flags & JFS_FLAG_ESCAPE) {
10519 *((unsigned int *)bh->b_data) =
10520 htonl(JFS_MAGIC_NUMBER);
10521 }
10522
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010523 mark_buffer_uptodate(nbh, 1);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010524 mark_buffer_dirty(nbh);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010525 ++info->nr_replays;
10526 /* ll_rw_block(WRITE, 1, &nbh); */
10527 unlock_buffer(nbh);
10528 brelse(obh);
10529 brelse(nbh);
10530 }
10531
10532 skip_write:
10533 tagp += sizeof(journal_block_tag_t);
10534 if (!(flags & JFS_FLAG_SAME_UUID))
10535 tagp += 16;
10536
10537 if (flags & JFS_FLAG_LAST_TAG)
10538 break;
10539 }
10540
10541 brelse(bh);
10542 continue;
10543
10544 case JFS_COMMIT_BLOCK:
10545 /* Found an expected commit block: not much to
10546 * do other than move on to the next sequence
10547 * number. */
10548 brelse(bh);
10549 next_commit_ID++;
10550 continue;
10551
10552 case JFS_REVOKE_BLOCK:
10553 /* If we aren't in the REVOKE pass, then we can
10554 * just skip over this block. */
10555 if (pass != PASS_REVOKE) {
10556 brelse(bh);
10557 continue;
10558 }
10559
10560 err = scan_revoke_records(journal, bh,
10561 next_commit_ID, info);
10562 brelse(bh);
10563 if (err)
10564 goto failed;
10565 continue;
10566
10567 default:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010568 goto done;
10569 }
10570 }
10571
10572 done:
10573 /*
10574 * We broke out of the log scan loop: either we came to the
10575 * known end of the log or we found an unexpected block in the
10576 * log. If the latter happened, then we know that the "current"
10577 * transaction marks the end of the valid log.
10578 */
10579
10580 if (pass == PASS_SCAN)
10581 info->end_transaction = next_commit_ID;
10582 else {
10583 /* It's really bad news if different passes end up at
10584 * different places (but possible due to IO errors). */
10585 if (info->end_transaction != next_commit_ID) {
Rob Landley43ac8882006-04-01 00:40:33 +000010586 printf ("JBD: recovery pass %d ended at "
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010587 "transaction %u, expected %u\n",
10588 pass, next_commit_ID, info->end_transaction);
10589 if (!success)
10590 success = -EIO;
10591 }
10592 }
10593
10594 return success;
10595
10596 failed:
10597 return err;
10598}
10599
10600
10601/* Scan a revoke record, marking all blocks mentioned as revoked. */
10602
10603static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
10604 tid_t sequence, struct recovery_info *info)
10605{
10606 journal_revoke_header_t *header;
10607 int offset, max;
10608
10609 header = (journal_revoke_header_t *) bh->b_data;
10610 offset = sizeof(journal_revoke_header_t);
10611 max = ntohl(header->r_count);
10612
10613 while (offset < max) {
10614 unsigned long blocknr;
10615 int err;
10616
10617 blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
10618 offset += 4;
10619 err = journal_set_revoke(journal, blocknr, sequence);
10620 if (err)
10621 return err;
10622 ++info->nr_revokes;
10623 }
10624 return 0;
10625}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010626
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010627
10628/*
10629 * rehash.c --- rebuild hash tree directories
10630 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010631 * This algorithm is designed for simplicity of implementation and to
10632 * pack the directory as much as possible. It however requires twice
10633 * as much memory as the size of the directory. The maximum size
10634 * directory supported using a 4k blocksize is roughly a gigabyte, and
10635 * so there may very well be problems with machines that don't have
10636 * virtual memory, and obscenely large directories.
10637 *
10638 * An alternate algorithm which is much more disk intensive could be
10639 * written, and probably will need to be written in the future. The
10640 * design goals of such an algorithm are: (a) use (roughly) constant
10641 * amounts of memory, no matter how large the directory, (b) the
10642 * directory must be safe at all times, even if e2fsck is interrupted
10643 * in the middle, (c) we must use minimal amounts of extra disk
10644 * blocks. This pretty much requires an incremental approach, where
10645 * we are reading from one part of the directory, and inserting into
10646 * the front half. So the algorithm will have to keep track of a
10647 * moving block boundary between the new tree and the old tree, and
10648 * files will need to be moved from the old directory and inserted
10649 * into the new tree. If the new directory requires space which isn't
10650 * yet available, blocks from the beginning part of the old directory
10651 * may need to be moved to the end of the directory to make room for
10652 * the new tree:
10653 *
10654 * --------------------------------------------------------
10655 * | new tree | | old tree |
10656 * --------------------------------------------------------
10657 * ^ ptr ^ptr
10658 * tail new head old
10659 *
10660 * This is going to be a pain in the tuckus to implement, and will
10661 * require a lot more disk accesses. So I'm going to skip it for now;
10662 * it's only really going to be an issue for really, really big
10663 * filesystems (when we reach the level of tens of millions of files
10664 * in a single directory). It will probably be easier to simply
10665 * require that e2fsck use VM first.
10666 */
10667
10668struct fill_dir_struct {
10669 char *buf;
10670 struct ext2_inode *inode;
10671 int err;
10672 e2fsck_t ctx;
10673 struct hash_entry *harray;
10674 int max_array, num_array;
10675 int dir_size;
10676 int compress;
10677 ino_t parent;
10678};
10679
10680struct hash_entry {
10681 ext2_dirhash_t hash;
10682 ext2_dirhash_t minor_hash;
10683 struct ext2_dir_entry *dir;
10684};
10685
10686struct out_dir {
10687 int num;
10688 int max;
10689 char *buf;
10690 ext2_dirhash_t *hashes;
10691};
10692
10693static int fill_dir_block(ext2_filsys fs,
10694 blk_t *block_nr,
10695 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000010696 blk_t ref_block FSCK_ATTR((unused)),
10697 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010698 void *priv_data)
10699{
10700 struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
10701 struct hash_entry *new_array, *ent;
10702 struct ext2_dir_entry *dirent;
10703 char *dir;
10704 unsigned int offset, dir_offset;
10705
10706 if (blockcnt < 0)
10707 return 0;
10708
10709 offset = blockcnt * fs->blocksize;
10710 if (offset + fs->blocksize > fd->inode->i_size) {
10711 fd->err = EXT2_ET_DIR_CORRUPTED;
10712 return BLOCK_ABORT;
10713 }
10714 dir = (fd->buf+offset);
10715 if (HOLE_BLKADDR(*block_nr)) {
10716 memset(dir, 0, fs->blocksize);
10717 dirent = (struct ext2_dir_entry *) dir;
10718 dirent->rec_len = fs->blocksize;
10719 } else {
10720 fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
10721 if (fd->err)
10722 return BLOCK_ABORT;
10723 }
10724 /* While the directory block is "hot", index it. */
10725 dir_offset = 0;
10726 while (dir_offset < fs->blocksize) {
10727 dirent = (struct ext2_dir_entry *) (dir + dir_offset);
10728 if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
10729 (dirent->rec_len < 8) ||
10730 ((dirent->rec_len % 4) != 0) ||
10731 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
10732 fd->err = EXT2_ET_DIR_CORRUPTED;
10733 return BLOCK_ABORT;
10734 }
10735 dir_offset += dirent->rec_len;
10736 if (dirent->inode == 0)
10737 continue;
10738 if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
10739 (dirent->name[0] == '.'))
10740 continue;
10741 if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
10742 (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
10743 fd->parent = dirent->inode;
10744 continue;
10745 }
10746 if (fd->num_array >= fd->max_array) {
10747 new_array = realloc(fd->harray,
10748 sizeof(struct hash_entry) * (fd->max_array+500));
10749 if (!new_array) {
10750 fd->err = ENOMEM;
10751 return BLOCK_ABORT;
10752 }
10753 fd->harray = new_array;
10754 fd->max_array += 500;
10755 }
10756 ent = fd->harray + fd->num_array++;
10757 ent->dir = dirent;
10758 fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
10759 if (fd->compress)
10760 ent->hash = ent->minor_hash = 0;
10761 else {
10762 fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
10763 dirent->name,
10764 dirent->name_len & 0xFF,
10765 fs->super->s_hash_seed,
10766 &ent->hash, &ent->minor_hash);
10767 if (fd->err)
10768 return BLOCK_ABORT;
10769 }
10770 }
10771
10772 return 0;
10773}
10774
10775/* Used for sorting the hash entry */
10776static EXT2_QSORT_TYPE name_cmp(const void *a, const void *b)
10777{
10778 const struct hash_entry *he_a = (const struct hash_entry *) a;
10779 const struct hash_entry *he_b = (const struct hash_entry *) b;
10780 int ret;
10781 int min_len;
10782
10783 min_len = he_a->dir->name_len;
10784 if (min_len > he_b->dir->name_len)
10785 min_len = he_b->dir->name_len;
10786
10787 ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
10788 if (ret == 0) {
10789 if (he_a->dir->name_len > he_b->dir->name_len)
10790 ret = 1;
10791 else if (he_a->dir->name_len < he_b->dir->name_len)
10792 ret = -1;
10793 else
10794 ret = he_b->dir->inode - he_a->dir->inode;
10795 }
10796 return ret;
10797}
10798
10799/* Used for sorting the hash entry */
10800static EXT2_QSORT_TYPE hash_cmp(const void *a, const void *b)
10801{
10802 const struct hash_entry *he_a = (const struct hash_entry *) a;
10803 const struct hash_entry *he_b = (const struct hash_entry *) b;
10804 int ret;
10805
10806 if (he_a->hash > he_b->hash)
10807 ret = 1;
10808 else if (he_a->hash < he_b->hash)
10809 ret = -1;
10810 else {
10811 if (he_a->minor_hash > he_b->minor_hash)
10812 ret = 1;
10813 else if (he_a->minor_hash < he_b->minor_hash)
10814 ret = -1;
10815 else
10816 ret = name_cmp(a, b);
10817 }
10818 return ret;
10819}
10820
10821static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
10822 int blocks)
10823{
10824 void *new_mem;
10825
10826 if (outdir->max) {
10827 new_mem = realloc(outdir->buf, blocks * fs->blocksize);
10828 if (!new_mem)
10829 return ENOMEM;
10830 outdir->buf = new_mem;
10831 new_mem = realloc(outdir->hashes,
10832 blocks * sizeof(ext2_dirhash_t));
10833 if (!new_mem)
10834 return ENOMEM;
10835 outdir->hashes = new_mem;
10836 } else {
10837 outdir->buf = malloc(blocks * fs->blocksize);
10838 outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
10839 outdir->num = 0;
10840 }
10841 outdir->max = blocks;
10842 return 0;
10843}
10844
10845static void free_out_dir(struct out_dir *outdir)
10846{
Rob Landleye7c43b62006-03-01 16:39:45 +000010847 free(outdir->buf);
10848 free(outdir->hashes);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010849 outdir->max = 0;
10850 outdir->num =0;
10851}
10852
10853static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
10854 char ** ret)
10855{
10856 errcode_t retval;
10857
10858 if (outdir->num >= outdir->max) {
10859 retval = alloc_size_dir(fs, outdir, outdir->max + 50);
10860 if (retval)
10861 return retval;
10862 }
10863 *ret = outdir->buf + (outdir->num++ * fs->blocksize);
10864 memset(*ret, 0, fs->blocksize);
10865 return 0;
10866}
10867
10868/*
10869 * This function is used to make a unique filename. We do this by
10870 * appending ~0, and then incrementing the number. However, we cannot
10871 * expand the length of the filename beyond the padding available in
10872 * the directory entry.
10873 */
10874static void mutate_name(char *str, __u16 *len)
10875{
10876 int i;
10877 __u16 l = *len & 0xFF, h = *len & 0xff00;
10878
10879 /*
10880 * First check to see if it looks the name has been mutated
10881 * already
10882 */
10883 for (i = l-1; i > 0; i--) {
10884 if (!isdigit(str[i]))
10885 break;
10886 }
10887 if ((i == l-1) || (str[i] != '~')) {
10888 if (((l-1) & 3) < 2)
10889 l += 2;
10890 else
10891 l = (l+3) & ~3;
10892 str[l-2] = '~';
10893 str[l-1] = '0';
10894 *len = l | h;
10895 return;
10896 }
10897 for (i = l-1; i >= 0; i--) {
10898 if (isdigit(str[i])) {
10899 if (str[i] == '9')
10900 str[i] = '0';
10901 else {
10902 str[i]++;
10903 return;
10904 }
10905 continue;
10906 }
10907 if (i == 1) {
10908 if (str[0] == 'z')
10909 str[0] = 'A';
10910 else if (str[0] == 'Z') {
10911 str[0] = '~';
10912 str[1] = '0';
10913 } else
10914 str[0]++;
10915 } else if (i > 0) {
10916 str[i] = '1';
10917 str[i-1] = '~';
10918 } else {
10919 if (str[0] == '~')
10920 str[0] = 'a';
10921 else
10922 str[0]++;
10923 }
10924 break;
10925 }
10926}
10927
10928static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
10929 ext2_ino_t ino,
10930 struct fill_dir_struct *fd)
10931{
10932 struct problem_context pctx;
10933 struct hash_entry *ent, *prev;
10934 int i, j;
10935 int fixed = 0;
10936 char new_name[256];
10937 __u16 new_len;
10938
10939 clear_problem_context(&pctx);
10940 pctx.ino = ino;
10941
10942 for (i=1; i < fd->num_array; i++) {
10943 ent = fd->harray + i;
10944 prev = ent - 1;
10945 if (!ent->dir->inode ||
10946 ((ent->dir->name_len & 0xFF) !=
10947 (prev->dir->name_len & 0xFF)) ||
10948 (strncmp(ent->dir->name, prev->dir->name,
10949 ent->dir->name_len & 0xFF)))
10950 continue;
10951 pctx.dirent = ent->dir;
10952 if ((ent->dir->inode == prev->dir->inode) &&
10953 fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
10954 e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
10955 ent->dir->inode = 0;
10956 fixed++;
10957 continue;
10958 }
10959 memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
10960 new_len = ent->dir->name_len;
10961 mutate_name(new_name, &new_len);
10962 for (j=0; j < fd->num_array; j++) {
10963 if ((i==j) ||
10964 ((ent->dir->name_len & 0xFF) !=
10965 (fd->harray[j].dir->name_len & 0xFF)) ||
10966 (strncmp(new_name, fd->harray[j].dir->name,
10967 new_len & 0xFF)))
10968 continue;
10969 mutate_name(new_name, &new_len);
10970
10971 j = -1;
10972 }
10973 new_name[new_len & 0xFF] = 0;
10974 pctx.str = new_name;
10975 if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
10976 memcpy(ent->dir->name, new_name, new_len & 0xFF);
10977 ent->dir->name_len = new_len;
10978 ext2fs_dirhash(fs->super->s_def_hash_version,
10979 ent->dir->name,
10980 ent->dir->name_len & 0xFF,
10981 fs->super->s_hash_seed,
10982 &ent->hash, &ent->minor_hash);
10983 fixed++;
10984 }
10985 }
10986 return fixed;
10987}
10988
10989
10990static errcode_t copy_dir_entries(ext2_filsys fs,
10991 struct fill_dir_struct *fd,
10992 struct out_dir *outdir)
10993{
10994 errcode_t retval;
10995 char *block_start;
10996 struct hash_entry *ent;
10997 struct ext2_dir_entry *dirent;
10998 int i, rec_len, left;
10999 ext2_dirhash_t prev_hash;
11000 int offset;
11001
11002 outdir->max = 0;
11003 retval = alloc_size_dir(fs, outdir,
11004 (fd->dir_size / fs->blocksize) + 2);
11005 if (retval)
11006 return retval;
11007 outdir->num = fd->compress ? 0 : 1;
11008 offset = 0;
11009 outdir->hashes[0] = 0;
11010 prev_hash = 1;
11011 if ((retval = get_next_block(fs, outdir, &block_start)))
11012 return retval;
11013 dirent = (struct ext2_dir_entry *) block_start;
11014 left = fs->blocksize;
11015 for (i=0; i < fd->num_array; i++) {
11016 ent = fd->harray + i;
11017 if (ent->dir->inode == 0)
11018 continue;
11019 rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
11020 if (rec_len > left) {
11021 if (left)
11022 dirent->rec_len += left;
11023 if ((retval = get_next_block(fs, outdir,
11024 &block_start)))
11025 return retval;
11026 offset = 0;
11027 }
11028 left = fs->blocksize - offset;
11029 dirent = (struct ext2_dir_entry *) (block_start + offset);
11030 if (offset == 0) {
11031 if (ent->hash == prev_hash)
11032 outdir->hashes[outdir->num-1] = ent->hash | 1;
11033 else
11034 outdir->hashes[outdir->num-1] = ent->hash;
11035 }
11036 dirent->inode = ent->dir->inode;
11037 dirent->name_len = ent->dir->name_len;
11038 dirent->rec_len = rec_len;
11039 memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
11040 offset += rec_len;
11041 left -= rec_len;
11042 if (left < 12) {
11043 dirent->rec_len += left;
11044 offset += left;
11045 left = 0;
11046 }
11047 prev_hash = ent->hash;
11048 }
11049 if (left)
11050 dirent->rec_len += left;
11051
11052 return 0;
11053}
11054
11055
11056static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
11057 ext2_ino_t ino, ext2_ino_t parent)
11058{
11059 struct ext2_dir_entry *dir;
11060 struct ext2_dx_root_info *root;
11061 struct ext2_dx_countlimit *limits;
11062 int filetype = 0;
11063
11064 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
11065 filetype = EXT2_FT_DIR << 8;
11066
11067 memset(buf, 0, fs->blocksize);
11068 dir = (struct ext2_dir_entry *) buf;
11069 dir->inode = ino;
11070 dir->name[0] = '.';
11071 dir->name_len = 1 | filetype;
11072 dir->rec_len = 12;
11073 dir = (struct ext2_dir_entry *) (buf + 12);
11074 dir->inode = parent;
11075 dir->name[0] = '.';
11076 dir->name[1] = '.';
11077 dir->name_len = 2 | filetype;
11078 dir->rec_len = fs->blocksize - 12;
11079
11080 root = (struct ext2_dx_root_info *) (buf+24);
11081 root->reserved_zero = 0;
11082 root->hash_version = fs->super->s_def_hash_version;
11083 root->info_length = 8;
11084 root->indirect_levels = 0;
11085 root->unused_flags = 0;
11086
11087 limits = (struct ext2_dx_countlimit *) (buf+32);
11088 limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
11089 limits->count = 0;
11090
11091 return root;
11092}
11093
11094
11095static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
11096{
11097 struct ext2_dir_entry *dir;
11098 struct ext2_dx_countlimit *limits;
11099
11100 memset(buf, 0, fs->blocksize);
11101 dir = (struct ext2_dir_entry *) buf;
11102 dir->inode = 0;
11103 dir->rec_len = fs->blocksize;
11104
11105 limits = (struct ext2_dx_countlimit *) (buf+8);
11106 limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
11107 limits->count = 0;
11108
11109 return (struct ext2_dx_entry *) limits;
11110}
11111
11112/*
11113 * This function takes the leaf nodes which have been written in
11114 * outdir, and populates the root node and any necessary interior nodes.
11115 */
11116static errcode_t calculate_tree(ext2_filsys fs,
11117 struct out_dir *outdir,
11118 ext2_ino_t ino,
11119 ext2_ino_t parent)
11120{
11121 struct ext2_dx_root_info *root_info;
11122 struct ext2_dx_entry *root, *dx_ent = 0;
11123 struct ext2_dx_countlimit *root_limit, *limit;
11124 errcode_t retval;
11125 char * block_start;
11126 int i, c1, c2, nblks;
11127 int limit_offset, root_offset;
11128
11129 root_info = set_root_node(fs, outdir->buf, ino, parent);
11130 root_offset = limit_offset = ((char *) root_info - outdir->buf) +
11131 root_info->info_length;
11132 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
11133 c1 = root_limit->limit;
11134 nblks = outdir->num;
11135
11136 /* Write out the pointer blocks */
11137 if (nblks-1 <= c1) {
11138 /* Just write out the root block, and we're done */
11139 root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
11140 for (i=1; i < nblks; i++) {
11141 root->block = ext2fs_cpu_to_le32(i);
11142 if (i != 1)
11143 root->hash =
11144 ext2fs_cpu_to_le32(outdir->hashes[i]);
11145 root++;
11146 c1--;
11147 }
11148 } else {
11149 c2 = 0;
11150 limit = 0;
11151 root_info->indirect_levels = 1;
11152 for (i=1; i < nblks; i++) {
11153 if (c1 == 0)
11154 return ENOSPC;
11155 if (c2 == 0) {
11156 if (limit)
11157 limit->limit = limit->count =
11158 ext2fs_cpu_to_le16(limit->limit);
11159 root = (struct ext2_dx_entry *)
11160 (outdir->buf + root_offset);
11161 root->block = ext2fs_cpu_to_le32(outdir->num);
11162 if (i != 1)
11163 root->hash =
11164 ext2fs_cpu_to_le32(outdir->hashes[i]);
11165 if ((retval = get_next_block(fs, outdir,
11166 &block_start)))
11167 return retval;
11168 dx_ent = set_int_node(fs, block_start);
11169 limit = (struct ext2_dx_countlimit *) dx_ent;
11170 c2 = limit->limit;
11171 root_offset += sizeof(struct ext2_dx_entry);
11172 c1--;
11173 }
11174 dx_ent->block = ext2fs_cpu_to_le32(i);
11175 if (c2 != limit->limit)
11176 dx_ent->hash =
11177 ext2fs_cpu_to_le32(outdir->hashes[i]);
11178 dx_ent++;
11179 c2--;
11180 }
11181 limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
11182 limit->limit = ext2fs_cpu_to_le16(limit->limit);
11183 }
11184 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
11185 root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
11186 root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
11187
11188 return 0;
11189}
11190
11191struct write_dir_struct {
11192 struct out_dir *outdir;
11193 errcode_t err;
11194 e2fsck_t ctx;
11195 int cleared;
11196};
11197
11198/*
11199 * Helper function which writes out a directory block.
11200 */
11201static int write_dir_block(ext2_filsys fs,
11202 blk_t *block_nr,
11203 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000011204 blk_t ref_block FSCK_ATTR((unused)),
11205 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011206 void *priv_data)
11207{
11208 struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
11209 blk_t blk;
11210 char *dir;
11211
11212 if (*block_nr == 0)
11213 return 0;
11214 if (blockcnt >= wd->outdir->num) {
11215 e2fsck_read_bitmaps(wd->ctx);
11216 blk = *block_nr;
11217 ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
11218 ext2fs_block_alloc_stats(fs, blk, -1);
11219 *block_nr = 0;
11220 wd->cleared++;
11221 return BLOCK_CHANGED;
11222 }
11223 if (blockcnt < 0)
11224 return 0;
11225
11226 dir = wd->outdir->buf + (blockcnt * fs->blocksize);
11227 wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
11228 if (wd->err)
11229 return BLOCK_ABORT;
11230 return 0;
11231}
11232
11233static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
11234 struct out_dir *outdir,
11235 ext2_ino_t ino, int compress)
11236{
11237 struct write_dir_struct wd;
11238 errcode_t retval;
11239 struct ext2_inode inode;
11240
11241 retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
11242 if (retval)
11243 return retval;
11244
11245 wd.outdir = outdir;
11246 wd.err = 0;
11247 wd.ctx = ctx;
11248 wd.cleared = 0;
11249
11250 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
11251 write_dir_block, &wd);
11252 if (retval)
11253 return retval;
11254 if (wd.err)
11255 return wd.err;
11256
11257 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
11258 if (compress)
11259 inode.i_flags &= ~EXT2_INDEX_FL;
11260 else
11261 inode.i_flags |= EXT2_INDEX_FL;
11262 inode.i_size = outdir->num * fs->blocksize;
11263 inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
11264 e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
11265
11266 return 0;
11267}
11268
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011269static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011270{
11271 ext2_filsys fs = ctx->fs;
11272 errcode_t retval;
11273 struct ext2_inode inode;
11274 char *dir_buf = 0;
11275 struct fill_dir_struct fd;
11276 struct out_dir outdir;
11277
11278 outdir.max = outdir.num = 0;
11279 outdir.buf = 0;
11280 outdir.hashes = 0;
11281 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
11282
11283 retval = ENOMEM;
11284 fd.harray = 0;
11285 dir_buf = malloc(inode.i_size);
11286 if (!dir_buf)
11287 goto errout;
11288
11289 fd.max_array = inode.i_size / 32;
11290 fd.num_array = 0;
11291 fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
11292 if (!fd.harray)
11293 goto errout;
11294
11295 fd.ctx = ctx;
11296 fd.buf = dir_buf;
11297 fd.inode = &inode;
11298 fd.err = 0;
11299 fd.dir_size = 0;
11300 fd.compress = 0;
11301 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
11302 (inode.i_size / fs->blocksize) < 2)
11303 fd.compress = 1;
11304 fd.parent = 0;
11305
11306 /* Read in the entire directory into memory */
11307 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
11308 fill_dir_block, &fd);
11309 if (fd.err) {
11310 retval = fd.err;
11311 goto errout;
11312 }
11313
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011314 /* Sort the list */
11315resort:
11316 if (fd.compress)
11317 qsort(fd.harray+2, fd.num_array-2,
11318 sizeof(struct hash_entry), name_cmp);
11319 else
11320 qsort(fd.harray, fd.num_array,
11321 sizeof(struct hash_entry), hash_cmp);
11322
11323 /*
11324 * Look for duplicates
11325 */
11326 if (duplicate_search_and_fix(ctx, fs, ino, &fd))
11327 goto resort;
11328
11329 if (ctx->options & E2F_OPT_NO) {
11330 retval = 0;
11331 goto errout;
11332 }
11333
11334 /*
11335 * Copy the directory entries. In a htree directory these
11336 * will become the leaf nodes.
11337 */
11338 retval = copy_dir_entries(fs, &fd, &outdir);
11339 if (retval)
11340 goto errout;
11341
11342 free(dir_buf); dir_buf = 0;
11343
11344 if (!fd.compress) {
11345 /* Calculate the interior nodes */
11346 retval = calculate_tree(fs, &outdir, ino, fd.parent);
11347 if (retval)
11348 goto errout;
11349 }
11350
11351 retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011352
11353errout:
Rob Landleye7c43b62006-03-01 16:39:45 +000011354 free(dir_buf);
11355 free(fd.harray);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011356
11357 free_out_dir(&outdir);
11358 return retval;
11359}
11360
11361void e2fsck_rehash_directories(e2fsck_t ctx)
11362{
11363 struct problem_context pctx;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011364 struct dir_info *dir;
11365 ext2_u32_iterate iter;
11366 ext2_ino_t ino;
11367 errcode_t retval;
11368 int i, cur, max, all_dirs, dir_index, first = 1;
11369
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011370 all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
11371
11372 if (!ctx->dirs_to_hash && !all_dirs)
11373 return;
11374
11375 e2fsck_get_lost_and_found(ctx, 0);
11376
11377 clear_problem_context(&pctx);
11378
11379 dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
11380 cur = 0;
11381 if (all_dirs) {
11382 i = 0;
11383 max = e2fsck_get_num_dirinfo(ctx);
11384 } else {
11385 retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
11386 &iter);
11387 if (retval) {
11388 pctx.errcode = retval;
11389 fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
11390 return;
11391 }
11392 max = ext2fs_u32_list_count(ctx->dirs_to_hash);
11393 }
11394 while (1) {
11395 if (all_dirs) {
11396 if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
11397 break;
11398 ino = dir->ino;
11399 } else {
11400 if (!ext2fs_u32_list_iterate(iter, &ino))
11401 break;
11402 }
11403 if (ino == ctx->lost_and_found)
11404 continue;
11405 pctx.dir = ino;
11406 if (first) {
11407 fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
11408 first = 0;
11409 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011410 pctx.errcode = e2fsck_rehash_dir(ctx, ino);
11411 if (pctx.errcode) {
11412 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
11413 fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
11414 }
11415 if (ctx->progress && !ctx->progress_fd)
11416 e2fsck_simple_progress(ctx, "Rebuilding directory",
11417 100.0 * (float) (++cur) / (float) max, ino);
11418 }
11419 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
11420 if (!all_dirs)
11421 ext2fs_u32_list_iterate_end(iter);
11422
Rob Landleye7c43b62006-03-01 16:39:45 +000011423 ext2fs_u32_list_free(ctx->dirs_to_hash);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011424 ctx->dirs_to_hash = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011425}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011426
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011427/*
11428 * linux/fs/revoke.c
11429 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011430 * Journal revoke routines for the generic filesystem journaling code;
11431 * part of the ext2fs journaling system.
11432 *
11433 * Revoke is the mechanism used to prevent old log records for deleted
11434 * metadata from being replayed on top of newer data using the same
11435 * blocks. The revoke mechanism is used in two separate places:
11436 *
11437 * + Commit: during commit we write the entire list of the current
11438 * transaction's revoked blocks to the journal
11439 *
11440 * + Recovery: during recovery we record the transaction ID of all
11441 * revoked blocks. If there are multiple revoke records in the log
11442 * for a single block, only the last one counts, and if there is a log
11443 * entry for a block beyond the last revoke, then that log entry still
11444 * gets replayed.
11445 *
11446 * We can get interactions between revokes and new log data within a
11447 * single transaction:
11448 *
11449 * Block is revoked and then journaled:
11450 * The desired end result is the journaling of the new block, so we
11451 * cancel the revoke before the transaction commits.
11452 *
11453 * Block is journaled and then revoked:
11454 * The revoke must take precedence over the write of the block, so we
11455 * need either to cancel the journal entry or to write the revoke
11456 * later in the log than the log block. In this case, we choose the
11457 * latter: journaling a block cancels any revoke record for that block
11458 * in the current transaction, so any revoke for that block in the
11459 * transaction must have happened after the block was journaled and so
11460 * the revoke must take precedence.
11461 *
11462 * Block is revoked and then written as data:
11463 * The data write is allowed to succeed, but the revoke is _not_
11464 * cancelled. We still need to prevent old log records from
11465 * overwriting the new data. We don't even need to clear the revoke
11466 * bit here.
11467 *
11468 * Revoke information on buffers is a tri-state value:
11469 *
11470 * RevokeValid clear: no cached revoke status, need to look it up
11471 * RevokeValid set, Revoked clear:
11472 * buffer has not been revoked, and cancel_revoke
11473 * need do nothing.
11474 * RevokeValid set, Revoked set:
11475 * buffer has been revoked.
11476 */
11477
11478static kmem_cache_t *revoke_record_cache;
11479static kmem_cache_t *revoke_table_cache;
11480
11481/* Each revoke record represents one single revoked block. During
11482 journal replay, this involves recording the transaction ID of the
11483 last transaction to revoke this block. */
11484
11485struct jbd_revoke_record_s
11486{
11487 struct list_head hash;
11488 tid_t sequence; /* Used for recovery only */
11489 unsigned long blocknr;
11490};
11491
11492
11493/* The revoke table is just a simple hash table of revoke records. */
11494struct jbd_revoke_table_s
11495{
11496 /* It is conceivable that we might want a larger hash table
11497 * for recovery. Must be a power of two. */
11498 int hash_size;
11499 int hash_shift;
11500 struct list_head *hash_table;
11501};
11502
11503
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011504/* Utility functions to maintain the revoke table */
11505
11506/* Borrowed from buffer.c: this is a tried and tested block hash function */
11507static inline int hash(journal_t *journal, unsigned long block)
11508{
11509 struct jbd_revoke_table_s *table = journal->j_revoke;
11510 int hash_shift = table->hash_shift;
11511
11512 return ((block << (hash_shift - 6)) ^
11513 (block >> 13) ^
11514 (block << (hash_shift - 12))) & (table->hash_size - 1);
11515}
11516
11517static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
11518 tid_t seq)
11519{
11520 struct list_head *hash_list;
11521 struct jbd_revoke_record_s *record;
11522
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011523 record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
11524 if (!record)
11525 goto oom;
11526
11527 record->sequence = seq;
11528 record->blocknr = blocknr;
11529 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
11530 list_add(&record->hash, hash_list);
11531 return 0;
11532
11533oom:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011534 return -ENOMEM;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011535}
11536
11537/* Find a revoke record in the journal's hash table. */
11538
11539static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
11540 unsigned long blocknr)
11541{
11542 struct list_head *hash_list;
11543 struct jbd_revoke_record_s *record;
11544
11545 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
11546
11547 record = (struct jbd_revoke_record_s *) hash_list->next;
11548 while (&(record->hash) != hash_list) {
11549 if (record->blocknr == blocknr)
11550 return record;
11551 record = (struct jbd_revoke_record_s *) record->hash.next;
11552 }
11553 return NULL;
11554}
11555
11556int journal_init_revoke_caches(void)
11557{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011558 revoke_record_cache = do_cache_create(sizeof(struct jbd_revoke_record_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011559 if (revoke_record_cache == 0)
11560 return -ENOMEM;
11561
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011562 revoke_table_cache = do_cache_create(sizeof(struct jbd_revoke_table_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011563 if (revoke_table_cache == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011564 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011565 revoke_record_cache = NULL;
11566 return -ENOMEM;
11567 }
11568 return 0;
11569}
11570
11571void journal_destroy_revoke_caches(void)
11572{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011573 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011574 revoke_record_cache = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011575 do_cache_destroy(revoke_table_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011576 revoke_table_cache = 0;
11577}
11578
11579/* Initialise the revoke table for a given journal to a given size. */
11580
11581int journal_init_revoke(journal_t *journal, int hash_size)
11582{
11583 int shift, tmp;
11584
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011585 journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
11586 if (!journal->j_revoke)
11587 return -ENOMEM;
11588
11589 /* Check that the hash_size is a power of two */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011590 journal->j_revoke->hash_size = hash_size;
11591
11592 shift = 0;
11593 tmp = hash_size;
11594 while((tmp >>= 1UL) != 0UL)
11595 shift++;
11596 journal->j_revoke->hash_shift = shift;
11597
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011598 journal->j_revoke->hash_table = malloc(hash_size * sizeof(struct list_head));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011599 if (!journal->j_revoke->hash_table) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011600 free(journal->j_revoke);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011601 journal->j_revoke = NULL;
11602 return -ENOMEM;
11603 }
11604
11605 for (tmp = 0; tmp < hash_size; tmp++)
11606 INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
11607
11608 return 0;
11609}
11610
11611/* Destoy a journal's revoke table. The table must already be empty! */
11612
11613void journal_destroy_revoke(journal_t *journal)
11614{
11615 struct jbd_revoke_table_s *table;
11616 struct list_head *hash_list;
11617 int i;
11618
11619 table = journal->j_revoke;
11620 if (!table)
11621 return;
11622
11623 for (i=0; i<table->hash_size; i++) {
11624 hash_list = &table->hash_table[i];
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011625 }
11626
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011627 free(table->hash_table);
11628 free(table);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011629 journal->j_revoke = NULL;
11630}
11631
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011632/*
11633 * Revoke support for recovery.
11634 *
11635 * Recovery needs to be able to:
11636 *
11637 * record all revoke records, including the tid of the latest instance
11638 * of each revoke in the journal
11639 *
11640 * check whether a given block in a given transaction should be replayed
11641 * (ie. has not been revoked by a revoke record in that or a subsequent
11642 * transaction)
11643 *
11644 * empty the revoke table after recovery.
11645 */
11646
11647/*
11648 * First, setting revoke records. We create a new revoke record for
11649 * every block ever revoked in the log as we scan it for recovery, and
11650 * we update the existing records if we find multiple revokes for a
11651 * single block.
11652 */
11653
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011654int journal_set_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011655 tid_t sequence)
11656{
11657 struct jbd_revoke_record_s *record;
11658
11659 record = find_revoke_record(journal, blocknr);
11660 if (record) {
11661 /* If we have multiple occurences, only record the
11662 * latest sequence number in the hashed record */
11663 if (tid_gt(sequence, record->sequence))
11664 record->sequence = sequence;
11665 return 0;
11666 }
11667 return insert_revoke_hash(journal, blocknr, sequence);
11668}
11669
11670/*
11671 * Test revoke records. For a given block referenced in the log, has
11672 * that block been revoked? A revoke record with a given transaction
11673 * sequence number revokes all blocks in that transaction and earlier
11674 * ones, but later transactions still need replayed.
11675 */
11676
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011677int journal_test_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011678 tid_t sequence)
11679{
11680 struct jbd_revoke_record_s *record;
11681
11682 record = find_revoke_record(journal, blocknr);
11683 if (!record)
11684 return 0;
11685 if (tid_gt(sequence, record->sequence))
11686 return 0;
11687 return 1;
11688}
11689
11690/*
11691 * Finally, once recovery is over, we need to clear the revoke table so
11692 * that it can be reused by the running filesystem.
11693 */
11694
11695void journal_clear_revoke(journal_t *journal)
11696{
11697 int i;
11698 struct list_head *hash_list;
11699 struct jbd_revoke_record_s *record;
11700 struct jbd_revoke_table_s *revoke_var;
11701
11702 revoke_var = journal->j_revoke;
11703
11704 for (i = 0; i < revoke_var->hash_size; i++) {
11705 hash_list = &revoke_var->hash_table[i];
11706 while (!list_empty(hash_list)) {
11707 record = (struct jbd_revoke_record_s*) hash_list->next;
11708 list_del(&record->hash);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011709 free(record);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011710 }
11711 }
11712}
11713
11714/*
11715 * e2fsck.c - superblock checks
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011716 */
11717
11718#define MIN_CHECK 1
11719#define MAX_CHECK 2
11720
11721static void check_super_value(e2fsck_t ctx, const char *descr,
11722 unsigned long value, int flags,
11723 unsigned long min_val, unsigned long max_val)
11724{
11725 struct problem_context pctx;
11726
11727 if (((flags & MIN_CHECK) && (value < min_val)) ||
11728 ((flags & MAX_CHECK) && (value > max_val))) {
11729 clear_problem_context(&pctx);
11730 pctx.num = value;
11731 pctx.str = descr;
11732 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
11733 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
11734 }
11735}
11736
11737/*
11738 * This routine may get stubbed out in special compilations of the
11739 * e2fsck code..
11740 */
11741#ifndef EXT2_SPECIAL_DEVICE_SIZE
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011742static errcode_t e2fsck_get_device_size(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011743{
11744 return (ext2fs_get_device_size(ctx->filesystem_name,
11745 EXT2_BLOCK_SIZE(ctx->fs->super),
11746 &ctx->num_blocks));
11747}
11748#endif
11749
11750/*
11751 * helper function to release an inode
11752 */
11753struct process_block_struct {
11754 e2fsck_t ctx;
11755 char *buf;
11756 struct problem_context *pctx;
11757 int truncating;
11758 int truncate_offset;
11759 e2_blkcnt_t truncate_block;
11760 int truncated_blocks;
11761 int abort;
11762 errcode_t errcode;
11763};
11764
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011765static int release_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011766 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000011767 blk_t ref_blk FSCK_ATTR((unused)),
11768 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011769 void *priv_data)
11770{
11771 struct process_block_struct *pb;
11772 e2fsck_t ctx;
11773 struct problem_context *pctx;
11774 blk_t blk = *block_nr;
11775 int retval = 0;
11776
11777 pb = (struct process_block_struct *) priv_data;
11778 ctx = pb->ctx;
11779 pctx = pb->pctx;
11780
11781 pctx->blk = blk;
11782 pctx->blkcount = blockcnt;
11783
11784 if (HOLE_BLKADDR(blk))
11785 return 0;
11786
11787 if ((blk < fs->super->s_first_data_block) ||
11788 (blk >= fs->super->s_blocks_count)) {
11789 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
11790 return_abort:
11791 pb->abort = 1;
11792 return BLOCK_ABORT;
11793 }
11794
11795 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
11796 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
11797 goto return_abort;
11798 }
11799
11800 /*
11801 * If we are deleting an orphan, then we leave the fields alone.
11802 * If we are truncating an orphan, then update the inode fields
11803 * and clean up any partial block data.
11804 */
11805 if (pb->truncating) {
11806 /*
11807 * We only remove indirect blocks if they are
11808 * completely empty.
11809 */
11810 if (blockcnt < 0) {
11811 int i, limit;
11812 blk_t *bp;
11813
11814 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
11815 pb->buf);
11816 if (pb->errcode)
11817 goto return_abort;
11818
11819 limit = fs->blocksize >> 2;
11820 for (i = 0, bp = (blk_t *) pb->buf;
11821 i < limit; i++, bp++)
11822 if (*bp)
11823 return 0;
11824 }
11825 /*
11826 * We don't remove direct blocks until we've reached
11827 * the truncation block.
11828 */
11829 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
11830 return 0;
11831 /*
11832 * If part of the last block needs truncating, we do
11833 * it here.
11834 */
11835 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
11836 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
11837 pb->buf);
11838 if (pb->errcode)
11839 goto return_abort;
11840 memset(pb->buf + pb->truncate_offset, 0,
11841 fs->blocksize - pb->truncate_offset);
11842 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
11843 pb->buf);
11844 if (pb->errcode)
11845 goto return_abort;
11846 }
11847 pb->truncated_blocks++;
11848 *block_nr = 0;
11849 retval |= BLOCK_CHANGED;
11850 }
11851
11852 ext2fs_block_alloc_stats(fs, blk, -1);
11853 return retval;
11854}
11855
11856/*
11857 * This function releases an inode. Returns 1 if an inconsistency was
11858 * found. If the inode has a link count, then it is being truncated and
11859 * not deleted.
11860 */
11861static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
11862 struct ext2_inode *inode, char *block_buf,
11863 struct problem_context *pctx)
11864{
11865 struct process_block_struct pb;
11866 ext2_filsys fs = ctx->fs;
11867 errcode_t retval;
11868 __u32 count;
11869
11870 if (!ext2fs_inode_has_valid_blocks(inode))
11871 return 0;
11872
11873 pb.buf = block_buf + 3 * ctx->fs->blocksize;
11874 pb.ctx = ctx;
11875 pb.abort = 0;
11876 pb.errcode = 0;
11877 pb.pctx = pctx;
11878 if (inode->i_links_count) {
11879 pb.truncating = 1;
11880 pb.truncate_block = (e2_blkcnt_t)
11881 ((((long long)inode->i_size_high << 32) +
11882 inode->i_size + fs->blocksize - 1) /
11883 fs->blocksize);
11884 pb.truncate_offset = inode->i_size % fs->blocksize;
11885 } else {
11886 pb.truncating = 0;
11887 pb.truncate_block = 0;
11888 pb.truncate_offset = 0;
11889 }
11890 pb.truncated_blocks = 0;
11891 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
11892 block_buf, release_inode_block, &pb);
11893 if (retval) {
11894 com_err("release_inode_blocks", retval,
11895 _("while calling ext2fs_block_iterate for inode %d"),
11896 ino);
11897 return 1;
11898 }
11899 if (pb.abort)
11900 return 1;
11901
11902 /* Refresh the inode since ext2fs_block_iterate may have changed it */
11903 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
11904
11905 if (pb.truncated_blocks)
11906 inode->i_blocks -= pb.truncated_blocks *
11907 (fs->blocksize / 512);
11908
11909 if (inode->i_file_acl) {
11910 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
11911 block_buf, -1, &count);
11912 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
11913 retval = 0;
11914 count = 1;
11915 }
11916 if (retval) {
11917 com_err("release_inode_blocks", retval,
11918 _("while calling ext2fs_adjust_ea_refocunt for inode %d"),
11919 ino);
11920 return 1;
11921 }
11922 if (count == 0)
11923 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
11924 inode->i_file_acl = 0;
11925 }
11926 return 0;
11927}
11928
11929/*
11930 * This function releases all of the orphan inodes. It returns 1 if
11931 * it hit some error, and 0 on success.
11932 */
11933static int release_orphan_inodes(e2fsck_t ctx)
11934{
11935 ext2_filsys fs = ctx->fs;
11936 ext2_ino_t ino, next_ino;
11937 struct ext2_inode inode;
11938 struct problem_context pctx;
11939 char *block_buf;
11940
11941 if ((ino = fs->super->s_last_orphan) == 0)
11942 return 0;
11943
11944 /*
11945 * Win or lose, we won't be using the head of the orphan inode
11946 * list again.
11947 */
11948 fs->super->s_last_orphan = 0;
11949 ext2fs_mark_super_dirty(fs);
11950
11951 /*
11952 * If the filesystem contains errors, don't run the orphan
11953 * list, since the orphan list can't be trusted; and we're
11954 * going to be running a full e2fsck run anyway...
11955 */
11956 if (fs->super->s_state & EXT2_ERROR_FS)
11957 return 0;
11958
11959 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
11960 (ino > fs->super->s_inodes_count)) {
11961 clear_problem_context(&pctx);
11962 pctx.ino = ino;
11963 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
11964 return 1;
11965 }
11966
11967 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
11968 "block iterate buffer");
11969 e2fsck_read_bitmaps(ctx);
11970
11971 while (ino) {
11972 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
11973 clear_problem_context(&pctx);
11974 pctx.ino = ino;
11975 pctx.inode = &inode;
11976 pctx.str = inode.i_links_count ? _("Truncating") :
11977 _("Clearing");
11978
11979 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
11980
11981 next_ino = inode.i_dtime;
11982 if (next_ino &&
11983 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
11984 (next_ino > fs->super->s_inodes_count))) {
11985 pctx.ino = next_ino;
11986 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
11987 goto return_abort;
11988 }
11989
11990 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
11991 goto return_abort;
11992
11993 if (!inode.i_links_count) {
11994 ext2fs_inode_alloc_stats2(fs, ino, -1,
11995 LINUX_S_ISDIR(inode.i_mode));
11996 inode.i_dtime = time(0);
11997 } else {
11998 inode.i_dtime = 0;
11999 }
12000 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
12001 ino = next_ino;
12002 }
12003 ext2fs_free_mem(&block_buf);
12004 return 0;
12005return_abort:
12006 ext2fs_free_mem(&block_buf);
12007 return 1;
12008}
12009
12010/*
12011 * Check the resize inode to make sure it is sane. We check both for
12012 * the case where on-line resizing is not enabled (in which case the
12013 * resize inode should be cleared) as well as the case where on-line
12014 * resizing is enabled.
12015 */
12016static void check_resize_inode(e2fsck_t ctx)
12017{
12018 ext2_filsys fs = ctx->fs;
12019 struct ext2_inode inode;
12020 struct problem_context pctx;
12021 int i, j, gdt_off, ind_off;
12022 blk_t blk, pblk, expect;
12023 __u32 *dind_buf = 0, *ind_buf;
12024 errcode_t retval;
12025
12026 clear_problem_context(&pctx);
12027
12028 /*
12029 * If the resize inode feature isn't set, then
12030 * s_reserved_gdt_blocks must be zero.
12031 */
12032 if (!(fs->super->s_feature_compat &
12033 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
12034 if (fs->super->s_reserved_gdt_blocks) {
12035 pctx.num = fs->super->s_reserved_gdt_blocks;
12036 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
12037 &pctx)) {
12038 fs->super->s_reserved_gdt_blocks = 0;
12039 ext2fs_mark_super_dirty(fs);
12040 }
12041 }
12042 }
12043
Mike Frysinger874af852006-03-08 07:03:27 +000012044 /* Read the resize inode */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012045 pctx.ino = EXT2_RESIZE_INO;
12046 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
12047 if (retval) {
12048 if (fs->super->s_feature_compat &
12049 EXT2_FEATURE_COMPAT_RESIZE_INODE)
12050 ctx->flags |= E2F_FLAG_RESIZE_INODE;
12051 return;
12052 }
12053
12054 /*
12055 * If the resize inode feature isn't set, check to make sure
12056 * the resize inode is cleared; then we're done.
12057 */
12058 if (!(fs->super->s_feature_compat &
12059 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
12060 for (i=0; i < EXT2_N_BLOCKS; i++) {
12061 if (inode.i_block[i])
12062 break;
12063 }
12064 if ((i < EXT2_N_BLOCKS) &&
12065 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
12066 memset(&inode, 0, sizeof(inode));
12067 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
12068 "clear_resize");
12069 }
12070 return;
12071 }
12072
12073 /*
12074 * The resize inode feature is enabled; check to make sure the
12075 * only block in use is the double indirect block
12076 */
12077 blk = inode.i_block[EXT2_DIND_BLOCK];
12078 for (i=0; i < EXT2_N_BLOCKS; i++) {
12079 if (i != EXT2_DIND_BLOCK && inode.i_block[i])
12080 break;
12081 }
12082 if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
12083 !(inode.i_mode & LINUX_S_IFREG) ||
12084 (blk < fs->super->s_first_data_block ||
12085 blk >= fs->super->s_blocks_count)) {
12086 resize_inode_invalid:
12087 if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
12088 memset(&inode, 0, sizeof(inode));
12089 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
12090 "clear_resize");
12091 ctx->flags |= E2F_FLAG_RESIZE_INODE;
12092 }
12093 if (!(ctx->options & E2F_OPT_READONLY)) {
12094 fs->super->s_state &= ~EXT2_VALID_FS;
12095 ext2fs_mark_super_dirty(fs);
12096 }
12097 goto cleanup;
12098 }
12099 dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
12100 "resize dind buffer");
12101 ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
12102
12103 retval = ext2fs_read_ind_block(fs, blk, dind_buf);
12104 if (retval)
12105 goto resize_inode_invalid;
12106
12107 gdt_off = fs->desc_blocks;
12108 pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
12109 for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
12110 i++, gdt_off++, pblk++) {
12111 gdt_off %= fs->blocksize/4;
12112 if (dind_buf[gdt_off] != pblk)
12113 goto resize_inode_invalid;
12114 retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
12115 if (retval)
12116 goto resize_inode_invalid;
12117 ind_off = 0;
12118 for (j = 1; j < fs->group_desc_count; j++) {
12119 if (!ext2fs_bg_has_super(fs, j))
12120 continue;
12121 expect = pblk + (j * fs->super->s_blocks_per_group);
12122 if (ind_buf[ind_off] != expect)
12123 goto resize_inode_invalid;
12124 ind_off++;
12125 }
12126 }
12127
12128cleanup:
Rob Landleye7c43b62006-03-01 16:39:45 +000012129 ext2fs_free_mem(&dind_buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012130
12131 }
12132
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012133static void check_super_block(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012134{
12135 ext2_filsys fs = ctx->fs;
12136 blk_t first_block, last_block;
12137 struct ext2_super_block *sb = fs->super;
12138 struct ext2_group_desc *gd;
12139 blk_t blocks_per_group = fs->super->s_blocks_per_group;
12140 blk_t bpg_max;
12141 int inodes_per_block;
12142 int ipg_max;
12143 int inode_size;
12144 dgrp_t i;
12145 blk_t should_be;
12146 struct problem_context pctx;
12147 __u32 free_blocks = 0, free_inodes = 0;
12148
12149 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
12150 ipg_max = inodes_per_block * (blocks_per_group - 4);
12151 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
12152 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
12153 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
12154 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
12155 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
12156
12157 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
12158 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
12159 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
12160 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
12161 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
12162 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
12163
12164 clear_problem_context(&pctx);
12165
12166 /*
12167 * Verify the super block constants...
12168 */
12169 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
12170 MIN_CHECK, 1, 0);
12171 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
12172 MIN_CHECK, 1, 0);
12173 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
12174 MAX_CHECK, 0, sb->s_blocks_count);
12175 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
12176 MIN_CHECK | MAX_CHECK, 0,
12177 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
12178 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
12179 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
12180 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
12181 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
12182 bpg_max);
12183 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
12184 MIN_CHECK | MAX_CHECK, 8, bpg_max);
12185 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
12186 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
12187 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
12188 MAX_CHECK, 0, sb->s_blocks_count / 2);
12189 check_super_value(ctx, "reserved_gdt_blocks",
12190 sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
12191 fs->blocksize/4);
12192 inode_size = EXT2_INODE_SIZE(sb);
12193 check_super_value(ctx, "inode_size",
12194 inode_size, MIN_CHECK | MAX_CHECK,
12195 EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
12196 if (inode_size & (inode_size - 1)) {
12197 pctx.num = inode_size;
12198 pctx.str = "inode_size";
12199 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
12200 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
12201 return;
12202 }
12203
12204 if (!ctx->num_blocks) {
12205 pctx.errcode = e2fsck_get_device_size(ctx);
12206 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
12207 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
12208 ctx->flags |= E2F_FLAG_ABORT;
12209 return;
12210 }
12211 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
12212 (ctx->num_blocks < sb->s_blocks_count)) {
12213 pctx.blk = sb->s_blocks_count;
12214 pctx.blk2 = ctx->num_blocks;
12215 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
12216 ctx->flags |= E2F_FLAG_ABORT;
12217 return;
12218 }
12219 }
12220 }
12221
12222 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
12223 pctx.blk = EXT2_BLOCK_SIZE(sb);
12224 pctx.blk2 = EXT2_FRAG_SIZE(sb);
12225 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
12226 ctx->flags |= E2F_FLAG_ABORT;
12227 return;
12228 }
12229
12230 should_be = sb->s_frags_per_group >>
12231 (sb->s_log_block_size - sb->s_log_frag_size);
12232 if (sb->s_blocks_per_group != should_be) {
12233 pctx.blk = sb->s_blocks_per_group;
12234 pctx.blk2 = should_be;
12235 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
12236 ctx->flags |= E2F_FLAG_ABORT;
12237 return;
12238 }
12239
12240 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
12241 if (sb->s_first_data_block != should_be) {
12242 pctx.blk = sb->s_first_data_block;
12243 pctx.blk2 = should_be;
12244 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
12245 ctx->flags |= E2F_FLAG_ABORT;
12246 return;
12247 }
12248
12249 should_be = sb->s_inodes_per_group * fs->group_desc_count;
12250 if (sb->s_inodes_count != should_be) {
12251 pctx.ino = sb->s_inodes_count;
12252 pctx.ino2 = should_be;
12253 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
12254 sb->s_inodes_count = should_be;
12255 ext2fs_mark_super_dirty(fs);
12256 }
12257 }
12258
12259 /*
12260 * Verify the group descriptors....
12261 */
12262 first_block = sb->s_first_data_block;
12263 last_block = first_block + blocks_per_group;
12264
12265 for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
12266 pctx.group = i;
12267
12268 if (i == fs->group_desc_count - 1)
12269 last_block = sb->s_blocks_count;
12270 if ((gd->bg_block_bitmap < first_block) ||
12271 (gd->bg_block_bitmap >= last_block)) {
12272 pctx.blk = gd->bg_block_bitmap;
12273 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
12274 gd->bg_block_bitmap = 0;
12275 }
12276 if (gd->bg_block_bitmap == 0) {
12277 ctx->invalid_block_bitmap_flag[i]++;
12278 ctx->invalid_bitmaps++;
12279 }
12280 if ((gd->bg_inode_bitmap < first_block) ||
12281 (gd->bg_inode_bitmap >= last_block)) {
12282 pctx.blk = gd->bg_inode_bitmap;
12283 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
12284 gd->bg_inode_bitmap = 0;
12285 }
12286 if (gd->bg_inode_bitmap == 0) {
12287 ctx->invalid_inode_bitmap_flag[i]++;
12288 ctx->invalid_bitmaps++;
12289 }
12290 if ((gd->bg_inode_table < first_block) ||
12291 ((gd->bg_inode_table +
12292 fs->inode_blocks_per_group - 1) >= last_block)) {
12293 pctx.blk = gd->bg_inode_table;
12294 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
12295 gd->bg_inode_table = 0;
12296 }
12297 if (gd->bg_inode_table == 0) {
12298 ctx->invalid_inode_table_flag[i]++;
12299 ctx->invalid_bitmaps++;
12300 }
12301 free_blocks += gd->bg_free_blocks_count;
12302 free_inodes += gd->bg_free_inodes_count;
12303 first_block += sb->s_blocks_per_group;
12304 last_block += sb->s_blocks_per_group;
12305
12306 if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
12307 (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
12308 (gd->bg_used_dirs_count > sb->s_inodes_per_group))
12309 ext2fs_unmark_valid(fs);
12310
12311 }
12312
12313 /*
12314 * Update the global counts from the block group counts. This
12315 * is needed for an experimental patch which eliminates
12316 * locking the entire filesystem when allocating blocks or
12317 * inodes; if the filesystem is not unmounted cleanly, the
12318 * global counts may not be accurate.
12319 */
12320 if ((free_blocks != sb->s_free_blocks_count) ||
12321 (free_inodes != sb->s_free_inodes_count)) {
12322 if (ctx->options & E2F_OPT_READONLY)
12323 ext2fs_unmark_valid(fs);
12324 else {
12325 sb->s_free_blocks_count = free_blocks;
12326 sb->s_free_inodes_count = free_inodes;
12327 ext2fs_mark_super_dirty(fs);
12328 }
12329 }
12330
12331 if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
12332 (sb->s_free_inodes_count > sb->s_inodes_count))
12333 ext2fs_unmark_valid(fs);
12334
12335
12336 /*
12337 * If we have invalid bitmaps, set the error state of the
12338 * filesystem.
12339 */
12340 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
12341 sb->s_state &= ~EXT2_VALID_FS;
12342 ext2fs_mark_super_dirty(fs);
12343 }
12344
12345 clear_problem_context(&pctx);
12346
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012347 /*
12348 * If the UUID field isn't assigned, assign it.
12349 */
12350 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
12351 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
12352 uuid_generate(sb->s_uuid);
12353 ext2fs_mark_super_dirty(fs);
12354 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
12355 }
12356 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012357
Rob Landley3e72c592006-04-06 22:49:04 +000012358 /* FIXME - HURD support?
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012359 * For the Hurd, check to see if the filetype option is set,
12360 * since it doesn't support it.
12361 */
12362 if (!(ctx->options & E2F_OPT_READONLY) &&
12363 fs->super->s_creator_os == EXT2_OS_HURD &&
12364 (fs->super->s_feature_incompat &
12365 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
12366 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
12367 fs->super->s_feature_incompat &=
12368 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
12369 ext2fs_mark_super_dirty(fs);
12370
12371 }
12372 }
12373
12374 /*
12375 * If we have any of the compatibility flags set, we need to have a
12376 * revision 1 filesystem. Most kernels will not check the flags on
12377 * a rev 0 filesystem and we may have corruption issues because of
12378 * the incompatible changes to the filesystem.
12379 */
12380 if (!(ctx->options & E2F_OPT_READONLY) &&
12381 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
12382 (fs->super->s_feature_compat ||
12383 fs->super->s_feature_ro_compat ||
12384 fs->super->s_feature_incompat) &&
12385 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
12386 ext2fs_update_dynamic_rev(fs);
12387 ext2fs_mark_super_dirty(fs);
12388 }
12389
12390 check_resize_inode(ctx);
12391
12392 /*
12393 * Clean up any orphan inodes, if present.
12394 */
12395 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
12396 fs->super->s_state &= ~EXT2_VALID_FS;
12397 ext2fs_mark_super_dirty(fs);
12398 }
12399
12400 /*
12401 * Move the ext3 journal file, if necessary.
12402 */
12403 e2fsck_move_ext3_journal(ctx);
12404 return;
12405}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012406
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012407/*
12408 * swapfs.c --- byte-swap an ext2 filesystem
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012409 */
12410
12411#ifdef ENABLE_SWAPFS
12412
12413struct swap_block_struct {
12414 ext2_ino_t ino;
12415 int isdir;
12416 errcode_t errcode;
12417 char *dir_buf;
12418 struct ext2_inode *inode;
12419};
12420
12421/*
12422 * This is a helper function for block_iterate. We mark all of the
12423 * indirect and direct blocks as changed, so that block_iterate will
12424 * write them out.
12425 */
12426static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
12427 void *priv_data)
12428{
12429 errcode_t retval;
12430
12431 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
12432
12433 if (sb->isdir && (blockcnt >= 0) && *block_nr) {
12434 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
12435 if (retval) {
12436 sb->errcode = retval;
12437 return BLOCK_ABORT;
12438 }
12439 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
12440 if (retval) {
12441 sb->errcode = retval;
12442 return BLOCK_ABORT;
12443 }
12444 }
12445 if (blockcnt >= 0) {
12446 if (blockcnt < EXT2_NDIR_BLOCKS)
12447 return 0;
12448 return BLOCK_CHANGED;
12449 }
12450 if (blockcnt == BLOCK_COUNT_IND) {
12451 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
12452 return 0;
12453 return BLOCK_CHANGED;
12454 }
12455 if (blockcnt == BLOCK_COUNT_DIND) {
12456 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
12457 return 0;
12458 return BLOCK_CHANGED;
12459 }
12460 if (blockcnt == BLOCK_COUNT_TIND) {
12461 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
12462 return 0;
12463 return BLOCK_CHANGED;
12464 }
12465 return BLOCK_CHANGED;
12466}
12467
12468/*
12469 * This function is responsible for byte-swapping all of the indirect,
12470 * block pointers. It is also responsible for byte-swapping directories.
12471 */
12472static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
12473 struct ext2_inode *inode)
12474{
12475 errcode_t retval;
12476 struct swap_block_struct sb;
12477
12478 sb.ino = ino;
12479 sb.inode = inode;
12480 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
12481 sb.errcode = 0;
12482 sb.isdir = 0;
12483 if (LINUX_S_ISDIR(inode->i_mode))
12484 sb.isdir = 1;
12485
12486 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
12487 swap_block, &sb);
12488 if (retval) {
12489 com_err("swap_inode_blocks", retval,
12490 _("while calling ext2fs_block_iterate"));
12491 ctx->flags |= E2F_FLAG_ABORT;
12492 return;
12493 }
12494 if (sb.errcode) {
12495 com_err("swap_inode_blocks", sb.errcode,
12496 _("while calling iterator function"));
12497 ctx->flags |= E2F_FLAG_ABORT;
12498 return;
12499 }
12500}
12501
12502static void swap_inodes(e2fsck_t ctx)
12503{
12504 ext2_filsys fs = ctx->fs;
12505 dgrp_t group;
12506 unsigned int i;
12507 ext2_ino_t ino = 1;
12508 char *buf, *block_buf;
12509 errcode_t retval;
12510 struct ext2_inode * inode;
12511
12512 e2fsck_use_inode_shortcuts(ctx, 1);
12513
12514 retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
12515 &buf);
12516 if (retval) {
12517 com_err("swap_inodes", retval,
12518 _("while allocating inode buffer"));
12519 ctx->flags |= E2F_FLAG_ABORT;
12520 return;
12521 }
12522 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
12523 "block interate buffer");
12524 for (group = 0; group < fs->group_desc_count; group++) {
12525 retval = io_channel_read_blk(fs->io,
12526 fs->group_desc[group].bg_inode_table,
12527 fs->inode_blocks_per_group, buf);
12528 if (retval) {
12529 com_err("swap_inodes", retval,
12530 _("while reading inode table (group %d)"),
12531 group);
12532 ctx->flags |= E2F_FLAG_ABORT;
12533 return;
12534 }
12535 inode = (struct ext2_inode *) buf;
12536 for (i=0; i < fs->super->s_inodes_per_group;
12537 i++, ino++, inode++) {
12538 ctx->stashed_ino = ino;
12539 ctx->stashed_inode = inode;
12540
12541 if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
12542 ext2fs_swap_inode(fs, inode, inode, 0);
12543
12544 /*
12545 * Skip deleted files.
12546 */
12547 if (inode->i_links_count == 0)
12548 continue;
12549
12550 if (LINUX_S_ISDIR(inode->i_mode) ||
12551 ((inode->i_block[EXT2_IND_BLOCK] ||
12552 inode->i_block[EXT2_DIND_BLOCK] ||
12553 inode->i_block[EXT2_TIND_BLOCK]) &&
12554 ext2fs_inode_has_valid_blocks(inode)))
12555 swap_inode_blocks(ctx, ino, block_buf, inode);
12556
12557 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
12558 return;
12559
12560 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
12561 ext2fs_swap_inode(fs, inode, inode, 1);
12562 }
12563 retval = io_channel_write_blk(fs->io,
12564 fs->group_desc[group].bg_inode_table,
12565 fs->inode_blocks_per_group, buf);
12566 if (retval) {
12567 com_err("swap_inodes", retval,
12568 _("while writing inode table (group %d)"),
12569 group);
12570 ctx->flags |= E2F_FLAG_ABORT;
12571 return;
12572 }
12573 }
12574 ext2fs_free_mem(&buf);
12575 ext2fs_free_mem(&block_buf);
12576 e2fsck_use_inode_shortcuts(ctx, 0);
12577 ext2fs_flush_icache(fs);
12578}
12579
12580#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
12581/*
12582 * On the PowerPC, the big-endian variant of the ext2 filesystem
12583 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
12584 * of each word. Thus a bitmap with only bit 0 set would be, as
12585 * a string of bytes, 00 00 00 01 00 ...
12586 * To cope with this, we byte-reverse each word of a bitmap if
12587 * we have a big-endian filesystem, that is, if we are *not*
12588 * byte-swapping other word-sized numbers.
12589 */
12590#define EXT2_BIG_ENDIAN_BITMAPS
12591#endif
12592
12593#ifdef EXT2_BIG_ENDIAN_BITMAPS
12594static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
12595{
12596 __u32 *p = (__u32 *) bmap->bitmap;
12597 int n, nbytes = (bmap->end - bmap->start + 7) / 8;
12598
12599 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
12600 *p = ext2fs_swab32(*p);
12601}
12602#endif
12603
12604
12605#ifdef ENABLE_SWAPFS
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012606static void swap_filesys(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012607{
12608 ext2_filsys fs = ctx->fs;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012609 if (!(ctx->options & E2F_OPT_PREEN))
12610 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
12611
Rob Landley3e72c592006-04-06 22:49:04 +000012612 /* Byte swap */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012613
12614 if (fs->super->s_mnt_count) {
12615 fprintf(stderr, _("%s: the filesystem must be freshly "
12616 "checked using fsck\n"
12617 "and not mounted before trying to "
12618 "byte-swap it.\n"), ctx->device_name);
12619 ctx->flags |= E2F_FLAG_ABORT;
12620 return;
12621 }
12622 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
12623 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
12624 EXT2_FLAG_SWAP_BYTES_WRITE);
12625 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
12626 } else {
12627 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
12628 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
12629 }
12630 swap_inodes(ctx);
12631 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
12632 return;
12633 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
12634 fs->flags |= EXT2_FLAG_SWAP_BYTES;
12635 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
12636 EXT2_FLAG_SWAP_BYTES_WRITE);
12637
12638#ifdef EXT2_BIG_ENDIAN_BITMAPS
12639 e2fsck_read_bitmaps(ctx);
12640 ext2fs_swap_bitmap(fs->inode_map);
12641 ext2fs_swap_bitmap(fs->block_map);
12642 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
12643#endif
12644 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
12645 ext2fs_flush(fs);
12646 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012647}
12648#endif /* ENABLE_SWAPFS */
12649
12650#endif
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012651
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012652/*
12653 * util.c --- miscellaneous utilities
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012654 */
12655
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012656
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012657void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
12658 const char *description)
12659{
12660 void *ret;
12661 char buf[256];
12662
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012663 ret = malloc(size);
12664 if (!ret) {
12665 sprintf(buf, "Can't allocate %s\n", description);
12666 fatal_error(ctx, buf);
12667 }
12668 memset(ret, 0, size);
12669 return ret;
12670}
12671
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012672static char *string_copy(const char *str, int len)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012673{
12674 char *ret;
12675
12676 if (!str)
12677 return NULL;
12678 if (!len)
12679 len = strlen(str);
12680 ret = malloc(len+1);
12681 if (ret) {
12682 strncpy(ret, str, len);
12683 ret[len] = 0;
12684 }
12685 return ret;
12686}
12687
12688#ifndef HAVE_CONIO_H
12689static int read_a_char(void)
12690{
12691 char c;
12692 int r;
12693 int fail = 0;
12694
12695 while(1) {
12696 if (e2fsck_global_ctx &&
12697 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
12698 return 3;
12699 }
12700 r = read(0, &c, 1);
12701 if (r == 1)
12702 return c;
12703 if (fail++ > 100)
12704 break;
12705 }
12706 return EOF;
12707}
12708#endif
12709
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012710static int ask_yn(const char * string, int def)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012711{
12712 int c;
12713 const char *defstr;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012714 static const char short_yes[] = "yY";
12715 static const char short_no[] = "nN";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012716
12717#ifdef HAVE_TERMIOS_H
12718 struct termios termios, tmp;
12719
12720 tcgetattr (0, &termios);
12721 tmp = termios;
12722 tmp.c_lflag &= ~(ICANON | ECHO);
12723 tmp.c_cc[VMIN] = 1;
12724 tmp.c_cc[VTIME] = 0;
12725 tcsetattr (0, TCSANOW, &tmp);
12726#endif
12727
12728 if (def == 1)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012729 defstr = "<y>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012730 else if (def == 0)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012731 defstr = "<n>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012732 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012733 defstr = " (y/n)";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012734 printf("%s%s? ", string, defstr);
12735 while (1) {
12736 fflush (stdout);
12737 if ((c = read_a_char()) == EOF)
12738 break;
12739 if (c == 3) {
12740#ifdef HAVE_TERMIOS_H
12741 tcsetattr (0, TCSANOW, &termios);
12742#endif
12743 if (e2fsck_global_ctx &&
12744 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
12745 puts("\n");
12746 longjmp(e2fsck_global_ctx->abort_loc, 1);
12747 }
12748 puts(_("cancelled!\n"));
12749 return 0;
12750 }
12751 if (strchr(short_yes, (char) c)) {
12752 def = 1;
12753 break;
12754 }
12755 else if (strchr(short_no, (char) c)) {
12756 def = 0;
12757 break;
12758 }
12759 else if ((c == ' ' || c == '\n') && (def != -1))
12760 break;
12761 }
12762 if (def)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012763 puts("yes\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012764 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012765 puts ("no\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012766#ifdef HAVE_TERMIOS_H
12767 tcsetattr (0, TCSANOW, &termios);
12768#endif
12769 return def;
12770}
12771
12772int ask (e2fsck_t ctx, const char * string, int def)
12773{
12774 if (ctx->options & E2F_OPT_NO) {
12775 printf (_("%s? no\n\n"), string);
12776 return 0;
12777 }
12778 if (ctx->options & E2F_OPT_YES) {
12779 printf (_("%s? yes\n\n"), string);
12780 return 1;
12781 }
12782 if (ctx->options & E2F_OPT_PREEN) {
12783 printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
12784 return def;
12785 }
12786 return ask_yn(string, def);
12787}
12788
12789void e2fsck_read_bitmaps(e2fsck_t ctx)
12790{
12791 ext2_filsys fs = ctx->fs;
12792 errcode_t retval;
12793
12794 if (ctx->invalid_bitmaps) {
12795 com_err(ctx->program_name, 0,
12796 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
12797 ctx->device_name);
12798 fatal_error(ctx, 0);
12799 }
12800
12801 ehandler_operation(_("reading inode and block bitmaps"));
12802 retval = ext2fs_read_bitmaps(fs);
12803 ehandler_operation(0);
12804 if (retval) {
12805 com_err(ctx->program_name, retval,
12806 _("while retrying to read bitmaps for %s"),
12807 ctx->device_name);
12808 fatal_error(ctx, 0);
12809 }
12810}
12811
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012812static void e2fsck_write_bitmaps(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012813{
12814 ext2_filsys fs = ctx->fs;
12815 errcode_t retval;
12816
12817 if (ext2fs_test_bb_dirty(fs)) {
12818 ehandler_operation(_("writing block bitmaps"));
12819 retval = ext2fs_write_block_bitmap(fs);
12820 ehandler_operation(0);
12821 if (retval) {
12822 com_err(ctx->program_name, retval,
12823 _("while retrying to write block bitmaps for %s"),
12824 ctx->device_name);
12825 fatal_error(ctx, 0);
12826 }
12827 }
12828
12829 if (ext2fs_test_ib_dirty(fs)) {
12830 ehandler_operation(_("writing inode bitmaps"));
12831 retval = ext2fs_write_inode_bitmap(fs);
12832 ehandler_operation(0);
12833 if (retval) {
12834 com_err(ctx->program_name, retval,
12835 _("while retrying to write inode bitmaps for %s"),
12836 ctx->device_name);
12837 fatal_error(ctx, 0);
12838 }
12839 }
12840}
12841
12842void preenhalt(e2fsck_t ctx)
12843{
12844 ext2_filsys fs = ctx->fs;
12845
12846 if (!(ctx->options & E2F_OPT_PREEN))
12847 return;
12848 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
12849 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
12850 ctx->device_name);
12851 if (fs != NULL) {
12852 fs->super->s_state |= EXT2_ERROR_FS;
12853 ext2fs_mark_super_dirty(fs);
12854 ext2fs_close(fs);
12855 }
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000012856 exit(EXIT_UNCORRECTED);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012857}
12858
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012859void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
12860 struct ext2_inode * inode, const char *proc)
12861{
12862 int retval;
12863
12864 retval = ext2fs_read_inode(ctx->fs, ino, inode);
12865 if (retval) {
12866 com_err("ext2fs_read_inode", retval,
12867 _("while reading inode %ld in %s"), ino, proc);
12868 fatal_error(ctx, 0);
12869 }
12870}
12871
12872extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
12873 struct ext2_inode * inode, int bufsize,
12874 const char *proc)
12875{
12876 int retval;
12877
12878 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
12879 if (retval) {
12880 com_err("ext2fs_write_inode", retval,
12881 _("while writing inode %ld in %s"), ino, proc);
12882 fatal_error(ctx, 0);
12883 }
12884}
12885
12886extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
12887 struct ext2_inode * inode, const char *proc)
12888{
12889 int retval;
12890
12891 retval = ext2fs_write_inode(ctx->fs, ino, inode);
12892 if (retval) {
12893 com_err("ext2fs_write_inode", retval,
12894 _("while writing inode %ld in %s"), ino, proc);
12895 fatal_error(ctx, 0);
12896 }
12897}
12898
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012899blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
12900 io_manager manager)
12901{
12902 struct ext2_super_block *sb;
12903 io_channel io = NULL;
12904 void *buf = NULL;
12905 int blocksize;
12906 blk_t superblock, ret_sb = 8193;
12907
12908 if (fs && fs->super) {
12909 ret_sb = (fs->super->s_blocks_per_group +
12910 fs->super->s_first_data_block);
12911 if (ctx) {
12912 ctx->superblock = ret_sb;
12913 ctx->blocksize = fs->blocksize;
12914 }
12915 return ret_sb;
12916 }
12917
12918 if (ctx) {
12919 if (ctx->blocksize) {
12920 ret_sb = ctx->blocksize * 8;
12921 if (ctx->blocksize == 1024)
12922 ret_sb++;
12923 ctx->superblock = ret_sb;
12924 return ret_sb;
12925 }
12926 ctx->superblock = ret_sb;
12927 ctx->blocksize = 1024;
12928 }
12929
12930 if (!name || !manager)
12931 goto cleanup;
12932
12933 if (manager->open(name, 0, &io) != 0)
12934 goto cleanup;
12935
12936 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
12937 goto cleanup;
12938 sb = (struct ext2_super_block *) buf;
12939
12940 for (blocksize = EXT2_MIN_BLOCK_SIZE;
12941 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
12942 superblock = blocksize*8;
12943 if (blocksize == 1024)
12944 superblock++;
12945 io_channel_set_blksize(io, blocksize);
12946 if (io_channel_read_blk(io, superblock,
12947 -SUPERBLOCK_SIZE, buf))
12948 continue;
12949#ifdef EXT2FS_ENABLE_SWAPFS
12950 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
12951 ext2fs_swap_super(sb);
12952#endif
12953 if (sb->s_magic == EXT2_SUPER_MAGIC) {
12954 ret_sb = superblock;
12955 if (ctx) {
12956 ctx->superblock = superblock;
12957 ctx->blocksize = blocksize;
12958 }
12959 break;
12960 }
12961 }
12962
12963cleanup:
12964 if (io)
12965 io_channel_close(io);
Rob Landleye7c43b62006-03-01 16:39:45 +000012966 ext2fs_free_mem(&buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012967 return (ret_sb);
12968}
12969
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012970
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012971/*
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012972 * This function runs through the e2fsck passes and calls them all,
12973 * returning restart, abort, or cancel as necessary...
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012974 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012975typedef void (*pass_t)(e2fsck_t ctx);
12976
12977static const pass_t e2fsck_passes[] = {
12978 e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
12979 e2fsck_pass5, 0 };
12980
12981#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
12982
12983static int e2fsck_run(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012984{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012985 int i;
12986 pass_t e2fsck_pass;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012987
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012988 if (setjmp(ctx->abort_loc)) {
12989 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
12990 return (ctx->flags & E2F_FLAG_RUN_RETURN);
12991 }
12992 ctx->flags |= E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012993
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012994 for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
12995 if (ctx->flags & E2F_FLAG_RUN_RETURN)
12996 break;
12997 e2fsck_pass(ctx);
12998 if (ctx->progress)
12999 (void) (ctx->progress)(ctx, 0, 0, 0);
13000 }
13001 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013002
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013003 if (ctx->flags & E2F_FLAG_RUN_RETURN)
13004 return (ctx->flags & E2F_FLAG_RUN_RETURN);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013005 return 0;
13006}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013007
13008
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013009/*
13010 * unix.c - The unix-specific code for e2fsck
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013011 */
13012
13013
Mike Frysinger51a43b42005-09-24 07:11:16 +000013014/* Command line options */
13015static int swapfs;
13016#ifdef ENABLE_SWAPFS
13017static int normalize_swapfs;
13018#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013019static int cflag; /* check disk */
Mike Frysinger51a43b42005-09-24 07:11:16 +000013020static int show_version_only;
13021static int verbose;
13022
13023static int replace_bad_blocks;
13024static int keep_bad_blocks;
13025static char *bad_blocks_file;
13026
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013027#define P_E2(singular, plural, n) n, ((n) == 1 ? singular : plural)
13028
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013029static void show_stats(e2fsck_t ctx)
Mike Frysinger51a43b42005-09-24 07:11:16 +000013030{
13031 ext2_filsys fs = ctx->fs;
13032 int inodes, inodes_used, blocks, blocks_used;
13033 int dir_links;
13034 int num_files, num_links;
13035 int frag_percent;
13036
13037 dir_links = 2 * ctx->fs_directory_count - 1;
13038 num_files = ctx->fs_total_count - dir_links;
13039 num_links = ctx->fs_links_count - dir_links;
13040 inodes = fs->super->s_inodes_count;
13041 inodes_used = (fs->super->s_inodes_count -
13042 fs->super->s_free_inodes_count);
13043 blocks = fs->super->s_blocks_count;
13044 blocks_used = (fs->super->s_blocks_count -
13045 fs->super->s_free_blocks_count);
13046
13047 frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
13048 frag_percent = (frag_percent + 5) / 10;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013049
Mike Frysinger51a43b42005-09-24 07:11:16 +000013050 if (!verbose) {
13051 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
13052 ctx->device_name, inodes_used, inodes,
13053 frag_percent / 10, frag_percent % 10,
13054 blocks_used, blocks);
13055 return;
13056 }
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013057 printf ("\n%8d inode%s used (%d%%)\n", P_E2("", "s", inodes_used),
13058 100 * inodes_used / inodes);
13059 printf ("%8d non-contiguous inode%s (%0d.%d%%)\n",
13060 P_E2("", "s", ctx->fs_fragmented),
13061 frag_percent / 10, frag_percent % 10);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013062 printf (_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"),
13063 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013064 printf ("%8d block%s used (%d%%)\n", P_E2("", "s", blocks_used),
13065 (int) ((long long) 100 * blocks_used / blocks));
13066 printf ("%8d bad block%s\n", P_E2("", "s", ctx->fs_badblocks_count));
13067 printf ("%8d large file%s\n", P_E2("", "s", ctx->large_files));
13068 printf ("\n%8d regular file%s\n", P_E2("", "s", ctx->fs_regular_count));
13069 printf ("%8d director%s\n", P_E2("y", "ies", ctx->fs_directory_count));
13070 printf ("%8d character device file%s\n", P_E2("", "s", ctx->fs_chardev_count));
13071 printf ("%8d block device file%s\n", P_E2("", "s", ctx->fs_blockdev_count));
13072 printf ("%8d fifo%s\n", P_E2("", "s", ctx->fs_fifo_count));
13073 printf ("%8d link%s\n", P_E2("", "s", ctx->fs_links_count - dir_links));
13074 printf ("%8d symbolic link%s", P_E2("", "s", ctx->fs_symlinks_count));
13075 printf (" (%d fast symbolic link%s)\n", P_E2("", "s", ctx->fs_fast_symlinks_count));
13076 printf ("%8d socket%s--------\n\n", P_E2("", "s", ctx->fs_sockets_count));
13077 printf ("%8d file%s\n", P_E2("", "s", ctx->fs_total_count - dir_links));
Mike Frysinger51a43b42005-09-24 07:11:16 +000013078}
13079
13080static void check_mount(e2fsck_t ctx)
13081{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013082 errcode_t retval;
13083 int cont;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013084
13085 retval = ext2fs_check_if_mounted(ctx->filesystem_name,
13086 &ctx->mount_flags);
13087 if (retval) {
13088 com_err("ext2fs_check_if_mount", retval,
13089 _("while determining whether %s is mounted."),
13090 ctx->filesystem_name);
13091 return;
13092 }
13093
13094 /*
13095 * If the filesystem isn't mounted, or it's the root filesystem
13096 * and it's mounted read-only, then everything's fine.
13097 */
13098 if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) ||
13099 ((ctx->mount_flags & EXT2_MF_ISROOT) &&
13100 (ctx->mount_flags & EXT2_MF_READONLY)))
13101 return;
13102
13103 if (ctx->options & E2F_OPT_READONLY) {
13104 printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name);
13105 return;
13106 }
13107
13108 printf(_("%s is mounted. "), ctx->filesystem_name);
13109 if (!ctx->interactive)
13110 fatal_error(ctx, _("Cannot continue, aborting.\n\n"));
13111 printf(_("\n\n\007\007\007\007WARNING!!! "
13112 "Running e2fsck on a mounted filesystem may cause\n"
13113 "SEVERE filesystem damage.\007\007\007\n\n"));
13114 cont = ask_yn(_("Do you really want to continue"), -1);
13115 if (!cont) {
13116 printf (_("check aborted.\n"));
13117 exit (0);
13118 }
13119 return;
13120}
13121
13122static int is_on_batt(void)
13123{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013124 FILE *f;
13125 DIR *d;
13126 char tmp[80], tmp2[80], fname[80];
13127 unsigned int acflag;
13128 struct dirent* de;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013129
13130 f = fopen("/proc/apm", "r");
13131 if (f) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013132 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
Mike Frysinger51a43b42005-09-24 07:11:16 +000013133 acflag = 1;
13134 fclose(f);
13135 return (acflag != 1);
13136 }
13137 d = opendir("/proc/acpi/ac_adapter");
13138 if (d) {
13139 while ((de=readdir(d)) != NULL) {
13140 if (!strncmp(".", de->d_name, 1))
13141 continue;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013142 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state",
Mike Frysinger51a43b42005-09-24 07:11:16 +000013143 de->d_name);
13144 f = fopen(fname, "r");
13145 if (!f)
13146 continue;
13147 if (fscanf(f, "%s %s", tmp2, tmp) != 2)
13148 tmp[0] = 0;
13149 fclose(f);
13150 if (strncmp(tmp, "off-line", 8) == 0) {
13151 closedir(d);
13152 return 1;
13153 }
13154 }
13155 closedir(d);
13156 }
13157 return 0;
13158}
13159
13160/*
13161 * This routine checks to see if a filesystem can be skipped; if so,
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000013162 * it will exit with EXIT_OK. Under some conditions it will print a
Mike Frysinger51a43b42005-09-24 07:11:16 +000013163 * message explaining why a check is being forced.
13164 */
13165static void check_if_skip(e2fsck_t ctx)
13166{
13167 ext2_filsys fs = ctx->fs;
13168 const char *reason = NULL;
13169 unsigned int reason_arg = 0;
13170 long next_check;
13171 int batt = is_on_batt();
13172 time_t now = time(0);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013173
Mike Frysinger51a43b42005-09-24 07:11:16 +000013174 if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file ||
13175 cflag || swapfs)
13176 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013177
Mike Frysinger51a43b42005-09-24 07:11:16 +000013178 if ((fs->super->s_state & EXT2_ERROR_FS) ||
13179 !ext2fs_test_valid(fs))
13180 reason = _(" contains a file system with errors");
13181 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
13182 reason = _(" was not cleanly unmounted");
13183 else if ((fs->super->s_max_mnt_count > 0) &&
13184 (fs->super->s_mnt_count >=
13185 (unsigned) fs->super->s_max_mnt_count)) {
13186 reason = _(" has been mounted %u times without being checked");
13187 reason_arg = fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013188 if (batt && (fs->super->s_mnt_count <
Mike Frysinger51a43b42005-09-24 07:11:16 +000013189 (unsigned) fs->super->s_max_mnt_count*2))
13190 reason = 0;
13191 } else if (fs->super->s_checkinterval &&
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013192 ((now - fs->super->s_lastcheck) >=
Mike Frysinger51a43b42005-09-24 07:11:16 +000013193 fs->super->s_checkinterval)) {
13194 reason = _(" has gone %u days without being checked");
13195 reason_arg = (now - fs->super->s_lastcheck)/(3600*24);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013196 if (batt && ((now - fs->super->s_lastcheck) <
Mike Frysinger51a43b42005-09-24 07:11:16 +000013197 fs->super->s_checkinterval*2))
13198 reason = 0;
13199 }
13200 if (reason) {
13201 fputs(ctx->device_name, stdout);
13202 printf(reason, reason_arg);
13203 fputs(_(", check forced.\n"), stdout);
13204 return;
13205 }
13206 printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name,
13207 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
13208 fs->super->s_inodes_count,
13209 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
13210 fs->super->s_blocks_count);
13211 next_check = 100000;
13212 if (fs->super->s_max_mnt_count > 0) {
13213 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013214 if (next_check <= 0)
Mike Frysinger51a43b42005-09-24 07:11:16 +000013215 next_check = 1;
13216 }
13217 if (fs->super->s_checkinterval &&
13218 ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval))
13219 next_check = 1;
13220 if (next_check <= 5) {
13221 if (next_check == 1)
13222 fputs(_(" (check after next mount)"), stdout);
13223 else
13224 printf(_(" (check in %ld mounts)"), next_check);
13225 }
13226 fputc('\n', stdout);
13227 ext2fs_close(fs);
13228 ctx->fs = NULL;
13229 e2fsck_free_context(ctx);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000013230 exit(EXIT_OK);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013231}
13232
13233/*
13234 * For completion notice
13235 */
13236struct percent_tbl {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013237 int max_pass;
13238 int table[32];
Mike Frysinger51a43b42005-09-24 07:11:16 +000013239};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013240static const struct percent_tbl e2fsck_tbl = {
Mike Frysinger51a43b42005-09-24 07:11:16 +000013241 5, { 0, 70, 90, 92, 95, 100 }
13242};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013243
Mike Frysinger51a43b42005-09-24 07:11:16 +000013244static char bar[128], spaces[128];
13245
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013246static float calc_percent(const struct percent_tbl *tbl, int pass, int curr,
Mike Frysinger51a43b42005-09-24 07:11:16 +000013247 int max)
13248{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013249 float percent;
13250
Mike Frysinger51a43b42005-09-24 07:11:16 +000013251 if (pass <= 0)
13252 return 0.0;
13253 if (pass > tbl->max_pass || max == 0)
13254 return 100.0;
13255 percent = ((float) curr) / ((float) max);
13256 return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
13257 + tbl->table[pass-1]);
13258}
13259
Rob Landleydfba7412006-03-06 20:47:33 +000013260void e2fsck_clear_progbar(e2fsck_t ctx)
Mike Frysinger51a43b42005-09-24 07:11:16 +000013261{
13262 if (!(ctx->flags & E2F_FLAG_PROG_BAR))
13263 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013264
Mike Frysinger51a43b42005-09-24 07:11:16 +000013265 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80),
13266 ctx->stop_meta);
13267 fflush(stdout);
13268 ctx->flags &= ~E2F_FLAG_PROG_BAR;
13269}
13270
13271int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
13272 unsigned int dpynum)
13273{
13274 static const char spinner[] = "\\|/-";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013275 int i;
13276 unsigned int tick;
13277 struct timeval tv;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013278 int dpywidth;
13279 int fixed_percent;
13280
13281 if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
13282 return 0;
13283
13284 /*
13285 * Calculate the new progress position. If the
13286 * percentage hasn't changed, then we skip out right
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013287 * away.
Mike Frysinger51a43b42005-09-24 07:11:16 +000013288 */
13289 fixed_percent = (int) ((10 * percent) + 0.5);
13290 if (ctx->progress_last_percent == fixed_percent)
13291 return 0;
13292 ctx->progress_last_percent = fixed_percent;
13293
13294 /*
13295 * If we've already updated the spinner once within
13296 * the last 1/8th of a second, no point doing it
13297 * again.
13298 */
13299 gettimeofday(&tv, NULL);
13300 tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8));
13301 if ((tick == ctx->progress_last_time) &&
13302 (fixed_percent != 0) && (fixed_percent != 1000))
13303 return 0;
13304 ctx->progress_last_time = tick;
13305
13306 /*
13307 * Advance the spinner, and note that the progress bar
13308 * will be on the screen
13309 */
13310 ctx->progress_pos = (ctx->progress_pos+1) & 3;
13311 ctx->flags |= E2F_FLAG_PROG_BAR;
13312
13313 dpywidth = 66 - strlen(label);
13314 dpywidth = 8 * (dpywidth / 8);
13315 if (dpynum)
13316 dpywidth -= 8;
13317
13318 i = ((percent * dpywidth) + 50) / 100;
13319 printf("%s%s: |%s%s", ctx->start_meta, label,
13320 bar + (sizeof(bar) - (i+1)),
13321 spaces + (sizeof(spaces) - (dpywidth - i + 1)));
13322 if (fixed_percent == 1000)
13323 fputc('|', stdout);
13324 else
13325 fputc(spinner[ctx->progress_pos & 3], stdout);
13326 printf(" %4.1f%% ", percent);
13327 if (dpynum)
13328 printf("%u\r", dpynum);
13329 else
13330 fputs(" \r", stdout);
13331 fputs(ctx->stop_meta, stdout);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013332
Mike Frysinger51a43b42005-09-24 07:11:16 +000013333 if (fixed_percent == 1000)
13334 e2fsck_clear_progbar(ctx);
13335 fflush(stdout);
13336
13337 return 0;
13338}
13339
13340static int e2fsck_update_progress(e2fsck_t ctx, int pass,
13341 unsigned long cur, unsigned long max)
13342{
13343 char buf[80];
13344 float percent;
13345
13346 if (pass == 0)
13347 return 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013348
Mike Frysinger51a43b42005-09-24 07:11:16 +000013349 if (ctx->progress_fd) {
13350 sprintf(buf, "%d %lu %lu\n", pass, cur, max);
13351 write(ctx->progress_fd, buf, strlen(buf));
13352 } else {
13353 percent = calc_percent(&e2fsck_tbl, pass, cur, max);
13354 e2fsck_simple_progress(ctx, ctx->device_name,
13355 percent, 0);
13356 }
13357 return 0;
13358}
13359
Mike Frysinger51a43b42005-09-24 07:11:16 +000013360static void reserve_stdio_fds(void)
13361{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013362 int fd;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013363
13364 while (1) {
"Vladimir N. Oleynik"6c35c7c2005-10-12 15:34:25 +000013365 fd = open(bb_dev_null, O_RDWR);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013366 if (fd > 2)
13367 break;
13368 if (fd < 0) {
13369 fprintf(stderr, _("ERROR: Couldn't open "
13370 "/dev/null (%s)\n"),
13371 strerror(errno));
13372 break;
13373 }
13374 }
13375 close(fd);
13376}
13377
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000013378static void signal_progress_on(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000013379{
13380 e2fsck_t ctx = e2fsck_global_ctx;
13381
13382 if (!ctx)
13383 return;
13384
13385 ctx->progress = e2fsck_update_progress;
13386 ctx->progress_fd = 0;
13387}
13388
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000013389static void signal_progress_off(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000013390{
13391 e2fsck_t ctx = e2fsck_global_ctx;
13392
13393 if (!ctx)
13394 return;
13395
13396 e2fsck_clear_progbar(ctx);
13397 ctx->progress = 0;
13398}
13399
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000013400static void signal_cancel(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000013401{
13402 e2fsck_t ctx = e2fsck_global_ctx;
13403
13404 if (!ctx)
13405 exit(FSCK_CANCELED);
13406
13407 ctx->flags |= E2F_FLAG_CANCEL;
13408}
Mike Frysinger51a43b42005-09-24 07:11:16 +000013409
13410static void parse_extended_opts(e2fsck_t ctx, const char *opts)
13411{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013412 char *buf, *token, *next, *p, *arg;
13413 int ea_ver;
13414 int extended_usage = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013415
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013416 buf = string_copy(opts, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013417 for (token = buf; token && *token; token = next) {
13418 p = strchr(token, ',');
13419 next = 0;
13420 if (p) {
13421 *p = 0;
13422 next = p+1;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013423 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000013424 arg = strchr(token, '=');
13425 if (arg) {
13426 *arg = 0;
13427 arg++;
13428 }
13429 if (strcmp(token, "ea_ver") == 0) {
13430 if (!arg) {
13431 extended_usage++;
13432 continue;
13433 }
13434 ea_ver = strtoul(arg, &p, 0);
13435 if (*p ||
13436 ((ea_ver != 1) && (ea_ver != 2))) {
13437 fprintf(stderr,
13438 _("Invalid EA version.\n"));
13439 extended_usage++;
13440 continue;
13441 }
13442 ctx->ext_attr_ver = ea_ver;
Mike Frysinger874af852006-03-08 07:03:27 +000013443 } else {
13444 fprintf(stderr, _("Unknown extended option: %s\n"),
13445 token);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013446 extended_usage++;
Mike Frysinger874af852006-03-08 07:03:27 +000013447 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000013448 }
13449 if (extended_usage) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013450 bb_error_msg_and_die(
13451 "Extended options are separated by commas, "
Mike Frysinger51a43b42005-09-24 07:11:16 +000013452 "and may take an argument which\n"
13453 "is set off by an equals ('=') sign. "
Mike Frysinger874af852006-03-08 07:03:27 +000013454 "Valid extended options are:\n"
13455 "\tea_ver=<ea_version (1 or 2)>\n\n");
Mike Frysinger51a43b42005-09-24 07:11:16 +000013456 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013457}
Mike Frysinger51a43b42005-09-24 07:11:16 +000013458
13459
13460static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
13461{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013462 int flush = 0;
13463 int c, fd;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013464 e2fsck_t ctx;
13465 errcode_t retval;
13466 struct sigaction sa;
13467 char *extended_opts = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013468
13469 retval = e2fsck_allocate_context(&ctx);
13470 if (retval)
13471 return retval;
13472
13473 *ret_ctx = ctx;
13474
13475 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
13476 setvbuf(stderr, NULL, _IONBF, BUFSIZ);
13477 if (isatty(0) && isatty(1)) {
13478 ctx->interactive = 1;
13479 } else {
13480 ctx->start_meta[0] = '\001';
13481 ctx->stop_meta[0] = '\002';
13482 }
13483 memset(bar, '=', sizeof(bar)-1);
13484 memset(spaces, ' ', sizeof(spaces)-1);
13485 blkid_get_cache(&ctx->blkid, NULL);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013486
Mike Frysinger51a43b42005-09-24 07:11:16 +000013487 if (argc && *argv)
13488 ctx->program_name = *argv;
13489 else
13490 ctx->program_name = "e2fsck";
13491 while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
13492 switch (c) {
13493 case 'C':
13494 ctx->progress = e2fsck_update_progress;
13495 ctx->progress_fd = atoi(optarg);
13496 if (!ctx->progress_fd)
13497 break;
13498 /* Validate the file descriptor to avoid disasters */
13499 fd = dup(ctx->progress_fd);
13500 if (fd < 0) {
13501 fprintf(stderr,
13502 _("Error validating file descriptor %d: %s\n"),
13503 ctx->progress_fd,
13504 error_message(errno));
13505 fatal_error(ctx,
13506 _("Invalid completion information file descriptor"));
13507 } else
13508 close(fd);
13509 break;
13510 case 'D':
13511 ctx->options |= E2F_OPT_COMPRESS_DIRS;
13512 break;
13513 case 'E':
13514 extended_opts = optarg;
13515 break;
13516 case 'p':
13517 case 'a':
13518 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) {
13519 conflict_opt:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013520 fatal_error(ctx,
Mike Frysinger51a43b42005-09-24 07:11:16 +000013521 _("Only one the options -p/-a, -n or -y may be specified."));
13522 }
13523 ctx->options |= E2F_OPT_PREEN;
13524 break;
13525 case 'n':
13526 if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
13527 goto conflict_opt;
13528 ctx->options |= E2F_OPT_NO;
13529 break;
13530 case 'y':
13531 if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO))
13532 goto conflict_opt;
13533 ctx->options |= E2F_OPT_YES;
13534 break;
13535 case 't':
Rob Landley3e72c592006-04-06 22:49:04 +000013536 /* FIXME - This needs to go away in a future path - will change binary */
Mike Frysinger51a43b42005-09-24 07:11:16 +000013537 fprintf(stderr, _("The -t option is not "
13538 "supported on this version of e2fsck.\n"));
Mike Frysinger51a43b42005-09-24 07:11:16 +000013539 break;
13540 case 'c':
13541 if (cflag++)
13542 ctx->options |= E2F_OPT_WRITECHECK;
13543 ctx->options |= E2F_OPT_CHECKBLOCKS;
13544 break;
13545 case 'r':
13546 /* What we do by default, anyway! */
13547 break;
13548 case 'b':
13549 ctx->use_superblock = atoi(optarg);
13550 ctx->flags |= E2F_FLAG_SB_SPECIFIED;
13551 break;
13552 case 'B':
13553 ctx->blocksize = atoi(optarg);
13554 break;
13555 case 'I':
13556 ctx->inode_buffer_blocks = atoi(optarg);
13557 break;
13558 case 'j':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013559 ctx->journal_name = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013560 break;
13561 case 'P':
13562 ctx->process_inode_size = atoi(optarg);
13563 break;
13564 case 'L':
13565 replace_bad_blocks++;
13566 case 'l':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013567 bad_blocks_file = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013568 break;
13569 case 'd':
13570 ctx->options |= E2F_OPT_DEBUG;
13571 break;
13572 case 'f':
13573 ctx->options |= E2F_OPT_FORCE;
13574 break;
13575 case 'F':
13576 flush = 1;
13577 break;
13578 case 'v':
13579 verbose = 1;
13580 break;
13581 case 'V':
13582 show_version_only = 1;
13583 break;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013584 case 'N':
13585 ctx->device_name = optarg;
13586 break;
13587#ifdef ENABLE_SWAPFS
13588 case 's':
13589 normalize_swapfs = 1;
13590 case 'S':
13591 swapfs = 1;
13592 break;
13593#else
13594 case 's':
13595 case 'S':
13596 fprintf(stderr, _("Byte-swapping filesystems "
13597 "not compiled in this version "
13598 "of e2fsck\n"));
13599 exit(1);
13600#endif
13601 case 'k':
13602 keep_bad_blocks++;
13603 break;
13604 default:
13605 usage();
13606 }
13607 if (show_version_only)
13608 return 0;
13609 if (optind != argc - 1)
13610 usage();
13611 if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
13612 !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
13613 ctx->options |= E2F_OPT_READONLY;
13614 ctx->io_options = strchr(argv[optind], '?');
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013615 if (ctx->io_options)
Mike Frysinger51a43b42005-09-24 07:11:16 +000013616 *ctx->io_options++ = 0;
13617 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
13618 if (!ctx->filesystem_name) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013619 com_err(ctx->program_name, 0, _("Unable to resolve '%s'"),
Mike Frysinger51a43b42005-09-24 07:11:16 +000013620 argv[optind]);
13621 fatal_error(ctx, 0);
13622 }
13623 if (extended_opts)
13624 parse_extended_opts(ctx, extended_opts);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013625
Mike Frysinger51a43b42005-09-24 07:11:16 +000013626 if (flush) {
13627 fd = open(ctx->filesystem_name, O_RDONLY, 0);
13628 if (fd < 0) {
13629 com_err("open", errno,
13630 _("while opening %s for flushing"),
13631 ctx->filesystem_name);
13632 fatal_error(ctx, 0);
13633 }
13634 if ((retval = ext2fs_sync_device(fd, 1))) {
13635 com_err("ext2fs_sync_device", retval,
13636 _("while trying to flush %s"),
13637 ctx->filesystem_name);
13638 fatal_error(ctx, 0);
13639 }
13640 close(fd);
13641 }
13642#ifdef ENABLE_SWAPFS
13643 if (swapfs) {
13644 if (cflag || bad_blocks_file) {
13645 fprintf(stderr, _("Incompatible options not "
13646 "allowed when byte-swapping.\n"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000013647 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013648 }
13649 }
13650#endif
13651 if (cflag && bad_blocks_file) {
13652 fprintf(stderr, _("The -c and the -l/-L options may "
13653 "not be both used at the same time.\n"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000013654 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013655 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000013656 /*
13657 * Set up signal action
13658 */
13659 memset(&sa, 0, sizeof(struct sigaction));
13660 sa.sa_handler = signal_cancel;
13661 sigaction(SIGINT, &sa, 0);
13662 sigaction(SIGTERM, &sa, 0);
13663#ifdef SA_RESTART
13664 sa.sa_flags = SA_RESTART;
13665#endif
13666 e2fsck_global_ctx = ctx;
13667 sa.sa_handler = signal_progress_on;
13668 sigaction(SIGUSR1, &sa, 0);
13669 sa.sa_handler = signal_progress_off;
13670 sigaction(SIGUSR2, &sa, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013671
13672 /* Update our PATH to include /sbin if we need to run badblocks */
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000013673 if (cflag)
13674 e2fs_set_sbin_path();
Mike Frysinger51a43b42005-09-24 07:11:16 +000013675 return 0;
13676}
13677
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013678static const char my_ver_string[] = E2FSPROGS_VERSION;
13679static const char my_ver_date[] = E2FSPROGS_DATE;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013680
Mike Frysinger51a43b42005-09-24 07:11:16 +000013681int e2fsck_main (int argc, char *argv[])
13682{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013683 errcode_t retval;
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000013684 int exit_value = EXIT_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013685 ext2_filsys fs = 0;
13686 io_manager io_ptr;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013687 struct ext2_super_block *sb;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013688 const char *lib_ver_date;
13689 int my_ver, lib_ver;
13690 e2fsck_t ctx;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013691 struct problem_context pctx;
13692 int flags, run_result;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013693
Mike Frysinger51a43b42005-09-24 07:11:16 +000013694 clear_problem_context(&pctx);
Rob Landley3e72c592006-04-06 22:49:04 +000013695
Mike Frysinger51a43b42005-09-24 07:11:16 +000013696 my_ver = ext2fs_parse_version_string(my_ver_string);
13697 lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
13698 if (my_ver > lib_ver) {
13699 fprintf( stderr, _("Error: ext2fs library version "
13700 "out of date!\n"));
13701 show_version_only++;
13702 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013703
Mike Frysinger51a43b42005-09-24 07:11:16 +000013704 retval = PRS(argc, argv, &ctx);
13705 if (retval) {
13706 com_err("e2fsck", retval,
13707 _("while trying to initialize program"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000013708 exit(EXIT_ERROR);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013709 }
13710 reserve_stdio_fds();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013711
Mike Frysinger51a43b42005-09-24 07:11:16 +000013712 if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
13713 fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string,
13714 my_ver_date);
13715
13716 if (show_version_only) {
13717 fprintf(stderr, _("\tUsing %s, %s\n"),
13718 error_message(EXT2_ET_BASE), lib_ver_date);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000013719 exit(EXIT_OK);
Mike Frysinger51a43b42005-09-24 07:11:16 +000013720 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013721
Mike Frysinger51a43b42005-09-24 07:11:16 +000013722 check_mount(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013723
Mike Frysinger51a43b42005-09-24 07:11:16 +000013724 if (!(ctx->options & E2F_OPT_PREEN) &&
13725 !(ctx->options & E2F_OPT_NO) &&
13726 !(ctx->options & E2F_OPT_YES)) {
13727 if (!ctx->interactive)
13728 fatal_error(ctx,
13729 _("need terminal for interactive repairs"));
13730 }
13731 ctx->superblock = ctx->use_superblock;
13732restart:
13733#ifdef CONFIG_TESTIO_DEBUG
13734 io_ptr = test_io_manager;
13735 test_io_backing_manager = unix_io_manager;
13736#else
13737 io_ptr = unix_io_manager;
13738#endif
13739 flags = 0;
13740 if ((ctx->options & E2F_OPT_READONLY) == 0)
13741 flags |= EXT2_FLAG_RW;
13742
13743 if (ctx->superblock && ctx->blocksize) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013744 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000013745 flags, ctx->superblock, ctx->blocksize,
13746 io_ptr, &fs);
13747 } else if (ctx->superblock) {
13748 int blocksize;
13749 for (blocksize = EXT2_MIN_BLOCK_SIZE;
13750 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013751 retval = ext2fs_open2(ctx->filesystem_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000013752 ctx->io_options, flags,
13753 ctx->superblock, blocksize,
13754 io_ptr, &fs);
13755 if (!retval)
13756 break;
13757 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013758 } else
13759 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000013760 flags, 0, 0, io_ptr, &fs);
13761 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
13762 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
13763 ((retval == EXT2_ET_BAD_MAGIC) ||
13764 ((retval == 0) && ext2fs_check_desc(fs)))) {
13765 if (!fs || (fs->group_desc_count > 1)) {
13766 printf(_("%s trying backup blocks...\n"),
13767 retval ? _("Couldn't find ext2 superblock,") :
13768 _("Group descriptors look bad..."));
13769 get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
13770 if (fs)
13771 ext2fs_close(fs);
13772 goto restart;
13773 }
13774 }
13775 if (retval) {
13776 com_err(ctx->program_name, retval, _("while trying to open %s"),
13777 ctx->filesystem_name);
13778 if (retval == EXT2_ET_REV_TOO_HIGH) {
13779 printf(_("The filesystem revision is apparently "
13780 "too high for this version of e2fsck.\n"
13781 "(Or the filesystem superblock "
13782 "is corrupt)\n\n"));
13783 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
13784 } else if (retval == EXT2_ET_SHORT_READ)
13785 printf(_("Could this be a zero-length partition?\n"));
13786 else if ((retval == EPERM) || (retval == EACCES))
13787 printf(_("You must have %s access to the "
13788 "filesystem or be root\n"),
13789 (ctx->options & E2F_OPT_READONLY) ?
13790 "r/o" : "r/w");
13791 else if (retval == ENXIO)
13792 printf(_("Possibly non-existent or swap device?\n"));
13793#ifdef EROFS
13794 else if (retval == EROFS)
13795 printf(_("Disk write-protected; use the -n option "
13796 "to do a read-only\n"
13797 "check of the device.\n"));
13798#endif
13799 else
13800 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
13801 fatal_error(ctx, 0);
13802 }
13803 ctx->fs = fs;
13804 fs->priv_data = ctx;
13805 sb = fs->super;
13806 if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
13807 com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH,
13808 _("while trying to open %s"),
13809 ctx->filesystem_name);
13810 get_newer:
13811 fatal_error(ctx, _("Get a newer version of e2fsck!"));
13812 }
13813
13814 /*
13815 * Set the device name, which is used whenever we print error
13816 * or informational messages to the user.
13817 */
13818 if (ctx->device_name == 0 &&
13819 (sb->s_volume_name[0] != 0)) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013820 ctx->device_name = string_copy(sb->s_volume_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000013821 sizeof(sb->s_volume_name));
13822 }
13823 if (ctx->device_name == 0)
13824 ctx->device_name = ctx->filesystem_name;
13825
13826 /*
13827 * Make sure the ext3 superblock fields are consistent.
13828 */
13829 retval = e2fsck_check_ext3_journal(ctx);
13830 if (retval) {
13831 com_err(ctx->program_name, retval,
13832 _("while checking ext3 journal for %s"),
13833 ctx->device_name);
13834 fatal_error(ctx, 0);
13835 }
13836
13837 /*
13838 * Check to see if we need to do ext3-style recovery. If so,
13839 * do it, and then restart the fsck.
13840 */
13841 if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
13842 if (ctx->options & E2F_OPT_READONLY) {
13843 printf(_("Warning: skipping journal recovery "
13844 "because doing a read-only filesystem "
13845 "check.\n"));
13846 io_channel_flush(ctx->fs->io);
13847 } else {
13848 if (ctx->flags & E2F_FLAG_RESTARTED) {
13849 /*
13850 * Whoops, we attempted to run the
13851 * journal twice. This should never
13852 * happen, unless the hardware or
13853 * device driver is being bogus.
13854 */
13855 com_err(ctx->program_name, 0,
13856 _("unable to set superblock flags on %s\n"), ctx->device_name);
13857 fatal_error(ctx, 0);
13858 }
13859 retval = e2fsck_run_ext3_journal(ctx);
13860 if (retval) {
13861 com_err(ctx->program_name, retval,
13862 _("while recovering ext3 journal of %s"),
13863 ctx->device_name);
13864 fatal_error(ctx, 0);
13865 }
13866 ext2fs_close(ctx->fs);
13867 ctx->fs = 0;
13868 ctx->flags |= E2F_FLAG_RESTARTED;
13869 goto restart;
13870 }
13871 }
13872
13873 /*
13874 * Check for compatibility with the feature sets. We need to
13875 * be more stringent than ext2fs_open().
13876 */
13877 if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
13878 (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
13879 com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
13880 "(%s)", ctx->device_name);
13881 goto get_newer;
13882 }
13883 if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
13884 com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE,
13885 "(%s)", ctx->device_name);
13886 goto get_newer;
13887 }
13888#ifdef ENABLE_COMPRESSION
Rob Landley3e72c592006-04-06 22:49:04 +000013889 /* FIXME - do we support this at all? */
Mike Frysinger51a43b42005-09-24 07:11:16 +000013890 if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
13891 com_err(ctx->program_name, 0,
13892 _("Warning: compression support is experimental.\n"));
13893#endif
13894#ifndef ENABLE_HTREE
13895 if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
13896 com_err(ctx->program_name, 0,
13897 _("E2fsck not compiled with HTREE support,\n\t"
13898 "but filesystem %s has HTREE directories.\n"),
13899 ctx->device_name);
13900 goto get_newer;
13901 }
13902#endif
13903
13904 /*
13905 * If the user specified a specific superblock, presumably the
13906 * master superblock has been trashed. So we mark the
13907 * superblock as dirty, so it can be written out.
13908 */
13909 if (ctx->superblock &&
13910 !(ctx->options & E2F_OPT_READONLY))
13911 ext2fs_mark_super_dirty(fs);
13912
13913 /*
13914 * We only update the master superblock because (a) paranoia;
13915 * we don't want to corrupt the backup superblocks, and (b) we
13916 * don't need to update the mount count and last checked
13917 * fields in the backup superblock (the kernel doesn't
13918 * update the backup superblocks anyway).
13919 */
13920 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
13921
13922 ehandler_init(fs->io);
13923
13924 if (ctx->superblock)
13925 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
13926 ext2fs_mark_valid(fs);
13927 check_super_block(ctx);
13928 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
13929 fatal_error(ctx, 0);
13930 check_if_skip(ctx);
13931 if (bad_blocks_file)
13932 read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks);
13933 else if (cflag)
13934 read_bad_blocks_file(ctx, 0, !keep_bad_blocks); /* Test disk */
13935 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
13936 fatal_error(ctx, 0);
13937#ifdef ENABLE_SWAPFS
Rob Landley391a9042006-01-23 21:38:06 +000013938
13939#ifdef WORDS_BIGENDIAN
Rob Landley8b606342006-01-24 02:38:28 +000013940#define NATIVE_FLAG EXT2_FLAG_SWAP_BYTES
Rob Landley391a9042006-01-23 21:38:06 +000013941#else
Rob Landley8b606342006-01-24 02:38:28 +000013942#define NATIVE_FLAG 0
Rob Landley391a9042006-01-23 21:38:06 +000013943#endif
13944
13945
Mike Frysinger51a43b42005-09-24 07:11:16 +000013946 if (normalize_swapfs) {
Rob Landley391a9042006-01-23 21:38:06 +000013947 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == NATIVE_FLAG) {
Mike Frysinger51a43b42005-09-24 07:11:16 +000013948 fprintf(stderr, _("%s: Filesystem byte order "
13949 "already normalized.\n"), ctx->device_name);
13950 fatal_error(ctx, 0);
13951 }
13952 }
13953 if (swapfs) {
13954 swap_filesys(ctx);
13955 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
13956 fatal_error(ctx, 0);
13957 }
13958#endif
13959
13960 /*
13961 * Mark the system as valid, 'til proven otherwise
13962 */
13963 ext2fs_mark_valid(fs);
13964
13965 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
13966 if (retval) {
13967 com_err(ctx->program_name, retval,
13968 _("while reading bad blocks inode"));
13969 preenhalt(ctx);
13970 printf(_("This doesn't bode well,"
13971 " but we'll try to go on...\n"));
13972 }
13973
13974 run_result = e2fsck_run(ctx);
13975 e2fsck_clear_progbar(ctx);
13976 if (run_result == E2F_FLAG_RESTART) {
13977 printf(_("Restarting e2fsck from the beginning...\n"));
13978 retval = e2fsck_reset_context(ctx);
13979 if (retval) {
13980 com_err(ctx->program_name, retval,
13981 _("while resetting context"));
13982 fatal_error(ctx, 0);
13983 }
13984 ext2fs_close(fs);
13985 goto restart;
13986 }
13987 if (run_result & E2F_FLAG_CANCEL) {
13988 printf(_("%s: e2fsck canceled.\n"), ctx->device_name ?
13989 ctx->device_name : ctx->filesystem_name);
13990 exit_value |= FSCK_CANCELED;
13991 }
13992 if (run_result & E2F_FLAG_ABORT)
13993 fatal_error(ctx, _("aborted"));
13994
Rob Landley3e72c592006-04-06 22:49:04 +000013995 /* Cleanup */
Mike Frysinger51a43b42005-09-24 07:11:16 +000013996 if (ext2fs_test_changed(fs)) {
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000013997 exit_value |= EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000013998 if (!(ctx->options & E2F_OPT_PREEN))
13999 printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
14000 ctx->device_name);
14001 if (ctx->mount_flags & EXT2_MF_ISROOT) {
14002 printf(_("%s: ***** REBOOT LINUX *****\n"),
14003 ctx->device_name);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014004 exit_value |= EXIT_DESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014005 }
14006 }
14007 if (!ext2fs_test_valid(fs)) {
14008 printf(_("\n%s: ********** WARNING: Filesystem still has "
14009 "errors **********\n\n"), ctx->device_name);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014010 exit_value |= EXIT_UNCORRECTED;
14011 exit_value &= ~EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014012 }
14013 if (exit_value & FSCK_CANCELED)
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014014 exit_value &= ~EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014015 else {
14016 show_stats(ctx);
14017 if (!(ctx->options & E2F_OPT_READONLY)) {
14018 if (ext2fs_test_valid(fs)) {
14019 if (!(sb->s_state & EXT2_VALID_FS))
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014020 exit_value |= EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014021 sb->s_state = EXT2_VALID_FS;
14022 } else
14023 sb->s_state &= ~EXT2_VALID_FS;
14024 sb->s_mnt_count = 0;
14025 sb->s_lastcheck = time(NULL);
14026 ext2fs_mark_super_dirty(fs);
14027 }
14028 }
14029
14030 e2fsck_write_bitmaps(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014031
Mike Frysinger51a43b42005-09-24 07:11:16 +000014032 ext2fs_close(fs);
14033 ctx->fs = NULL;
14034 free(ctx->filesystem_name);
14035 free(ctx->journal_name);
14036 e2fsck_free_context(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014037
Mike Frysinger51a43b42005-09-24 07:11:16 +000014038 return exit_value;
14039}