1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#ifndef _GNU_SOURCE
33#define _GNU_SOURCE 1
34#endif
35
36#include "e2fsck.h"
37
38#define _(x) x
39#define N_(x) x
40
41
42
43
44
45static void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf);
46
47
48static void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
49
50
51static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
52 ext2_ino_t ino, char *buf);
53
54
55static int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
56static errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
57 int num, int gauranteed_size);
58static ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix);
59static errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino,
60 int adj);
61
62
63static void e2fsck_rehash_directories(e2fsck_t ctx);
64
65
66static void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
67 const char *description);
68static int ask(e2fsck_t ctx, const char * string, int def);
69static void e2fsck_read_bitmaps(e2fsck_t ctx);
70static void preenhalt(e2fsck_t ctx);
71static void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
72 struct ext2_inode * inode, const char * proc);
73static void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
74 struct ext2_inode * inode, const char * proc);
75static blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs,
76 const char *name, io_manager manager);
77
78
79static void e2fsck_clear_progbar(e2fsck_t ctx);
80static int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
81 float percent, unsigned int dpynum);
82
83
84
85
86
87
88typedef __u32 problem_t;
89
90struct problem_context {
91 errcode_t errcode;
92 ext2_ino_t ino, ino2, dir;
93 struct ext2_inode *inode;
94 struct ext2_dir_entry *dirent;
95 blk_t blk, blk2;
96 e2_blkcnt_t blkcount;
97 int group;
98 __u64 num;
99 const char *str;
100};
101
102
103
104
105
106static int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx);
107static int end_problem_latch(e2fsck_t ctx, int mask);
108static int set_latch_flags(int mask, int setflags, int clearflags);
109static void clear_problem_context(struct problem_context *ctx);
110
111
112
113
114
115
116
117
118
119#ifndef DICT_H
120#define DICT_H
121
122
123
124
125
126typedef unsigned long dictcount_t;
127#define DICTCOUNT_T_MAX ULONG_MAX
128
129
130
131
132
133typedef enum { dnode_red, dnode_black } dnode_color_t;
134
135typedef struct dnode_t {
136 struct dnode_t *dict_left;
137 struct dnode_t *dict_right;
138 struct dnode_t *dict_parent;
139 dnode_color_t dict_color;
140 const void *dict_key;
141 void *dict_data;
142} dnode_t;
143
144typedef int (*dict_comp_t)(const void *, const void *);
145typedef void (*dnode_free_t)(dnode_t *);
146
147typedef struct dict_t {
148 dnode_t dict_nilnode;
149 dictcount_t dict_nodecount;
150 dictcount_t dict_maxcount;
151 dict_comp_t dict_compare;
152 dnode_free_t dict_freenode;
153 int dict_dupes;
154} dict_t;
155
156typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
157
158typedef struct dict_load_t {
159 dict_t *dict_dictptr;
160 dnode_t dict_nilnode;
161} dict_load_t;
162
163#define dict_count(D) ((D)->dict_nodecount)
164#define dnode_get(N) ((N)->dict_data)
165#define dnode_getkey(N) ((N)->dict_key)
166
167#endif
168
169
170
171
172
173
174
175
176
177
178
179
180struct buffer_head {
181 char b_data[8192];
182 e2fsck_t b_ctx;
183 io_channel b_io;
184 int b_size;
185 blk_t b_blocknr;
186 int b_dirty;
187 int b_uptodate;
188 int b_err;
189};
190
191
192#define K_DEV_FS 1
193#define K_DEV_JOURNAL 2
194
195#define lock_buffer(bh) do {} while (0)
196#define unlock_buffer(bh) do {} while (0)
197#define buffer_req(bh) 1
198#define do_readahead(journal, start) do {} while (0)
199
200static e2fsck_t e2fsck_global_ctx;
201
202typedef struct {
203 int object_length;
204} kmem_cache_t;
205
206#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length)
207
208
209
210
211
212
213static kmem_cache_t * do_cache_create(int len)
214{
215 kmem_cache_t *new_cache;
216
217 new_cache = xmalloc(sizeof(*new_cache));
218 new_cache->object_length = len;
219 return new_cache;
220}
221
222static void do_cache_destroy(kmem_cache_t *cache)
223{
224 free(cache);
225}
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245#define left dict_left
246#define right dict_right
247#define parent dict_parent
248#define color dict_color
249#define key dict_key
250#define data dict_data
251
252#define nilnode dict_nilnode
253#define maxcount dict_maxcount
254#define compare dict_compare
255#define dupes dict_dupes
256
257#define dict_root(D) ((D)->nilnode.left)
258#define dict_nil(D) (&(D)->nilnode)
259
260static void dnode_free(dnode_t *node);
261
262
263
264
265
266
267
268
269static void rotate_left(dnode_t *upper)
270{
271 dnode_t *lower, *lowleft, *upparent;
272
273 lower = upper->right;
274 upper->right = lowleft = lower->left;
275 lowleft->parent = upper;
276
277 lower->parent = upparent = upper->parent;
278
279
280
281
282 if (upper == upparent->left) {
283 upparent->left = lower;
284 } else {
285 assert (upper == upparent->right);
286 upparent->right = lower;
287 }
288
289 lower->left = upper;
290 upper->parent = lower;
291}
292
293
294
295
296
297
298static void rotate_right(dnode_t *upper)
299{
300 dnode_t *lower, *lowright, *upparent;
301
302 lower = upper->left;
303 upper->left = lowright = lower->right;
304 lowright->parent = upper;
305
306 lower->parent = upparent = upper->parent;
307
308 if (upper == upparent->right) {
309 upparent->right = lower;
310 } else {
311 assert (upper == upparent->left);
312 upparent->left = lower;
313 }
314
315 lower->right = upper;
316 upper->parent = lower;
317}
318
319
320
321
322
323
324static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
325{
326 if (node == nil)
327 return;
328 free_nodes(dict, node->left, nil);
329 free_nodes(dict, node->right, nil);
330 dict->dict_freenode(node);
331}
332
333
334
335
336
337
338
339
340static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
341{
342 if (root != nil) {
343 return root == node
344 || verify_dict_has_node(nil, root->left, node)
345 || verify_dict_has_node(nil, root->right, node);
346 }
347 return 0;
348}
349
350
351
352
353
354
355static void dict_set_allocator(dict_t *dict, dnode_free_t fr)
356{
357 assert(dict_count(dict) == 0);
358 dict->dict_freenode = fr;
359}
360
361
362
363
364
365
366static void dict_free_nodes(dict_t *dict)
367{
368 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
369 free_nodes(dict, root, nil);
370 dict->dict_nodecount = 0;
371 dict->nilnode.left = &dict->nilnode;
372 dict->nilnode.right = &dict->nilnode;
373}
374
375
376
377
378
379static dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
380{
381 dict->compare = comp;
382 dict->dict_freenode = dnode_free;
383 dict->dict_nodecount = 0;
384 dict->maxcount = maxcount;
385 dict->nilnode.left = &dict->nilnode;
386 dict->nilnode.right = &dict->nilnode;
387 dict->nilnode.parent = &dict->nilnode;
388 dict->nilnode.color = dnode_black;
389 dict->dupes = 0;
390 return dict;
391}
392
393
394
395
396
397
398
399
400static dnode_t *dict_lookup(dict_t *dict, const void *key)
401{
402 dnode_t *root = dict_root(dict);
403 dnode_t *nil = dict_nil(dict);
404 dnode_t *saved;
405 int result;
406
407
408
409 while (root != nil) {
410 result = dict->compare(key, root->key);
411 if (result < 0)
412 root = root->left;
413 else if (result > 0)
414 root = root->right;
415 else {
416 if (!dict->dupes) {
417 return root;
418 } else {
419 do {
420 saved = root;
421 root = root->left;
422 while (root != nil && dict->compare(key, root->key))
423 root = root->right;
424 } while (root != nil);
425 return saved;
426 }
427 }
428 }
429
430 return NULL;
431}
432
433
434
435
436
437
438
439
440
441static void dict_insert(dict_t *dict, dnode_t *node, const void *key)
442{
443 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
444 dnode_t *parent = nil, *uncle, *grandpa;
445 int result = -1;
446
447 node->key = key;
448
449
450
451 while (where != nil) {
452 parent = where;
453 result = dict->compare(key, where->key);
454
455 assert(dict->dupes || result != 0);
456 if (result < 0)
457 where = where->left;
458 else
459 where = where->right;
460 }
461
462 assert(where == nil);
463
464 if (result < 0)
465 parent->left = node;
466 else
467 parent->right = node;
468
469 node->parent = parent;
470 node->left = nil;
471 node->right = nil;
472
473 dict->dict_nodecount++;
474
475
476
477 node->color = dnode_red;
478
479 while (parent->color == dnode_red) {
480 grandpa = parent->parent;
481 if (parent == grandpa->left) {
482 uncle = grandpa->right;
483 if (uncle->color == dnode_red) {
484 parent->color = dnode_black;
485 uncle->color = dnode_black;
486 grandpa->color = dnode_red;
487 node = grandpa;
488 parent = grandpa->parent;
489 } else {
490 if (node == parent->right) {
491 rotate_left(parent);
492 parent = node;
493 assert (grandpa == parent->parent);
494
495 }
496 parent->color = dnode_black;
497 grandpa->color = dnode_red;
498 rotate_right(grandpa);
499 break;
500 }
501 } else {
502 uncle = grandpa->left;
503 if (uncle->color == dnode_red) {
504 parent->color = dnode_black;
505 uncle->color = dnode_black;
506 grandpa->color = dnode_red;
507 node = grandpa;
508 parent = grandpa->parent;
509 } else {
510 if (node == parent->left) {
511 rotate_right(parent);
512 parent = node;
513 assert (grandpa == parent->parent);
514 }
515 parent->color = dnode_black;
516 grandpa->color = dnode_red;
517 rotate_left(grandpa);
518 break;
519 }
520 }
521 }
522
523 dict_root(dict)->color = dnode_black;
524
525}
526
527
528
529
530
531
532static dnode_t *dnode_init(dnode_t *dnode, void *data)
533{
534 dnode->data = data;
535 dnode->parent = NULL;
536 dnode->left = NULL;
537 dnode->right = NULL;
538 return dnode;
539}
540
541static int dict_alloc_insert(dict_t *dict, const void *key, void *data)
542{
543 dnode_t *node = xmalloc(sizeof(dnode_t));
544
545 dnode_init(node, data);
546 dict_insert(dict, node, key);
547 return 1;
548}
549
550
551
552
553
554
555static dnode_t *dict_first(dict_t *dict)
556{
557 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
558
559 if (root != nil)
560 while ((left = root->left) != nil)
561 root = left;
562
563 return (root == nil) ? NULL : root;
564}
565
566
567
568
569
570
571
572
573static dnode_t *dict_next(dict_t *dict, dnode_t *curr)
574{
575 dnode_t *nil = dict_nil(dict), *parent, *left;
576
577 if (curr->right != nil) {
578 curr = curr->right;
579 while ((left = curr->left) != nil)
580 curr = left;
581 return curr;
582 }
583
584 parent = curr->parent;
585
586 while (parent != nil && curr == parent->right) {
587 curr = parent;
588 parent = curr->parent;
589 }
590
591 return (parent == nil) ? NULL : parent;
592}
593
594
595static void dnode_free(dnode_t *node)
596{
597 free(node);
598}
599
600
601#undef left
602#undef right
603#undef parent
604#undef color
605#undef key
606#undef data
607
608#undef nilnode
609#undef maxcount
610#undef compare
611#undef dupes
612
613
614
615
616
617
618
619
620
621
622
623static void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
624{
625 struct dir_info *dir;
626 int i, j;
627 ext2_ino_t num_dirs;
628 errcode_t retval;
629 unsigned long old_size;
630
631 if (!ctx->dir_info) {
632 ctx->dir_info_count = 0;
633 retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
634 if (retval)
635 num_dirs = 1024;
636 ctx->dir_info_size = num_dirs + 10;
637 ctx->dir_info = (struct dir_info *)
638 e2fsck_allocate_memory(ctx, ctx->dir_info_size
639 * sizeof (struct dir_info),
640 "directory map");
641 }
642
643 if (ctx->dir_info_count >= ctx->dir_info_size) {
644 old_size = ctx->dir_info_size * sizeof(struct dir_info);
645 ctx->dir_info_size += 10;
646 retval = ext2fs_resize_mem(old_size, ctx->dir_info_size *
647 sizeof(struct dir_info),
648 &ctx->dir_info);
649 if (retval) {
650 ctx->dir_info_size -= 10;
651 return;
652 }
653 }
654
655
656
657
658
659
660
661
662
663
664 if (ctx->dir_info_count &&
665 ctx->dir_info[ctx->dir_info_count-1].ino >= ino) {
666 for (i = ctx->dir_info_count-1; i > 0; i--)
667 if (ctx->dir_info[i-1].ino < ino)
668 break;
669 dir = &ctx->dir_info[i];
670 if (dir->ino != ino)
671 for (j = ctx->dir_info_count++; j > i; j--)
672 ctx->dir_info[j] = ctx->dir_info[j-1];
673 } else
674 dir = &ctx->dir_info[ctx->dir_info_count++];
675
676 dir->ino = ino;
677 dir->dotdot = parent;
678 dir->parent = parent;
679}
680
681
682
683
684
685static struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)
686{
687 int low, high, mid;
688
689 low = 0;
690 high = ctx->dir_info_count-1;
691 if (!ctx->dir_info)
692 return 0;
693 if (ino == ctx->dir_info[low].ino)
694 return &ctx->dir_info[low];
695 if (ino == ctx->dir_info[high].ino)
696 return &ctx->dir_info[high];
697
698 while (low < high) {
699 mid = (low+high)/2;
700 if (mid == low || mid == high)
701 break;
702 if (ino == ctx->dir_info[mid].ino)
703 return &ctx->dir_info[mid];
704 if (ino < ctx->dir_info[mid].ino)
705 high = mid;
706 else
707 low = mid;
708 }
709 return 0;
710}
711
712
713
714
715static void e2fsck_free_dir_info(e2fsck_t ctx)
716{
717 ext2fs_free_mem(&ctx->dir_info);
718 ctx->dir_info_size = 0;
719 ctx->dir_info_count = 0;
720}
721
722
723
724
725static int e2fsck_get_num_dirinfo(e2fsck_t ctx)
726{
727 return ctx->dir_info_count;
728}
729
730
731
732
733static struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
734{
735 if (*control >= ctx->dir_info_count)
736 return 0;
737
738 return ctx->dir_info + (*control)++;
739}
740
741
742
743
744
745
746#ifdef ENABLE_HTREE
747
748
749
750
751
752
753static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
754{
755 struct dx_dir_info *dir;
756 int i, j;
757 errcode_t retval;
758 unsigned long old_size;
759
760 if (!ctx->dx_dir_info) {
761 ctx->dx_dir_info_count = 0;
762 ctx->dx_dir_info_size = 100;
763 ctx->dx_dir_info = (struct dx_dir_info *)
764 e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
765 * sizeof (struct dx_dir_info),
766 "directory map");
767 }
768
769 if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
770 old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
771 ctx->dx_dir_info_size += 10;
772 retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
773 sizeof(struct dx_dir_info),
774 &ctx->dx_dir_info);
775 if (retval) {
776 ctx->dx_dir_info_size -= 10;
777 return;
778 }
779 }
780
781
782
783
784
785
786
787
788
789
790 if (ctx->dx_dir_info_count &&
791 ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
792 for (i = ctx->dx_dir_info_count-1; i > 0; i--)
793 if (ctx->dx_dir_info[i-1].ino < ino)
794 break;
795 dir = &ctx->dx_dir_info[i];
796 if (dir->ino != ino)
797 for (j = ctx->dx_dir_info_count++; j > i; j--)
798 ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
799 } else
800 dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
801
802 dir->ino = ino;
803 dir->numblocks = num_blocks;
804 dir->hashversion = 0;
805 dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
806 * sizeof (struct dx_dirblock_info),
807 "dx_block info array");
808
809}
810
811
812
813
814
815static struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino)
816{
817 int low, high, mid;
818
819 low = 0;
820 high = ctx->dx_dir_info_count-1;
821 if (!ctx->dx_dir_info)
822 return 0;
823 if (ino == ctx->dx_dir_info[low].ino)
824 return &ctx->dx_dir_info[low];
825 if (ino == ctx->dx_dir_info[high].ino)
826 return &ctx->dx_dir_info[high];
827
828 while (low < high) {
829 mid = (low+high)/2;
830 if (mid == low || mid == high)
831 break;
832 if (ino == ctx->dx_dir_info[mid].ino)
833 return &ctx->dx_dir_info[mid];
834 if (ino < ctx->dx_dir_info[mid].ino)
835 high = mid;
836 else
837 low = mid;
838 }
839 return 0;
840}
841
842
843
844
845static void e2fsck_free_dx_dir_info(e2fsck_t ctx)
846{
847 int i;
848 struct dx_dir_info *dir;
849
850 if (ctx->dx_dir_info) {
851 dir = ctx->dx_dir_info;
852 for (i=0; i < ctx->dx_dir_info_count; i++) {
853 ext2fs_free_mem(&dir->dx_block);
854 }
855 ext2fs_free_mem(&ctx->dx_dir_info);
856 }
857 ctx->dx_dir_info_size = 0;
858 ctx->dx_dir_info_count = 0;
859}
860
861
862
863
864static struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
865{
866 if (*control >= ctx->dx_dir_info_count)
867 return 0;
868
869 return ctx->dx_dir_info + (*control)++;
870}
871
872#endif
873
874
875
876
877
878
879
880
881static errcode_t e2fsck_allocate_context(e2fsck_t *ret)
882{
883 e2fsck_t context;
884 errcode_t retval;
885
886 retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
887 if (retval)
888 return retval;
889
890 memset(context, 0, sizeof(struct e2fsck_struct));
891
892 context->process_inode_size = 256;
893 context->ext_attr_ver = 2;
894
895 *ret = context;
896 return 0;
897}
898
899struct ea_refcount_el {
900 blk_t ea_blk;
901 int ea_count;
902};
903
904struct ea_refcount {
905 blk_t count;
906 blk_t size;
907 blk_t cursor;
908 struct ea_refcount_el *list;
909};
910
911static void ea_refcount_free(ext2_refcount_t refcount)
912{
913 if (!refcount)
914 return;
915
916 ext2fs_free_mem(&refcount->list);
917 ext2fs_free_mem(&refcount);
918}
919
920
921
922
923
924static errcode_t e2fsck_reset_context(e2fsck_t ctx)
925{
926 ctx->flags = 0;
927 ctx->lost_and_found = 0;
928 ctx->bad_lost_and_found = 0;
929 ext2fs_free_inode_bitmap(ctx->inode_used_map);
930 ctx->inode_used_map = 0;
931 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
932 ctx->inode_dir_map = 0;
933 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
934 ctx->inode_reg_map = 0;
935 ext2fs_free_block_bitmap(ctx->block_found_map);
936 ctx->block_found_map = 0;
937 ext2fs_free_icount(ctx->inode_link_info);
938 ctx->inode_link_info = 0;
939 if (ctx->journal_io) {
940 if (ctx->fs && ctx->fs->io != ctx->journal_io)
941 io_channel_close(ctx->journal_io);
942 ctx->journal_io = 0;
943 }
944 if (ctx->fs) {
945 ext2fs_free_dblist(ctx->fs->dblist);
946 ctx->fs->dblist = 0;
947 }
948 e2fsck_free_dir_info(ctx);
949#ifdef ENABLE_HTREE
950 e2fsck_free_dx_dir_info(ctx);
951#endif
952 ea_refcount_free(ctx->refcount);
953 ctx->refcount = 0;
954 ea_refcount_free(ctx->refcount_extra);
955 ctx->refcount_extra = 0;
956 ext2fs_free_block_bitmap(ctx->block_dup_map);
957 ctx->block_dup_map = 0;
958 ext2fs_free_block_bitmap(ctx->block_ea_map);
959 ctx->block_ea_map = 0;
960 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
961 ctx->inode_bad_map = 0;
962 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
963 ctx->inode_imagic_map = 0;
964 ext2fs_u32_list_free(ctx->dirs_to_hash);
965 ctx->dirs_to_hash = 0;
966
967
968
969
970 ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
971 ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
972 ext2fs_free_mem(&ctx->invalid_inode_table_flag);
973
974
975 ctx->fs_directory_count = 0;
976 ctx->fs_regular_count = 0;
977 ctx->fs_blockdev_count = 0;
978 ctx->fs_chardev_count = 0;
979 ctx->fs_links_count = 0;
980 ctx->fs_symlinks_count = 0;
981 ctx->fs_fast_symlinks_count = 0;
982 ctx->fs_fifo_count = 0;
983 ctx->fs_total_count = 0;
984 ctx->fs_sockets_count = 0;
985 ctx->fs_ind_count = 0;
986 ctx->fs_dind_count = 0;
987 ctx->fs_tind_count = 0;
988 ctx->fs_fragmented = 0;
989 ctx->large_files = 0;
990
991
992 ctx->superblock = ctx->use_superblock;
993
994 return 0;
995}
996
997static void e2fsck_free_context(e2fsck_t ctx)
998{
999 if (!ctx)
1000 return;
1001
1002 e2fsck_reset_context(ctx);
1003 if (ctx->blkid)
1004 blkid_put_cache(ctx->blkid);
1005
1006 ext2fs_free_mem(&ctx);
1007}
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
1023{
1024 ext2_refcount_t refcount;
1025 errcode_t retval;
1026 size_t bytes;
1027
1028 retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount);
1029 if (retval)
1030 return retval;
1031 memset(refcount, 0, sizeof(struct ea_refcount));
1032
1033 if (!size)
1034 size = 500;
1035 refcount->size = size;
1036 bytes = (size_t) (size * sizeof(struct ea_refcount_el));
1037#ifdef DEBUG
1038 printf("Refcount allocated %d entries, %d bytes.\n",
1039 refcount->size, bytes);
1040#endif
1041 retval = ext2fs_get_mem(bytes, &refcount->list);
1042 if (retval)
1043 goto errout;
1044 memset(refcount->list, 0, bytes);
1045
1046 refcount->count = 0;
1047 refcount->cursor = 0;
1048
1049 *ret = refcount;
1050 return 0;
1051
1052errout:
1053 ea_refcount_free(refcount);
1054 return retval;
1055}
1056
1057
1058
1059
1060
1061static void refcount_collapse(ext2_refcount_t refcount)
1062{
1063 unsigned int i, j;
1064 struct ea_refcount_el *list;
1065
1066 list = refcount->list;
1067 for (i = 0, j = 0; i < refcount->count; i++) {
1068 if (list[i].ea_count) {
1069 if (i != j)
1070 list[j] = list[i];
1071 j++;
1072 }
1073 }
1074#if defined(DEBUG) || defined(TEST_PROGRAM)
1075 printf("Refcount_collapse: size was %d, now %d\n",
1076 refcount->count, j);
1077#endif
1078 refcount->count = j;
1079}
1080
1081
1082
1083
1084
1085
1086static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
1087 blk_t blk, int pos)
1088{
1089 struct ea_refcount_el *el;
1090 errcode_t retval;
1091 blk_t new_size = 0;
1092 int num;
1093
1094 if (refcount->count >= refcount->size) {
1095 new_size = refcount->size + 100;
1096#ifdef DEBUG
1097 printf("Reallocating refcount %d entries...\n", new_size);
1098#endif
1099 retval = ext2fs_resize_mem((size_t) refcount->size *
1100 sizeof(struct ea_refcount_el),
1101 (size_t) new_size *
1102 sizeof(struct ea_refcount_el),
1103 &refcount->list);
1104 if (retval)
1105 return 0;
1106 refcount->size = new_size;
1107 }
1108 num = (int) refcount->count - pos;
1109 if (num < 0)
1110 return 0;
1111 if (num) {
1112 memmove(&refcount->list[pos+1], &refcount->list[pos],
1113 sizeof(struct ea_refcount_el) * num);
1114 }
1115 refcount->count++;
1116 el = &refcount->list[pos];
1117 el->ea_count = 0;
1118 el->ea_blk = blk;
1119 return el;
1120}
1121
1122
1123
1124
1125
1126
1127
1128static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
1129 blk_t blk, int create)
1130{
1131 float range;
1132 int low, high, mid;
1133 blk_t lowval, highval;
1134
1135 if (!refcount || !refcount->list)
1136 return 0;
1137retry:
1138 low = 0;
1139 high = (int) refcount->count-1;
1140 if (create && ((refcount->count == 0) ||
1141 (blk > refcount->list[high].ea_blk))) {
1142 if (refcount->count >= refcount->size)
1143 refcount_collapse(refcount);
1144
1145 return insert_refcount_el(refcount, blk,
1146 (unsigned) refcount->count);
1147 }
1148 if (refcount->count == 0)
1149 return 0;
1150
1151 if (refcount->cursor >= refcount->count)
1152 refcount->cursor = 0;
1153 if (blk == refcount->list[refcount->cursor].ea_blk)
1154 return &refcount->list[refcount->cursor++];
1155#ifdef DEBUG
1156 printf("Non-cursor get_refcount_el: %u\n", blk);
1157#endif
1158 while (low <= high) {
1159 if (low == high)
1160 mid = low;
1161 else {
1162
1163 lowval = refcount->list[low].ea_blk;
1164 highval = refcount->list[high].ea_blk;
1165
1166 if (blk < lowval)
1167 range = 0;
1168 else if (blk > highval)
1169 range = 1;
1170 else
1171 range = ((float) (blk - lowval)) /
1172 (highval - lowval);
1173 mid = low + ((int) (range * (high-low)));
1174 }
1175
1176 if (blk == refcount->list[mid].ea_blk) {
1177 refcount->cursor = mid+1;
1178 return &refcount->list[mid];
1179 }
1180 if (blk < refcount->list[mid].ea_blk)
1181 high = mid-1;
1182 else
1183 low = mid+1;
1184 }
1185
1186
1187
1188
1189 if (create) {
1190 if (refcount->count >= refcount->size) {
1191 refcount_collapse(refcount);
1192 if (refcount->count < refcount->size)
1193 goto retry;
1194 }
1195 return insert_refcount_el(refcount, blk, low);
1196 }
1197 return 0;
1198}
1199
1200static errcode_t
1201ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret)
1202{
1203 struct ea_refcount_el *el;
1204
1205 el = get_refcount_el(refcount, blk, 1);
1206 if (!el)
1207 return EXT2_ET_NO_MEMORY;
1208 el->ea_count++;
1209
1210 if (ret)
1211 *ret = el->ea_count;
1212 return 0;
1213}
1214
1215static errcode_t
1216ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret)
1217{
1218 struct ea_refcount_el *el;
1219
1220 el = get_refcount_el(refcount, blk, 0);
1221 if (!el || el->ea_count == 0)
1222 return EXT2_ET_INVALID_ARGUMENT;
1223
1224 el->ea_count--;
1225
1226 if (ret)
1227 *ret = el->ea_count;
1228 return 0;
1229}
1230
1231static errcode_t
1232ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count)
1233{
1234 struct ea_refcount_el *el;
1235
1236
1237
1238
1239 el = get_refcount_el(refcount, blk, count ? 1 : 0);
1240 if (!el)
1241 return count ? EXT2_ET_NO_MEMORY : 0;
1242 el->ea_count = count;
1243 return 0;
1244}
1245
1246static inline void ea_refcount_intr_begin(ext2_refcount_t refcount)
1247{
1248 refcount->cursor = 0;
1249}
1250
1251
1252static blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret)
1253{
1254 struct ea_refcount_el *list;
1255
1256 while (1) {
1257 if (refcount->cursor >= refcount->count)
1258 return 0;
1259 list = refcount->list;
1260 if (list[refcount->cursor].ea_count) {
1261 if (ret)
1262 *ret = list[refcount->cursor].ea_count;
1263 return list[refcount->cursor++].ea_blk;
1264 }
1265 refcount->cursor++;
1266 }
1267}
1268
1269
1270
1271
1272
1273
1274
1275
1276static const char *operation;
1277
1278static errcode_t
1279e2fsck_handle_read_error(io_channel channel, unsigned long block, int count,
1280 void *data, size_t size FSCK_ATTR((unused)),
1281 int actual FSCK_ATTR((unused)), errcode_t error)
1282{
1283 int i;
1284 char *p;
1285 ext2_filsys fs = (ext2_filsys) channel->app_data;
1286 e2fsck_t ctx;
1287
1288 ctx = (e2fsck_t) fs->priv_data;
1289
1290
1291
1292
1293
1294
1295 if (count > 1) {
1296 p = (char *) data;
1297 for (i=0; i < count; i++, p += channel->block_size, block++) {
1298 error = io_channel_read_blk(channel, block,
1299 1, p);
1300 if (error)
1301 return error;
1302 }
1303 return 0;
1304 }
1305 if (operation)
1306 printf(_("Error reading block %lu (%s) while %s. "), block,
1307 error_message(error), operation);
1308 else
1309 printf(_("Error reading block %lu (%s). "), block,
1310 error_message(error));
1311 preenhalt(ctx);
1312 if (ask(ctx, _("Ignore error"), 1)) {
1313 if (ask(ctx, _("Force rewrite"), 1))
1314 io_channel_write_blk(channel, block, 1, data);
1315 return 0;
1316 }
1317
1318 return error;
1319}
1320
1321static errcode_t
1322e2fsck_handle_write_error(io_channel channel, unsigned long block, int count,
1323 const void *data, size_t size FSCK_ATTR((unused)),
1324 int actual FSCK_ATTR((unused)), errcode_t error)
1325{
1326 int i;
1327 const char *p;
1328 ext2_filsys fs = (ext2_filsys) channel->app_data;
1329 e2fsck_t ctx;
1330
1331 ctx = (e2fsck_t) fs->priv_data;
1332
1333
1334
1335
1336
1337
1338 if (count > 1) {
1339 p = (const char *) data;
1340 for (i=0; i < count; i++, p += channel->block_size, block++) {
1341 error = io_channel_write_blk(channel, block,
1342 1, p);
1343 if (error)
1344 return error;
1345 }
1346 return 0;
1347 }
1348
1349 if (operation)
1350 printf(_("Error writing block %lu (%s) while %s. "), block,
1351 error_message(error), operation);
1352 else
1353 printf(_("Error writing block %lu (%s). "), block,
1354 error_message(error));
1355 preenhalt(ctx);
1356 if (ask(ctx, _("Ignore error"), 1))
1357 return 0;
1358
1359 return error;
1360}
1361
1362static const char *ehandler_operation(const char *op)
1363{
1364 const char *ret = operation;
1365
1366 operation = op;
1367 return ret;
1368}
1369
1370static void ehandler_init(io_channel channel)
1371{
1372 channel->read_error = e2fsck_handle_read_error;
1373 channel->write_error = e2fsck_handle_write_error;
1374}
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397#undef USE_INODE_IO
1398
1399
1400
1401
1402
1403static int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys)
1404{
1405#ifdef USE_INODE_IO
1406 *phys = block;
1407 return 0;
1408#else
1409 struct inode *inode = journal->j_inode;
1410 errcode_t retval;
1411 blk_t pblk;
1412
1413 if (!inode) {
1414 *phys = block;
1415 return 0;
1416 }
1417
1418 retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino,
1419 &inode->i_ext2, NULL, 0, block, &pblk);
1420 *phys = pblk;
1421 return retval;
1422#endif
1423}
1424
1425static struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize)
1426{
1427 struct buffer_head *bh;
1428
1429 bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer");
1430 if (!bh)
1431 return NULL;
1432
1433 bh->b_ctx = kdev->k_ctx;
1434 if (kdev->k_dev == K_DEV_FS)
1435 bh->b_io = kdev->k_ctx->fs->io;
1436 else
1437 bh->b_io = kdev->k_ctx->journal_io;
1438 bh->b_size = blocksize;
1439 bh->b_blocknr = blocknr;
1440
1441 return bh;
1442}
1443
1444static void sync_blockdev(kdev_t kdev)
1445{
1446 io_channel io;
1447
1448 if (kdev->k_dev == K_DEV_FS)
1449 io = kdev->k_ctx->fs->io;
1450 else
1451 io = kdev->k_ctx->journal_io;
1452
1453 io_channel_flush(io);
1454}
1455
1456static void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
1457{
1458 int retval;
1459 struct buffer_head *bh;
1460
1461 for (; nr > 0; --nr) {
1462 bh = *bhp++;
1463 if (rw == READ && !bh->b_uptodate) {
1464 retval = io_channel_read_blk(bh->b_io,
1465 bh->b_blocknr,
1466 1, bh->b_data);
1467 if (retval) {
1468 bb_error_msg("while reading block %lu",
1469 (unsigned long) bh->b_blocknr);
1470 bh->b_err = retval;
1471 continue;
1472 }
1473 bh->b_uptodate = 1;
1474 } else if (rw == WRITE && bh->b_dirty) {
1475 retval = io_channel_write_blk(bh->b_io,
1476 bh->b_blocknr,
1477 1, bh->b_data);
1478 if (retval) {
1479 bb_error_msg("while writing block %lu",
1480 (unsigned long) bh->b_blocknr);
1481 bh->b_err = retval;
1482 continue;
1483 }
1484 bh->b_dirty = 0;
1485 bh->b_uptodate = 1;
1486 }
1487 }
1488}
1489
1490static void mark_buffer_dirty(struct buffer_head *bh)
1491{
1492 bh->b_dirty = 1;
1493}
1494
1495static inline void mark_buffer_clean(struct buffer_head * bh)
1496{
1497 bh->b_dirty = 0;
1498}
1499
1500static void brelse(struct buffer_head *bh)
1501{
1502 if (bh->b_dirty)
1503 ll_rw_block(WRITE, 1, &bh);
1504 ext2fs_free_mem(&bh);
1505}
1506
1507static int buffer_uptodate(struct buffer_head *bh)
1508{
1509 return bh->b_uptodate;
1510}
1511
1512static inline void mark_buffer_uptodate(struct buffer_head *bh, int val)
1513{
1514 bh->b_uptodate = val;
1515}
1516
1517static void wait_on_buffer(struct buffer_head *bh)
1518{
1519 if (!bh->b_uptodate)
1520 ll_rw_block(READ, 1, &bh);
1521}
1522
1523
1524static void e2fsck_clear_recover(e2fsck_t ctx, int error)
1525{
1526 ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
1527
1528
1529 if (error)
1530 ctx->fs->super->s_state &= ~EXT2_VALID_FS;
1531 ext2fs_mark_super_dirty(ctx->fs);
1532}
1533
1534static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
1535{
1536 struct ext2_super_block *sb = ctx->fs->super;
1537 struct ext2_super_block jsuper;
1538 struct problem_context pctx;
1539 struct buffer_head *bh;
1540 struct inode *j_inode = NULL;
1541 struct kdev_s *dev_fs = NULL, *dev_journal;
1542 const char *journal_name = 0;
1543 journal_t *journal = NULL;
1544 errcode_t retval = 0;
1545 io_manager io_ptr = 0;
1546 unsigned long start = 0;
1547 blk_t blk;
1548 int ext_journal = 0;
1549 int tried_backup_jnl = 0;
1550 int i;
1551
1552 clear_problem_context(&pctx);
1553
1554 journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
1555 if (!journal) {
1556 return EXT2_ET_NO_MEMORY;
1557 }
1558
1559 dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
1560 if (!dev_fs) {
1561 retval = EXT2_ET_NO_MEMORY;
1562 goto errout;
1563 }
1564 dev_journal = dev_fs+1;
1565
1566 dev_fs->k_ctx = dev_journal->k_ctx = ctx;
1567 dev_fs->k_dev = K_DEV_FS;
1568 dev_journal->k_dev = K_DEV_JOURNAL;
1569
1570 journal->j_dev = dev_journal;
1571 journal->j_fs_dev = dev_fs;
1572 journal->j_inode = NULL;
1573 journal->j_blocksize = ctx->fs->blocksize;
1574
1575 if (uuid_is_null(sb->s_journal_uuid)) {
1576 if (!sb->s_journal_inum)
1577 return EXT2_ET_BAD_INODE_NUM;
1578 j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
1579 "journal inode");
1580 if (!j_inode) {
1581 retval = EXT2_ET_NO_MEMORY;
1582 goto errout;
1583 }
1584
1585 j_inode->i_ctx = ctx;
1586 j_inode->i_ino = sb->s_journal_inum;
1587
1588 if ((retval = ext2fs_read_inode(ctx->fs,
1589 sb->s_journal_inum,
1590 &j_inode->i_ext2))) {
1591 try_backup_journal:
1592 if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
1593 tried_backup_jnl)
1594 goto errout;
1595 memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
1596 memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
1597 EXT2_N_BLOCKS*4);
1598 j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
1599 j_inode->i_ext2.i_links_count = 1;
1600 j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
1601 tried_backup_jnl++;
1602 }
1603 if (!j_inode->i_ext2.i_links_count ||
1604 !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
1605 retval = EXT2_ET_NO_JOURNAL;
1606 goto try_backup_journal;
1607 }
1608 if (j_inode->i_ext2.i_size / journal->j_blocksize <
1609 JFS_MIN_JOURNAL_BLOCKS) {
1610 retval = EXT2_ET_JOURNAL_TOO_SMALL;
1611 goto try_backup_journal;
1612 }
1613 for (i=0; i < EXT2_N_BLOCKS; i++) {
1614 blk = j_inode->i_ext2.i_block[i];
1615 if (!blk) {
1616 if (i < EXT2_NDIR_BLOCKS) {
1617 retval = EXT2_ET_JOURNAL_TOO_SMALL;
1618 goto try_backup_journal;
1619 }
1620 continue;
1621 }
1622 if (blk < sb->s_first_data_block ||
1623 blk >= sb->s_blocks_count) {
1624 retval = EXT2_ET_BAD_BLOCK_NUM;
1625 goto try_backup_journal;
1626 }
1627 }
1628 journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;
1629
1630#ifdef USE_INODE_IO
1631 retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
1632 &j_inode->i_ext2,
1633 &journal_name);
1634 if (retval)
1635 goto errout;
1636
1637 io_ptr = inode_io_manager;
1638#else
1639 journal->j_inode = j_inode;
1640 ctx->journal_io = ctx->fs->io;
1641 if ((retval = journal_bmap(journal, 0, &start)) != 0)
1642 goto errout;
1643#endif
1644 } else {
1645 ext_journal = 1;
1646 if (!ctx->journal_name) {
1647 char uuid[37];
1648
1649 uuid_unparse(sb->s_journal_uuid, uuid);
1650 ctx->journal_name = blkid_get_devname(ctx->blkid,
1651 "UUID", uuid);
1652 if (!ctx->journal_name)
1653 ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
1654 }
1655 journal_name = ctx->journal_name;
1656
1657 if (!journal_name) {
1658 fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
1659 return EXT2_ET_LOAD_EXT_JOURNAL;
1660 }
1661
1662 io_ptr = unix_io_manager;
1663 }
1664
1665#ifndef USE_INODE_IO
1666 if (ext_journal)
1667#endif
1668 retval = io_ptr->open(journal_name, IO_FLAG_RW,
1669 &ctx->journal_io);
1670 if (retval)
1671 goto errout;
1672
1673 io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
1674
1675 if (ext_journal) {
1676 if (ctx->fs->blocksize == 1024)
1677 start = 1;
1678 bh = getblk(dev_journal, start, ctx->fs->blocksize);
1679 if (!bh) {
1680 retval = EXT2_ET_NO_MEMORY;
1681 goto errout;
1682 }
1683 ll_rw_block(READ, 1, &bh);
1684 if ((retval = bh->b_err) != 0)
1685 goto errout;
1686 memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
1687 sizeof(jsuper));
1688 brelse(bh);
1689#if BB_BIG_ENDIAN
1690 if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
1691 ext2fs_swap_super(&jsuper);
1692#endif
1693 if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
1694 !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
1695 fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
1696 retval = EXT2_ET_LOAD_EXT_JOURNAL;
1697 goto errout;
1698 }
1699
1700 if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
1701 sizeof(jsuper.s_uuid))) {
1702 fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
1703 retval = EXT2_ET_LOAD_EXT_JOURNAL;
1704 goto errout;
1705 }
1706
1707 journal->j_maxlen = jsuper.s_blocks_count;
1708 start++;
1709 }
1710
1711 if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
1712 retval = EXT2_ET_NO_MEMORY;
1713 goto errout;
1714 }
1715
1716 journal->j_sb_buffer = bh;
1717 journal->j_superblock = (journal_superblock_t *)bh->b_data;
1718
1719#ifdef USE_INODE_IO
1720 ext2fs_free_mem(&j_inode);
1721#endif
1722
1723 *ret_journal = journal;
1724 return 0;
1725
1726errout:
1727 ext2fs_free_mem(&dev_fs);
1728 ext2fs_free_mem(&j_inode);
1729 ext2fs_free_mem(&journal);
1730 return retval;
1731
1732}
1733
1734static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
1735 struct problem_context *pctx)
1736{
1737 struct ext2_super_block *sb = ctx->fs->super;
1738 int recover = ctx->fs->super->s_feature_incompat &
1739 EXT3_FEATURE_INCOMPAT_RECOVER;
1740 int has_journal = ctx->fs->super->s_feature_compat &
1741 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
1742
1743 if (has_journal || sb->s_journal_inum) {
1744
1745 pctx->ino = sb->s_journal_inum;
1746 if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
1747 if (has_journal && sb->s_journal_inum)
1748 printf("*** ext3 journal has been deleted - "
1749 "filesystem is now ext2 only ***\n\n");
1750 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
1751 sb->s_journal_inum = 0;
1752 ctx->flags |= E2F_FLAG_JOURNAL_INODE;
1753 e2fsck_clear_recover(ctx, 1);
1754 return 0;
1755 }
1756 return EXT2_ET_BAD_INODE_NUM;
1757 } else if (recover) {
1758 if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
1759 e2fsck_clear_recover(ctx, 1);
1760 return 0;
1761 }
1762 return EXT2_ET_UNSUPP_FEATURE;
1763 }
1764 return 0;
1765}
1766
1767#define V1_SB_SIZE 0x0024
1768static void clear_v2_journal_fields(journal_t *journal)
1769{
1770 e2fsck_t ctx = journal->j_dev->k_ctx;
1771 struct problem_context pctx;
1772
1773 clear_problem_context(&pctx);
1774
1775 if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
1776 return;
1777
1778 memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
1779 ctx->fs->blocksize-V1_SB_SIZE);
1780 mark_buffer_dirty(journal->j_sb_buffer);
1781}
1782
1783
1784static errcode_t e2fsck_journal_load(journal_t *journal)
1785{
1786 e2fsck_t ctx = journal->j_dev->k_ctx;
1787 journal_superblock_t *jsb;
1788 struct buffer_head *jbh = journal->j_sb_buffer;
1789 struct problem_context pctx;
1790
1791 clear_problem_context(&pctx);
1792
1793 ll_rw_block(READ, 1, &jbh);
1794 if (jbh->b_err) {
1795 bb_error_msg(_("reading journal superblock"));
1796 return jbh->b_err;
1797 }
1798
1799 jsb = journal->j_superblock;
1800
1801 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
1802 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
1803
1804 switch (ntohl(jsb->s_header.h_blocktype)) {
1805 case JFS_SUPERBLOCK_V1:
1806 journal->j_format_version = 1;
1807 if (jsb->s_feature_compat ||
1808 jsb->s_feature_incompat ||
1809 jsb->s_feature_ro_compat ||
1810 jsb->s_nr_users)
1811 clear_v2_journal_fields(journal);
1812 break;
1813
1814 case JFS_SUPERBLOCK_V2:
1815 journal->j_format_version = 2;
1816 if (ntohl(jsb->s_nr_users) > 1 &&
1817 uuid_is_null(ctx->fs->super->s_journal_uuid))
1818 clear_v2_journal_fields(journal);
1819 if (ntohl(jsb->s_nr_users) > 1) {
1820 fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
1821 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
1822 }
1823 break;
1824
1825
1826
1827
1828
1829 case JFS_DESCRIPTOR_BLOCK:
1830 case JFS_COMMIT_BLOCK:
1831 case JFS_REVOKE_BLOCK:
1832 return EXT2_ET_CORRUPT_SUPERBLOCK;
1833
1834
1835
1836
1837 default:
1838 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
1839 }
1840
1841 if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
1842 return EXT2_ET_UNSUPP_FEATURE;
1843
1844 if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
1845 return EXT2_ET_RO_UNSUPP_FEATURE;
1846
1847
1848
1849
1850 if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
1851 bb_error_msg(_("%s: no valid journal superblock found"),
1852 ctx->device_name);
1853 return EXT2_ET_CORRUPT_SUPERBLOCK;
1854 }
1855
1856 if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
1857 journal->j_maxlen = ntohl(jsb->s_maxlen);
1858 else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
1859 bb_error_msg(_("%s: journal too short"),
1860 ctx->device_name);
1861 return EXT2_ET_CORRUPT_SUPERBLOCK;
1862 }
1863
1864 journal->j_tail_sequence = ntohl(jsb->s_sequence);
1865 journal->j_transaction_sequence = journal->j_tail_sequence;
1866 journal->j_tail = ntohl(jsb->s_start);
1867 journal->j_first = ntohl(jsb->s_first);
1868 journal->j_last = ntohl(jsb->s_maxlen);
1869
1870 return 0;
1871}
1872
1873static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
1874 journal_t *journal)
1875{
1876 char *p;
1877 union {
1878 uuid_t uuid;
1879 __u32 val[4];
1880 } u;
1881 __u32 new_seq = 0;
1882 int i;
1883
1884
1885
1886
1887
1888 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
1889 jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
1890 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
1891 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
1892 }
1893
1894
1895
1896 p = ((char *) jsb) + sizeof(journal_header_t);
1897 memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
1898
1899 jsb->s_blocksize = htonl(ctx->fs->blocksize);
1900 jsb->s_maxlen = htonl(journal->j_maxlen);
1901 jsb->s_first = htonl(1);
1902
1903
1904
1905
1906
1907
1908 uuid_generate(u.uuid);
1909 for (i = 0; i < 4; i ++)
1910 new_seq ^= u.val[i];
1911 jsb->s_sequence = htonl(new_seq);
1912
1913 mark_buffer_dirty(journal->j_sb_buffer);
1914 ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
1915}
1916
1917static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
1918 journal_t *journal,
1919 struct problem_context *pctx)
1920{
1921 struct ext2_super_block *sb = ctx->fs->super;
1922 int recover = ctx->fs->super->s_feature_incompat &
1923 EXT3_FEATURE_INCOMPAT_RECOVER;
1924
1925 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
1926 if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
1927 e2fsck_journal_reset_super(ctx, journal->j_superblock,
1928 journal);
1929 journal->j_transaction_sequence = 1;
1930 e2fsck_clear_recover(ctx, recover);
1931 return 0;
1932 }
1933 return EXT2_ET_CORRUPT_SUPERBLOCK;
1934 } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
1935 return EXT2_ET_CORRUPT_SUPERBLOCK;
1936
1937 return 0;
1938}
1939
1940static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
1941 int reset, int drop)
1942{
1943 journal_superblock_t *jsb;
1944
1945 if (drop)
1946 mark_buffer_clean(journal->j_sb_buffer);
1947 else if (!(ctx->options & E2F_OPT_READONLY)) {
1948 jsb = journal->j_superblock;
1949 jsb->s_sequence = htonl(journal->j_transaction_sequence);
1950 if (reset)
1951 jsb->s_start = 0;
1952 mark_buffer_dirty(journal->j_sb_buffer);
1953 }
1954 brelse(journal->j_sb_buffer);
1955
1956 if (ctx->journal_io) {
1957 if (ctx->fs && ctx->fs->io != ctx->journal_io)
1958 io_channel_close(ctx->journal_io);
1959 ctx->journal_io = 0;
1960 }
1961
1962#ifndef USE_INODE_IO
1963 ext2fs_free_mem(&journal->j_inode);
1964#endif
1965 ext2fs_free_mem(&journal->j_fs_dev);
1966 ext2fs_free_mem(&journal);
1967}
1968
1969
1970
1971
1972
1973static int e2fsck_check_ext3_journal(e2fsck_t ctx)
1974{
1975 struct ext2_super_block *sb = ctx->fs->super;
1976 journal_t *journal;
1977 int recover = ctx->fs->super->s_feature_incompat &
1978 EXT3_FEATURE_INCOMPAT_RECOVER;
1979 struct problem_context pctx;
1980 problem_t problem;
1981 int reset = 0, force_fsck = 0;
1982 int retval;
1983
1984
1985 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
1986 !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
1987 uuid_is_null(sb->s_journal_uuid))
1988 return 0;
1989
1990 clear_problem_context(&pctx);
1991 pctx.num = sb->s_journal_inum;
1992
1993 retval = e2fsck_get_journal(ctx, &journal);
1994 if (retval) {
1995 if ((retval == EXT2_ET_BAD_INODE_NUM) ||
1996 (retval == EXT2_ET_BAD_BLOCK_NUM) ||
1997 (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
1998 (retval == EXT2_ET_NO_JOURNAL))
1999 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
2000 return retval;
2001 }
2002
2003 retval = e2fsck_journal_load(journal);
2004 if (retval) {
2005 if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
2006 ((retval == EXT2_ET_UNSUPP_FEATURE) &&
2007 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
2008 &pctx))) ||
2009 ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
2010 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
2011 &pctx))) ||
2012 ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
2013 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
2014 retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
2015 &pctx);
2016 e2fsck_journal_release(ctx, journal, 0, 1);
2017 return retval;
2018 }
2019
2020
2021
2022
2023
2024
2025no_has_journal:
2026 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
2027 recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
2028 pctx.str = "inode";
2029 if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
2030 if (recover &&
2031 !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
2032 goto no_has_journal;
2033
2034
2035
2036
2037 force_fsck = recover ||
2038 (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
2039
2040 sb->s_journal_inum = 0;
2041 sb->s_journal_dev = 0;
2042 memset(sb->s_journal_uuid, 0,
2043 sizeof(sb->s_journal_uuid));
2044 e2fsck_clear_recover(ctx, force_fsck);
2045 } else if (!(ctx->options & E2F_OPT_READONLY)) {
2046 sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
2047 ext2fs_mark_super_dirty(ctx->fs);
2048 }
2049 }
2050
2051 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
2052 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
2053 journal->j_superblock->s_start != 0) {
2054
2055 fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
2056 if (ctx->superblock)
2057 problem = PR_0_JOURNAL_RUN_DEFAULT;
2058 else
2059 problem = PR_0_JOURNAL_RUN;
2060 if (fix_problem(ctx, problem, &pctx)) {
2061 ctx->options |= E2F_OPT_FORCE;
2062 sb->s_feature_incompat |=
2063 EXT3_FEATURE_INCOMPAT_RECOVER;
2064 ext2fs_mark_super_dirty(ctx->fs);
2065 } else if (fix_problem(ctx,
2066 PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
2067 reset = 1;
2068 sb->s_state &= ~EXT2_VALID_FS;
2069 ext2fs_mark_super_dirty(ctx->fs);
2070 }
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082 }
2083
2084 e2fsck_journal_release(ctx, journal, reset, 0);
2085 return retval;
2086}
2087
2088static errcode_t recover_ext3_journal(e2fsck_t ctx)
2089{
2090 journal_t *journal;
2091 int retval;
2092
2093 journal_init_revoke_caches();
2094 retval = e2fsck_get_journal(ctx, &journal);
2095 if (retval)
2096 return retval;
2097
2098 retval = e2fsck_journal_load(journal);
2099 if (retval)
2100 goto errout;
2101
2102 retval = journal_init_revoke(journal, 1024);
2103 if (retval)
2104 goto errout;
2105
2106 retval = -journal_recover(journal);
2107 if (retval)
2108 goto errout;
2109
2110 if (journal->j_superblock->s_errno) {
2111 ctx->fs->super->s_state |= EXT2_ERROR_FS;
2112 ext2fs_mark_super_dirty(ctx->fs);
2113 journal->j_superblock->s_errno = 0;
2114 mark_buffer_dirty(journal->j_sb_buffer);
2115 }
2116
2117errout:
2118 journal_destroy_revoke(journal);
2119 journal_destroy_revoke_caches();
2120 e2fsck_journal_release(ctx, journal, 1, 0);
2121 return retval;
2122}
2123
2124static int e2fsck_run_ext3_journal(e2fsck_t ctx)
2125{
2126 io_manager io_ptr = ctx->fs->io->manager;
2127 int blocksize = ctx->fs->blocksize;
2128 errcode_t retval, recover_retval;
2129
2130 printf(_("%s: recovering journal\n"), ctx->device_name);
2131 if (ctx->options & E2F_OPT_READONLY) {
2132 printf(_("%s: won't do journal recovery while read-only\n"),
2133 ctx->device_name);
2134 return EXT2_ET_FILE_RO;
2135 }
2136
2137 if (ctx->fs->flags & EXT2_FLAG_DIRTY)
2138 ext2fs_flush(ctx->fs);
2139
2140 recover_retval = recover_ext3_journal(ctx);
2141
2142
2143
2144
2145
2146 ext2fs_close(ctx->fs);
2147 retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
2148 ctx->superblock, blocksize, io_ptr,
2149 &ctx->fs);
2150
2151 if (retval) {
2152 bb_error_msg(_("while trying to re-open %s"),
2153 ctx->device_name);
2154 bb_error_msg_and_die(0);
2155 }
2156 ctx->fs->priv_data = ctx;
2157
2158
2159 e2fsck_clear_recover(ctx, recover_retval);
2160 return recover_retval;
2161}
2162
2163
2164
2165
2166
2167static const char *const journal_names[] = {
2168 ".journal", "journal", ".journal.dat", "journal.dat", 0 };
2169
2170static void e2fsck_move_ext3_journal(e2fsck_t ctx)
2171{
2172 struct ext2_super_block *sb = ctx->fs->super;
2173 struct problem_context pctx;
2174 struct ext2_inode inode;
2175 ext2_filsys fs = ctx->fs;
2176 ext2_ino_t ino;
2177 errcode_t retval;
2178 const char *const * cpp;
2179 int group, mount_flags;
2180
2181 clear_problem_context(&pctx);
2182
2183
2184
2185
2186
2187 if ((ctx->options & E2F_OPT_READONLY) ||
2188 (sb->s_journal_inum == 0) ||
2189 !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
2190 return;
2191
2192
2193
2194
2195 if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
2196 return;
2197
2198
2199
2200
2201 if ((sb->s_jnl_backup_type == 0) ||
2202 ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
2203 memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
2204 if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
2205 memcpy(sb->s_jnl_blocks, inode.i_block,
2206 EXT2_N_BLOCKS*4);
2207 sb->s_jnl_blocks[16] = inode.i_size;
2208 sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
2209 ext2fs_mark_super_dirty(fs);
2210 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
2211 }
2212 }
2213
2214
2215
2216
2217 if (sb->s_journal_inum == EXT2_JOURNAL_INO)
2218 return;
2219
2220
2221
2222
2223 if (inode.i_links_count != 1)
2224 return;
2225
2226
2227
2228
2229
2230 retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
2231 if (retval || (mount_flags & EXT2_MF_MOUNTED))
2232 return;
2233
2234
2235
2236
2237
2238 for (cpp = journal_names; *cpp; cpp++) {
2239 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
2240 strlen(*cpp), 0, &ino);
2241 if ((retval == 0) && (ino == sb->s_journal_inum))
2242 break;
2243 }
2244 if (*cpp == 0)
2245 return;
2246
2247
2248 retval = ext2fs_read_bitmaps(fs);
2249 if (retval)
2250 return;
2251
2252 pctx.str = *cpp;
2253 if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
2254 return;
2255
2256
2257
2258
2259
2260
2261 if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
2262 goto err_out;
2263 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
2264 goto err_out;
2265 sb->s_journal_inum = EXT2_JOURNAL_INO;
2266 ext2fs_mark_super_dirty(fs);
2267 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
2268 inode.i_links_count = 0;
2269 inode.i_dtime = time(NULL);
2270 if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
2271 goto err_out;
2272
2273 group = ext2fs_group_of_ino(fs, ino);
2274 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
2275 ext2fs_mark_ib_dirty(fs);
2276 fs->group_desc[group].bg_free_inodes_count++;
2277 fs->super->s_free_inodes_count++;
2278 return;
2279
2280err_out:
2281 pctx.errcode = retval;
2282 fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
2283 fs->super->s_state &= ~EXT2_VALID_FS;
2284 ext2fs_mark_super_dirty(fs);
2285}
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371static const char *const abbrevs[] = {
2372 N_("aextended attribute"),
2373 N_("Aerror allocating"),
2374 N_("bblock"),
2375 N_("Bbitmap"),
2376 N_("ccompress"),
2377 N_("Cconflicts with some other fs @b"),
2378 N_("iinode"),
2379 N_("Iillegal"),
2380 N_("jjournal"),
2381 N_("Ddeleted"),
2382 N_("ddirectory"),
2383 N_("eentry"),
2384 N_("E@e '%Dn' in %p (%i)"),
2385 N_("ffilesystem"),
2386 N_("Ffor @i %i (%Q) is"),
2387 N_("ggroup"),
2388 N_("hHTREE @d @i"),
2389 N_("llost+found"),
2390 N_("Lis a link"),
2391 N_("mmultiply-claimed"),
2392 N_("ninvalid"),
2393 N_("oorphaned"),
2394 N_("pproblem in"),
2395 N_("rroot @i"),
2396 N_("sshould be"),
2397 N_("Ssuper@b"),
2398 N_("uunattached"),
2399 N_("vdevice"),
2400 N_("zzero-length"),
2401 "@@",
2402 0
2403 };
2404
2405
2406
2407
2408#define num_special_inodes 11
2409static const char *const special_inode_name[] =
2410{
2411 N_("<The NULL inode>"),
2412 N_("<The bad blocks inode>"),
2413 "/",
2414 N_("<The ACL index inode>"),
2415 N_("<The ACL data inode>"),
2416 N_("<The boot loader inode>"),
2417 N_("<The undelete directory inode>"),
2418 N_("<The group descriptor inode>"),
2419 N_("<The journal inode>"),
2420 N_("<Reserved inode 9>"),
2421 N_("<Reserved inode 10>"),
2422};
2423
2424
2425
2426
2427
2428static void safe_print(const char *cp, int len)
2429{
2430 unsigned char ch;
2431
2432 if (len < 0)
2433 len = strlen(cp);
2434
2435 while (len--) {
2436 ch = *cp++;
2437 if (ch > 128) {
2438 fputs("M-", stdout);
2439 ch -= 128;
2440 }
2441 if ((ch < 32) || (ch == 0x7f)) {
2442 bb_putchar('^');
2443 ch ^= 0x40;
2444 }
2445 bb_putchar(ch);
2446 }
2447}
2448
2449
2450
2451
2452
2453
2454static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
2455{
2456 errcode_t retval;
2457 char *path;
2458
2459 if (!dir && (ino < num_special_inodes)) {
2460 fputs(_(special_inode_name[ino]), stdout);
2461 return;
2462 }
2463
2464 retval = ext2fs_get_pathname(fs, dir, ino, &path);
2465 if (retval)
2466 fputs("???", stdout);
2467 else {
2468 safe_print(path, -1);
2469 ext2fs_free_mem(&path);
2470 }
2471}
2472
2473static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
2474 struct problem_context *pctx, int first);
2475
2476
2477
2478
2479
2480static void expand_at_expression(e2fsck_t ctx, char ch,
2481 struct problem_context *pctx,
2482 int *first)
2483{
2484 const char *const *cpp;
2485 const char *str;
2486
2487
2488 for (cpp = abbrevs; *cpp; cpp++) {
2489 if (ch == *cpp[0])
2490 break;
2491 }
2492 if (*cpp) {
2493 str = _(*cpp) + 1;
2494 if (*first && islower(*str)) {
2495 *first = 0;
2496 bb_putchar(toupper(*str++));
2497 }
2498 print_e2fsck_message(ctx, str, pctx, *first);
2499 } else
2500 printf("@%c", ch);
2501}
2502
2503
2504
2505
2506static void expand_inode_expression(char ch,
2507 struct problem_context *ctx)
2508{
2509 struct ext2_inode *inode;
2510 struct ext2_inode_large *large_inode;
2511 char * time_str;
2512 time_t t;
2513 int do_gmt = -1;
2514
2515 if (!ctx || !ctx->inode)
2516 goto no_inode;
2517
2518 inode = ctx->inode;
2519 large_inode = (struct ext2_inode_large *) inode;
2520
2521 switch (ch) {
2522 case 's':
2523 if (LINUX_S_ISDIR(inode->i_mode))
2524 printf("%u", inode->i_size);
2525 else {
2526 printf("%"PRIu64, (inode->i_size |
2527 ((uint64_t) inode->i_size_high << 32)));
2528 }
2529 break;
2530 case 'S':
2531 printf("%u", large_inode->i_extra_isize);
2532 break;
2533 case 'b':
2534 printf("%u", inode->i_blocks);
2535 break;
2536 case 'l':
2537 printf("%d", inode->i_links_count);
2538 break;
2539 case 'm':
2540 printf("0%o", inode->i_mode);
2541 break;
2542 case 'M':
2543
2544 if (do_gmt == -1) {
2545 time_str = getenv("TZ");
2546 if (!time_str)
2547 time_str = "";
2548 do_gmt = !strcmp(time_str, "GMT");
2549 }
2550 t = inode->i_mtime;
2551 time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
2552 printf("%.24s", time_str);
2553 break;
2554 case 'F':
2555 printf("%u", inode->i_faddr);
2556 break;
2557 case 'f':
2558 printf("%u", inode->i_file_acl);
2559 break;
2560 case 'd':
2561 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
2562 inode->i_dir_acl : 0));
2563 break;
2564 case 'u':
2565 printf("%d", (inode->i_uid |
2566 (inode->osd2.linux2.l_i_uid_high << 16)));
2567 break;
2568 case 'g':
2569 printf("%d", (inode->i_gid |
2570 (inode->osd2.linux2.l_i_gid_high << 16)));
2571 break;
2572 default:
2573 no_inode:
2574 printf("%%I%c", ch);
2575 break;
2576 }
2577}
2578
2579
2580
2581
2582static void expand_dirent_expression(char ch,
2583 struct problem_context *ctx)
2584{
2585 struct ext2_dir_entry *dirent;
2586 int len;
2587
2588 if (!ctx || !ctx->dirent)
2589 goto no_dirent;
2590
2591 dirent = ctx->dirent;
2592
2593 switch (ch) {
2594 case 'i':
2595 printf("%u", dirent->inode);
2596 break;
2597 case 'n':
2598 len = dirent->name_len & 0xFF;
2599 if (len > EXT2_NAME_LEN)
2600 len = EXT2_NAME_LEN;
2601 if (len > dirent->rec_len)
2602 len = dirent->rec_len;
2603 safe_print(dirent->name, len);
2604 break;
2605 case 'r':
2606 printf("%u", dirent->rec_len);
2607 break;
2608 case 'l':
2609 printf("%u", dirent->name_len & 0xFF);
2610 break;
2611 case 't':
2612 printf("%u", dirent->name_len >> 8);
2613 break;
2614 default:
2615 no_dirent:
2616 printf("%%D%c", ch);
2617 break;
2618 }
2619}
2620
2621static void expand_percent_expression(ext2_filsys fs, char ch,
2622 struct problem_context *ctx)
2623{
2624 if (!ctx)
2625 goto no_context;
2626
2627 switch (ch) {
2628 case '%':
2629 bb_putchar('%');
2630 break;
2631 case 'b':
2632 printf("%u", ctx->blk);
2633 break;
2634 case 'B':
2635 printf("%"PRIi64, ctx->blkcount);
2636 break;
2637 case 'c':
2638 printf("%u", ctx->blk2);
2639 break;
2640 case 'd':
2641 printf("%u", ctx->dir);
2642 break;
2643 case 'g':
2644 printf("%d", ctx->group);
2645 break;
2646 case 'i':
2647 printf("%u", ctx->ino);
2648 break;
2649 case 'j':
2650 printf("%u", ctx->ino2);
2651 break;
2652 case 'm':
2653 fputs(error_message(ctx->errcode), stdout);
2654 break;
2655 case 'N':
2656 printf("%"PRIi64, ctx->num);
2657 break;
2658 case 'p':
2659 print_pathname(fs, ctx->ino, 0);
2660 break;
2661 case 'P':
2662 print_pathname(fs, ctx->ino2,
2663 ctx->dirent ? ctx->dirent->inode : 0);
2664 break;
2665 case 'q':
2666 print_pathname(fs, ctx->dir, 0);
2667 break;
2668 case 'Q':
2669 print_pathname(fs, ctx->dir, ctx->ino);
2670 break;
2671 case 'S':
2672 printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
2673 break;
2674 case 's':
2675 fputs((ctx->str ? ctx->str : "NULL"), stdout);
2676 break;
2677 case 'X':
2678 printf("0x%"PRIi64, ctx->num);
2679 break;
2680 default:
2681 no_context:
2682 printf("%%%c", ch);
2683 break;
2684 }
2685}
2686
2687
2688static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
2689 struct problem_context *pctx, int first)
2690{
2691 ext2_filsys fs = ctx->fs;
2692 const char * cp;
2693 int i;
2694
2695 e2fsck_clear_progbar(ctx);
2696 for (cp = msg; *cp; cp++) {
2697 if (cp[0] == '@') {
2698 cp++;
2699 expand_at_expression(ctx, *cp, pctx, &first);
2700 } else if (cp[0] == '%' && cp[1] == 'I') {
2701 cp += 2;
2702 expand_inode_expression(*cp, pctx);
2703 } else if (cp[0] == '%' && cp[1] == 'D') {
2704 cp += 2;
2705 expand_dirent_expression(*cp, pctx);
2706 } else if ((cp[0] == '%')) {
2707 cp++;
2708 expand_percent_expression(fs, *cp, pctx);
2709 } else {
2710 for (i=0; cp[i]; i++)
2711 if ((cp[i] == '@') || cp[i] == '%')
2712 break;
2713 printf("%.*s", i, cp);
2714 cp += i-1;
2715 }
2716 first = 0;
2717 }
2718}
2719
2720
2721
2722
2723
2724
2725struct region_el {
2726 region_addr_t start;
2727 region_addr_t end;
2728 struct region_el *next;
2729};
2730
2731struct region_struct {
2732 region_addr_t min;
2733 region_addr_t max;
2734 struct region_el *allocated;
2735};
2736
2737static region_t region_create(region_addr_t min, region_addr_t max)
2738{
2739 region_t region;
2740
2741 region = xzalloc(sizeof(struct region_struct));
2742 region->min = min;
2743 region->max = max;
2744 return region;
2745}
2746
2747static void region_free(region_t region)
2748{
2749 struct region_el *r, *next;
2750
2751 for (r = region->allocated; r; r = next) {
2752 next = r->next;
2753 free(r);
2754 }
2755 memset(region, 0, sizeof(struct region_struct));
2756 free(region);
2757}
2758
2759static int region_allocate(region_t region, region_addr_t start, int n)
2760{
2761 struct region_el *r, *new_region, *prev, *next;
2762 region_addr_t end;
2763
2764 end = start+n;
2765 if ((start < region->min) || (end > region->max))
2766 return -1;
2767 if (n == 0)
2768 return 1;
2769
2770
2771
2772
2773
2774
2775
2776
2777 for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
2778 if (((start >= r->start) && (start < r->end)) ||
2779 ((end > r->start) && (end <= r->end)) ||
2780 ((start <= r->start) && (end >= r->end)))
2781 return 1;
2782 if (end == r->start) {
2783 r->start = start;
2784 return 0;
2785 }
2786 if (start == r->end) {
2787 if ((next = r->next)) {
2788 if (end > next->start)
2789 return 1;
2790 if (end == next->start) {
2791 r->end = next->end;
2792 r->next = next->next;
2793 free(next);
2794 return 0;
2795 }
2796 }
2797 r->end = end;
2798 return 0;
2799 }
2800 if (start < r->start)
2801 break;
2802 }
2803
2804
2805
2806 new_region = xmalloc(sizeof(struct region_el));
2807 new_region->start = start;
2808 new_region->end = start + n;
2809 new_region->next = r;
2810 if (prev)
2811 prev->next = new_region;
2812 else
2813 region->allocated = new_region;
2814 return 0;
2815}
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849static int process_block(ext2_filsys fs, blk_t *blocknr,
2850 e2_blkcnt_t blockcnt, blk_t ref_blk,
2851 int ref_offset, void *priv_data);
2852static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
2853 e2_blkcnt_t blockcnt, blk_t ref_blk,
2854 int ref_offset, void *priv_data);
2855static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
2856 char *block_buf);
2857static void mark_table_blocks(e2fsck_t ctx);
2858static void alloc_imagic_map(e2fsck_t ctx);
2859static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
2860static void handle_fs_bad_blocks(e2fsck_t ctx);
2861static void process_inodes(e2fsck_t ctx, char *block_buf);
2862static int process_inode_cmp(const void *a, const void *b);
2863static errcode_t scan_callback(ext2_filsys fs,
2864 dgrp_t group, void * priv_data);
2865static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
2866 char *block_buf, int adjust_sign);
2867
2868
2869static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
2870 struct ext2_inode * inode, int bufsize,
2871 const char *proc);
2872
2873struct process_block_struct_1 {
2874 ext2_ino_t ino;
2875 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
2876 fragmented:1, compressed:1, bbcheck:1;
2877 blk_t num_blocks;
2878 blk_t max_blocks;
2879 e2_blkcnt_t last_block;
2880 int num_illegal_blocks;
2881 blk_t previous_block;
2882 struct ext2_inode *inode;
2883 struct problem_context *pctx;
2884 ext2fs_block_bitmap fs_meta_blocks;
2885 e2fsck_t ctx;
2886};
2887
2888struct process_inode_block {
2889 ext2_ino_t ino;
2890 struct ext2_inode inode;
2891};
2892
2893struct scan_callback_struct {
2894 e2fsck_t ctx;
2895 char *block_buf;
2896};
2897
2898
2899
2900
2901static struct process_inode_block *inodes_to_process;
2902static int process_inode_count;
2903
2904static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
2905 EXT2_MIN_BLOCK_LOG_SIZE + 1];
2906
2907
2908
2909
2910
2911static void unwind_pass1(void)
2912{
2913 ext2fs_free_mem(&inodes_to_process);
2914}
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924static int
2925e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
2926{
2927 int i;
2928
2929
2930
2931
2932
2933 if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
2934 (inode->i_flags & EXT2_INDEX_FL))
2935 return 0;
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
2949 for (i=4; i < EXT2_N_BLOCKS; i++)
2950 if (inode->i_block[i])
2951 return 0;
2952 }
2953 return 1;
2954}
2955
2956
2957
2958
2959
2960static int
2961e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, char *buf)
2962{
2963 unsigned int len;
2964 int i;
2965 blk_t blocks;
2966
2967 if ((inode->i_size_high || inode->i_size == 0) ||
2968 (inode->i_flags & EXT2_INDEX_FL))
2969 return 0;
2970
2971 blocks = ext2fs_inode_data_blocks(fs, inode);
2972 if (blocks) {
2973 if ((inode->i_size >= fs->blocksize) ||
2974 (blocks != fs->blocksize >> 9) ||
2975 (inode->i_block[0] < fs->super->s_first_data_block) ||
2976 (inode->i_block[0] >= fs->super->s_blocks_count))
2977 return 0;
2978
2979 for (i = 1; i < EXT2_N_BLOCKS; i++)
2980 if (inode->i_block[i])
2981 return 0;
2982
2983 if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
2984 return 0;
2985
2986 len = strnlen(buf, fs->blocksize);
2987 if (len == fs->blocksize)
2988 return 0;
2989 } else {
2990 if (inode->i_size >= sizeof(inode->i_block))
2991 return 0;
2992
2993 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
2994 if (len == sizeof(inode->i_block))
2995 return 0;
2996 }
2997 if (len != inode->i_size)
2998 return 0;
2999 return 1;
3000}
3001
3002
3003
3004
3005
3006#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
3007static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
3008{
3009 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
3010 return;
3011
3012 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
3013 return;
3014
3015 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
3016 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
3017}
3018
3019
3020
3021
3022
3023static void check_size(e2fsck_t ctx, struct problem_context *pctx)
3024{
3025 struct ext2_inode *inode = pctx->inode;
3026
3027 if ((inode->i_size == 0) && (inode->i_size_high == 0))
3028 return;
3029
3030 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
3031 return;
3032
3033 inode->i_size = 0;
3034 inode->i_size_high = 0;
3035 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
3036}
3037
3038static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
3039{
3040 struct ext2_super_block *sb = ctx->fs->super;
3041 struct ext2_inode_large *inode;
3042 struct ext2_ext_attr_entry *entry;
3043 char *start, *end;
3044 int storage_size, remain, offs;
3045 int problem = 0;
3046
3047 inode = (struct ext2_inode_large *) pctx->inode;
3048 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
3049 inode->i_extra_isize;
3050 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
3051 inode->i_extra_isize + sizeof(__u32);
3052 end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
3053 entry = (struct ext2_ext_attr_entry *) start;
3054
3055
3056
3057
3058 remain = storage_size - sizeof(__u32);
3059 offs = end - start;
3060
3061 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
3062
3063
3064 remain -= sizeof(struct ext2_ext_attr_entry);
3065
3066
3067 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
3068 pctx->num = entry->e_name_len;
3069 problem = PR_1_ATTR_NAME_LEN;
3070 goto fix;
3071 }
3072
3073
3074 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
3075
3076
3077 if (entry->e_value_size == 0 || entry->e_value_size > remain) {
3078 pctx->num = entry->e_value_size;
3079 problem = PR_1_ATTR_VALUE_SIZE;
3080 goto fix;
3081 }
3082
3083
3084 if (entry->e_value_offs +
3085 EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
3086 printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
3087 pctx->num = entry->e_value_offs;
3088 problem = PR_1_ATTR_VALUE_OFFSET;
3089 goto fix;
3090 }
3091
3092
3093 if (entry->e_value_block != 0) {
3094 pctx->num = entry->e_value_block;
3095 problem = PR_1_ATTR_VALUE_BLOCK;
3096 goto fix;
3097 }
3098
3099
3100 if (entry->e_hash != 0) {
3101 pctx->num = entry->e_hash;
3102 problem = PR_1_ATTR_HASH;
3103 goto fix;
3104 }
3105
3106 remain -= entry->e_value_size;
3107 offs -= EXT2_XATTR_SIZE(entry->e_value_size);
3108
3109 entry = EXT2_EXT_ATTR_NEXT(entry);
3110 }
3111fix:
3112
3113
3114
3115
3116 if (problem == 0 || !fix_problem(ctx, problem, pctx))
3117 return;
3118
3119
3120 *((__u32 *)start) = 0UL;
3121 e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
3122 EXT2_INODE_SIZE(sb), "pass1");
3123}
3124
3125static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
3126{
3127 struct ext2_super_block *sb = ctx->fs->super;
3128 struct ext2_inode_large *inode;
3129 __u32 *eamagic;
3130 int min, max;
3131
3132 inode = (struct ext2_inode_large *) pctx->inode;
3133 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
3134
3135 return;
3136 }
3137
3138
3139 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
3140 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
3141
3142
3143
3144
3145 if (inode->i_extra_isize &&
3146 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
3147 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
3148 return;
3149 inode->i_extra_isize = min;
3150 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
3151 EXT2_INODE_SIZE(sb), "pass1");
3152 return;
3153 }
3154
3155 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
3156 inode->i_extra_isize);
3157 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
3158
3159 check_ea_in_inode(ctx, pctx);
3160 }
3161}
3162
3163static void e2fsck_pass1(e2fsck_t ctx)
3164{
3165 int i;
3166 __u64 max_sizes;
3167 ext2_filsys fs = ctx->fs;
3168 ext2_ino_t ino;
3169 struct ext2_inode *inode;
3170 ext2_inode_scan scan;
3171 char *block_buf;
3172 unsigned char frag, fsize;
3173 struct problem_context pctx;
3174 struct scan_callback_struct scan_struct;
3175 struct ext2_super_block *sb = ctx->fs->super;
3176 int imagic_fs;
3177 int busted_fs_time = 0;
3178 int inode_size;
3179
3180 clear_problem_context(&pctx);
3181
3182 if (!(ctx->options & E2F_OPT_PREEN))
3183 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
3184
3185 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
3186 !(ctx->options & E2F_OPT_NO)) {
3187 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
3188 ctx->dirs_to_hash = 0;
3189 }
3190
3191
3192
3193#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
3194
3195 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
3196 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
3197 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
3198 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
3199 max_sizes = (max_sizes * (1UL << i)) - 1;
3200 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
3201 }
3202#undef EXT2_BPP
3203
3204 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
3205
3206
3207
3208
3209 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
3210 &ctx->inode_used_map);
3211 if (pctx.errcode) {
3212 pctx.num = 1;
3213 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3214 ctx->flags |= E2F_FLAG_ABORT;
3215 return;
3216 }
3217 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
3218 _("directory inode map"), &ctx->inode_dir_map);
3219 if (pctx.errcode) {
3220 pctx.num = 2;
3221 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3222 ctx->flags |= E2F_FLAG_ABORT;
3223 return;
3224 }
3225 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
3226 _("regular file inode map"), &ctx->inode_reg_map);
3227 if (pctx.errcode) {
3228 pctx.num = 6;
3229 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3230 ctx->flags |= E2F_FLAG_ABORT;
3231 return;
3232 }
3233 pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
3234 &ctx->block_found_map);
3235 if (pctx.errcode) {
3236 pctx.num = 1;
3237 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
3238 ctx->flags |= E2F_FLAG_ABORT;
3239 return;
3240 }
3241 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
3242 &ctx->inode_link_info);
3243 if (pctx.errcode) {
3244 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
3245 ctx->flags |= E2F_FLAG_ABORT;
3246 return;
3247 }
3248 inode_size = EXT2_INODE_SIZE(fs->super);
3249 inode = (struct ext2_inode *)
3250 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
3251
3252 inodes_to_process = (struct process_inode_block *)
3253 e2fsck_allocate_memory(ctx,
3254 (ctx->process_inode_size *
3255 sizeof(struct process_inode_block)),
3256 "array of inodes to process");
3257 process_inode_count = 0;
3258
3259 pctx.errcode = ext2fs_init_dblist(fs, 0);
3260 if (pctx.errcode) {
3261 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
3262 ctx->flags |= E2F_FLAG_ABORT;
3263 return;
3264 }
3265
3266
3267
3268
3269
3270
3271
3272
3273 if (!(ctx->options & E2F_OPT_READONLY)) {
3274 if (fs->super->s_last_orphan) {
3275 fs->super->s_last_orphan = 0;
3276 ext2fs_mark_super_dirty(fs);
3277 }
3278 }
3279
3280 mark_table_blocks(ctx);
3281 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
3282 "block interate buffer");
3283 e2fsck_use_inode_shortcuts(ctx, 1);
3284 ehandler_operation(_("doing inode scan"));
3285 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
3286 &scan);
3287 if (pctx.errcode) {
3288 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
3289 ctx->flags |= E2F_FLAG_ABORT;
3290 return;
3291 }
3292 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
3293 ctx->stashed_inode = inode;
3294 scan_struct.ctx = ctx;
3295 scan_struct.block_buf = block_buf;
3296 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
3297 if (ctx->progress)
3298 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
3299 return;
3300 if ((fs->super->s_wtime < fs->super->s_inodes_count) ||
3301 (fs->super->s_mtime < fs->super->s_inodes_count))
3302 busted_fs_time = 1;
3303
3304 while (1) {
3305 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
3306 inode, inode_size);
3307 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3308 return;
3309 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
3310 continue;
3311 }
3312 if (pctx.errcode) {
3313 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
3314 ctx->flags |= E2F_FLAG_ABORT;
3315 return;
3316 }
3317 if (!ino)
3318 break;
3319 pctx.ino = ino;
3320 pctx.inode = inode;
3321 ctx->stashed_ino = ino;
3322 if (inode->i_links_count) {
3323 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
3324 ino, inode->i_links_count);
3325 if (pctx.errcode) {
3326 pctx.num = inode->i_links_count;
3327 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
3328 ctx->flags |= E2F_FLAG_ABORT;
3329 return;
3330 }
3331 }
3332 if (ino == EXT2_BAD_INO) {
3333 struct process_block_struct_1 pb;
3334
3335 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
3336 &pb.fs_meta_blocks);
3337 if (pctx.errcode) {
3338 pctx.num = 4;
3339 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
3340 ctx->flags |= E2F_FLAG_ABORT;
3341 return;
3342 }
3343 pb.ino = EXT2_BAD_INO;
3344 pb.num_blocks = pb.last_block = 0;
3345 pb.num_illegal_blocks = 0;
3346 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
3347 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
3348 pb.inode = inode;
3349 pb.pctx = &pctx;
3350 pb.ctx = ctx;
3351 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
3352 block_buf, process_bad_block, &pb);
3353 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
3354 if (pctx.errcode) {
3355 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
3356 ctx->flags |= E2F_FLAG_ABORT;
3357 return;
3358 }
3359 if (pb.bbcheck)
3360 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
3361 ctx->flags |= E2F_FLAG_ABORT;
3362 return;
3363 }
3364 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3365 clear_problem_context(&pctx);
3366 continue;
3367 } else if (ino == EXT2_ROOT_INO) {
3368
3369
3370
3371
3372
3373 if (!LINUX_S_ISDIR(inode->i_mode)) {
3374 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
3375 inode->i_dtime = time(NULL);
3376 inode->i_links_count = 0;
3377 ext2fs_icount_store(ctx->inode_link_info,
3378 ino, 0);
3379 e2fsck_write_inode(ctx, ino, inode,
3380 "pass1");
3381 }
3382
3383 }
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393 if (inode->i_dtime && inode->i_links_count) {
3394 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
3395 inode->i_dtime = 0;
3396 e2fsck_write_inode(ctx, ino, inode,
3397 "pass1");
3398 }
3399 }
3400 } else if (ino == EXT2_JOURNAL_INO) {
3401 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3402 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
3403 if (!LINUX_S_ISREG(inode->i_mode) &&
3404 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
3405 &pctx)) {
3406 inode->i_mode = LINUX_S_IFREG;
3407 e2fsck_write_inode(ctx, ino, inode,
3408 "pass1");
3409 }
3410 check_blocks(ctx, &pctx, block_buf);
3411 continue;
3412 }
3413 if ((inode->i_links_count || inode->i_blocks ||
3414 inode->i_blocks || inode->i_block[0]) &&
3415 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
3416 &pctx)) {
3417 memset(inode, 0, inode_size);
3418 ext2fs_icount_store(ctx->inode_link_info,
3419 ino, 0);
3420 e2fsck_write_inode_full(ctx, ino, inode,
3421 inode_size, "pass1");
3422 }
3423 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
3424 int problem = 0;
3425
3426 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3427 if (ino == EXT2_BOOT_LOADER_INO) {
3428 if (LINUX_S_ISDIR(inode->i_mode))
3429 problem = PR_1_RESERVED_BAD_MODE;
3430 } else if (ino == EXT2_RESIZE_INO) {
3431 if (inode->i_mode &&
3432 !LINUX_S_ISREG(inode->i_mode))
3433 problem = PR_1_RESERVED_BAD_MODE;
3434 } else {
3435 if (inode->i_mode != 0)
3436 problem = PR_1_RESERVED_BAD_MODE;
3437 }
3438 if (problem) {
3439 if (fix_problem(ctx, problem, &pctx)) {
3440 inode->i_mode = 0;
3441 e2fsck_write_inode(ctx, ino, inode,
3442 "pass1");
3443 }
3444 }
3445 check_blocks(ctx, &pctx, block_buf);
3446 continue;
3447 }
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465 if (inode->i_dtime && !busted_fs_time &&
3466 inode->i_dtime < ctx->fs->super->s_inodes_count) {
3467 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
3468 inode->i_dtime = inode->i_links_count ?
3469 0 : time(NULL);
3470 e2fsck_write_inode(ctx, ino, inode,
3471 "pass1");
3472 }
3473 }
3474
3475
3476
3477
3478
3479 if (!inode->i_links_count) {
3480 if (!inode->i_dtime && inode->i_mode) {
3481 if (fix_problem(ctx,
3482 PR_1_ZERO_DTIME, &pctx)) {
3483 inode->i_dtime = time(NULL);
3484 e2fsck_write_inode(ctx, ino, inode,
3485 "pass1");
3486 }
3487 }
3488 continue;
3489 }
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500 if (inode->i_dtime) {
3501 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
3502 inode->i_dtime = 0;
3503 e2fsck_write_inode(ctx, ino, inode, "pass1");
3504 }
3505 }
3506
3507 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3508 switch (fs->super->s_creator_os) {
3509 case EXT2_OS_LINUX:
3510 frag = inode->osd2.linux2.l_i_frag;
3511 fsize = inode->osd2.linux2.l_i_fsize;
3512 break;
3513 case EXT2_OS_HURD:
3514 frag = inode->osd2.hurd2.h_i_frag;
3515 fsize = inode->osd2.hurd2.h_i_fsize;
3516 break;
3517 case EXT2_OS_MASIX:
3518 frag = inode->osd2.masix2.m_i_frag;
3519 fsize = inode->osd2.masix2.m_i_fsize;
3520 break;
3521 default:
3522 frag = fsize = 0;
3523 }
3524
3525 if (inode->i_faddr || frag || fsize ||
3526 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
3527 mark_inode_bad(ctx, ino);
3528 if (inode->i_flags & EXT2_IMAGIC_FL) {
3529 if (imagic_fs) {
3530 if (!ctx->inode_imagic_map)
3531 alloc_imagic_map(ctx);
3532 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
3533 ino);
3534 } else {
3535 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
3536 inode->i_flags &= ~EXT2_IMAGIC_FL;
3537 e2fsck_write_inode(ctx, ino,
3538 inode, "pass1");
3539 }
3540 }
3541 }
3542
3543 check_inode_extra_space(ctx, &pctx);
3544
3545 if (LINUX_S_ISDIR(inode->i_mode)) {
3546 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
3547 e2fsck_add_dir_info(ctx, ino, 0);
3548 ctx->fs_directory_count++;
3549 } else if (LINUX_S_ISREG (inode->i_mode)) {
3550 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
3551 ctx->fs_regular_count++;
3552 } else if (LINUX_S_ISCHR (inode->i_mode) &&
3553 e2fsck_pass1_check_device_inode(fs, inode)) {
3554 check_immutable(ctx, &pctx);
3555 check_size(ctx, &pctx);
3556 ctx->fs_chardev_count++;
3557 } else if (LINUX_S_ISBLK (inode->i_mode) &&
3558 e2fsck_pass1_check_device_inode(fs, inode)) {
3559 check_immutable(ctx, &pctx);
3560 check_size(ctx, &pctx);
3561 ctx->fs_blockdev_count++;
3562 } else if (LINUX_S_ISLNK (inode->i_mode) &&
3563 e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
3564 check_immutable(ctx, &pctx);
3565 ctx->fs_symlinks_count++;
3566 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
3567 ctx->fs_fast_symlinks_count++;
3568 check_blocks(ctx, &pctx, block_buf);
3569 continue;
3570 }
3571 }
3572 else if (LINUX_S_ISFIFO (inode->i_mode) &&
3573 e2fsck_pass1_check_device_inode(fs, inode)) {
3574 check_immutable(ctx, &pctx);
3575 check_size(ctx, &pctx);
3576 ctx->fs_fifo_count++;
3577 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
3578 e2fsck_pass1_check_device_inode(fs, inode)) {
3579 check_immutable(ctx, &pctx);
3580 check_size(ctx, &pctx);
3581 ctx->fs_sockets_count++;
3582 } else
3583 mark_inode_bad(ctx, ino);
3584 if (inode->i_block[EXT2_IND_BLOCK])
3585 ctx->fs_ind_count++;
3586 if (inode->i_block[EXT2_DIND_BLOCK])
3587 ctx->fs_dind_count++;
3588 if (inode->i_block[EXT2_TIND_BLOCK])
3589 ctx->fs_tind_count++;
3590 if (inode->i_block[EXT2_IND_BLOCK] ||
3591 inode->i_block[EXT2_DIND_BLOCK] ||
3592 inode->i_block[EXT2_TIND_BLOCK] ||
3593 inode->i_file_acl) {
3594 inodes_to_process[process_inode_count].ino = ino;
3595 inodes_to_process[process_inode_count].inode = *inode;
3596 process_inode_count++;
3597 } else
3598 check_blocks(ctx, &pctx, block_buf);
3599
3600 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3601 return;
3602
3603 if (process_inode_count >= ctx->process_inode_size) {
3604 process_inodes(ctx, block_buf);
3605
3606 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3607 return;
3608 }
3609 }
3610 process_inodes(ctx, block_buf);
3611 ext2fs_close_inode_scan(scan);
3612 ehandler_operation(0);
3613
3614
3615
3616
3617
3618
3619 if (ctx->refcount) {
3620 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
3621 ea_refcount_free(ctx->refcount);
3622 ctx->refcount = 0;
3623 }
3624 if (ctx->refcount_extra) {
3625 adjust_extattr_refcount(ctx, ctx->refcount_extra,
3626 block_buf, +1);
3627 ea_refcount_free(ctx->refcount_extra);
3628 ctx->refcount_extra = 0;
3629 }
3630
3631 if (ctx->invalid_bitmaps)
3632 handle_fs_bad_blocks(ctx);
3633
3634
3635 ext2fs_free_block_bitmap(ctx->block_ea_map);
3636 ctx->block_ea_map = 0;
3637
3638 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
3639 ext2fs_block_bitmap save_bmap;
3640
3641 save_bmap = fs->block_map;
3642 fs->block_map = ctx->block_found_map;
3643 clear_problem_context(&pctx);
3644 pctx.errcode = ext2fs_create_resize_inode(fs);
3645 if (pctx.errcode) {
3646 fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
3647
3648 ctx->flags |= E2F_FLAG_ABORT;
3649 return;
3650 }
3651 e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
3652 "recreate inode");
3653 inode->i_mtime = time(NULL);
3654 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
3655 "recreate inode");
3656 fs->block_map = save_bmap;
3657 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
3658 }
3659
3660 if (ctx->flags & E2F_FLAG_RESTART) {
3661
3662
3663
3664
3665
3666
3667 ctx->use_superblock = 0;
3668 unwind_pass1();
3669 goto endit;
3670 }
3671
3672 if (ctx->block_dup_map) {
3673 if (ctx->options & E2F_OPT_PREEN) {
3674 clear_problem_context(&pctx);
3675 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
3676 }
3677 e2fsck_pass1_dupblocks(ctx, block_buf);
3678 }
3679 ext2fs_free_mem(&inodes_to_process);
3680endit:
3681 e2fsck_use_inode_shortcuts(ctx, 0);
3682
3683 ext2fs_free_mem(&block_buf);
3684 ext2fs_free_mem(&inode);
3685
3686}
3687
3688
3689
3690
3691
3692static errcode_t scan_callback(ext2_filsys fs,
3693 dgrp_t group, void * priv_data)
3694{
3695 struct scan_callback_struct *scan_struct;
3696 e2fsck_t ctx;
3697
3698 scan_struct = (struct scan_callback_struct *) priv_data;
3699 ctx = scan_struct->ctx;
3700
3701 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
3702
3703 if (ctx->progress)
3704 if ((ctx->progress)(ctx, 1, group+1,
3705 ctx->fs->group_desc_count))
3706 return EXT2_ET_CANCEL_REQUESTED;
3707
3708 return 0;
3709}
3710
3711
3712
3713
3714static void process_inodes(e2fsck_t ctx, char *block_buf)
3715{
3716 int i;
3717 struct ext2_inode *old_stashed_inode;
3718 ext2_ino_t old_stashed_ino;
3719 const char *old_operation;
3720 char buf[80];
3721 struct problem_context pctx;
3722
3723
3724 if (process_inode_count == 0)
3725 return;
3726 old_operation = ehandler_operation(0);
3727 old_stashed_inode = ctx->stashed_inode;
3728 old_stashed_ino = ctx->stashed_ino;
3729 qsort(inodes_to_process, process_inode_count,
3730 sizeof(struct process_inode_block), process_inode_cmp);
3731 clear_problem_context(&pctx);
3732 for (i=0; i < process_inode_count; i++) {
3733 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
3734 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
3735 sprintf(buf, _("reading indirect blocks of inode %u"),
3736 pctx.ino);
3737 ehandler_operation(buf);
3738 check_blocks(ctx, &pctx, block_buf);
3739 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3740 break;
3741 }
3742 ctx->stashed_inode = old_stashed_inode;
3743 ctx->stashed_ino = old_stashed_ino;
3744 process_inode_count = 0;
3745
3746
3747 ehandler_operation(old_operation);
3748}
3749
3750static int process_inode_cmp(const void *a, const void *b)
3751{
3752 const struct process_inode_block *ib_a =
3753 (const struct process_inode_block *) a;
3754 const struct process_inode_block *ib_b =
3755 (const struct process_inode_block *) b;
3756 int ret;
3757
3758 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
3759 ib_b->inode.i_block[EXT2_IND_BLOCK]);
3760 if (ret == 0)
3761 ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
3762 return ret;
3763}
3764
3765
3766
3767
3768static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
3769{
3770 struct problem_context pctx;
3771
3772 if (!ctx->inode_bad_map) {
3773 clear_problem_context(&pctx);
3774
3775 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
3776 _("bad inode map"), &ctx->inode_bad_map);
3777 if (pctx.errcode) {
3778 pctx.num = 3;
3779 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3780
3781 ctx->flags |= E2F_FLAG_ABORT;
3782 return;
3783 }
3784 }
3785 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
3786}
3787
3788
3789
3790
3791
3792static void alloc_imagic_map(e2fsck_t ctx)
3793{
3794 struct problem_context pctx;
3795
3796 clear_problem_context(&pctx);
3797 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
3798 _("imagic inode map"),
3799 &ctx->inode_imagic_map);
3800 if (pctx.errcode) {
3801 pctx.num = 5;
3802 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3803
3804 ctx->flags |= E2F_FLAG_ABORT;
3805 return;
3806 }
3807}
3808
3809
3810
3811
3812
3813
3814
3815
3816static void mark_block_used(e2fsck_t ctx, blk_t block)
3817{
3818 struct problem_context pctx;
3819
3820 clear_problem_context(&pctx);
3821
3822 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
3823 if (!ctx->block_dup_map) {
3824 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
3825 _("multiply claimed block map"),
3826 &ctx->block_dup_map);
3827 if (pctx.errcode) {
3828 pctx.num = 3;
3829 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
3830 &pctx);
3831
3832 ctx->flags |= E2F_FLAG_ABORT;
3833 return;
3834 }
3835 }
3836 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
3837 } else {
3838 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
3839 }
3840}
3841
3842
3843
3844
3845
3846
3847
3848
3849static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
3850 char *block_buf, int adjust_sign)
3851{
3852 struct ext2_ext_attr_header *header;
3853 struct problem_context pctx;
3854 ext2_filsys fs = ctx->fs;
3855 blk_t blk;
3856 __u32 should_be;
3857 int count;
3858
3859 clear_problem_context(&pctx);
3860
3861 ea_refcount_intr_begin(refcount);
3862 while (1) {
3863 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
3864 break;
3865 pctx.blk = blk;
3866 pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
3867 if (pctx.errcode) {
3868 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
3869 return;
3870 }
3871 header = (struct ext2_ext_attr_header *) block_buf;
3872 pctx.blkcount = header->h_refcount;
3873 should_be = header->h_refcount + adjust_sign * count;
3874 pctx.num = should_be;
3875 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
3876 header->h_refcount = should_be;
3877 pctx.errcode = ext2fs_write_ext_attr(fs, blk,
3878 block_buf);
3879 if (pctx.errcode) {
3880 fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
3881 continue;
3882 }
3883 }
3884 }
3885}
3886
3887
3888
3889
3890static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
3891 char *block_buf)
3892{
3893 ext2_filsys fs = ctx->fs;
3894 ext2_ino_t ino = pctx->ino;
3895 struct ext2_inode *inode = pctx->inode;
3896 blk_t blk;
3897 char * end;
3898 struct ext2_ext_attr_header *header;
3899 struct ext2_ext_attr_entry *entry;
3900 int count;
3901 region_t region;
3902
3903 blk = inode->i_file_acl;
3904 if (blk == 0)
3905 return 0;
3906
3907
3908
3909
3910
3911
3912
3913
3914 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
3915 (blk < fs->super->s_first_data_block) ||
3916 (blk >= fs->super->s_blocks_count)) {
3917 mark_inode_bad(ctx, ino);
3918 return 0;
3919 }
3920
3921
3922 if (!ctx->block_ea_map) {
3923 pctx->errcode = ext2fs_allocate_block_bitmap(fs,
3924 _("ext attr block map"),
3925 &ctx->block_ea_map);
3926 if (pctx->errcode) {
3927 pctx->num = 2;
3928 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
3929 ctx->flags |= E2F_FLAG_ABORT;
3930 return 0;
3931 }
3932 }
3933
3934
3935 if (!ctx->refcount) {
3936 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
3937 if (pctx->errcode) {
3938 pctx->num = 1;
3939 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
3940 ctx->flags |= E2F_FLAG_ABORT;
3941 return 0;
3942 }
3943 }
3944
3945
3946 if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
3947 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
3948 return 1;
3949
3950 if (!ctx->refcount_extra) {
3951 pctx->errcode = ea_refcount_create(0,
3952 &ctx->refcount_extra);
3953 if (pctx->errcode) {
3954 pctx->num = 2;
3955 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
3956 ctx->flags |= E2F_FLAG_ABORT;
3957 return 0;
3958 }
3959 }
3960 ea_refcount_increment(ctx->refcount_extra, blk, 0);
3961 return 1;
3962 }
3963
3964
3965
3966
3967
3968 pctx->blk = blk;
3969 pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
3970 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
3971 goto clear_extattr;
3972 header = (struct ext2_ext_attr_header *) block_buf;
3973 pctx->blk = inode->i_file_acl;
3974 if (((ctx->ext_attr_ver == 1) &&
3975 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
3976 ((ctx->ext_attr_ver == 2) &&
3977 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
3978 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
3979 goto clear_extattr;
3980 }
3981
3982 if (header->h_blocks != 1) {
3983 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
3984 goto clear_extattr;
3985 }
3986
3987 region = region_create(0, fs->blocksize);
3988 if (!region) {
3989 fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
3990 ctx->flags |= E2F_FLAG_ABORT;
3991 return 0;
3992 }
3993 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
3994 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
3995 goto clear_extattr;
3996 }
3997
3998 entry = (struct ext2_ext_attr_entry *)(header+1);
3999 end = block_buf + fs->blocksize;
4000 while ((char *)entry < end && *(__u32 *)entry) {
4001 if (region_allocate(region, (char *)entry - (char *)header,
4002 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
4003 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4004 goto clear_extattr;
4005 }
4006 if ((ctx->ext_attr_ver == 1 &&
4007 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
4008 (ctx->ext_attr_ver == 2 &&
4009 entry->e_name_index == 0)) {
4010 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
4011 goto clear_extattr;
4012 }
4013 if (entry->e_value_block != 0) {
4014 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
4015 goto clear_extattr;
4016 }
4017 if (entry->e_value_size &&
4018 region_allocate(region, entry->e_value_offs,
4019 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
4020 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4021 goto clear_extattr;
4022 }
4023 entry = EXT2_EXT_ATTR_NEXT(entry);
4024 }
4025 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
4026 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4027 goto clear_extattr;
4028 }
4029 region_free(region);
4030
4031 count = header->h_refcount - 1;
4032 if (count)
4033 ea_refcount_store(ctx->refcount, blk, count);
4034 mark_block_used(ctx, blk);
4035 ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
4036
4037 return 1;
4038
4039clear_extattr:
4040 inode->i_file_acl = 0;
4041 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
4042 return 0;
4043}
4044
4045
4046static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
4047 ext2_ino_t ino FSCK_ATTR((unused)),
4048 struct ext2_inode *inode,
4049 char *block_buf)
4050{
4051 struct ext2_dx_root_info *root;
4052 ext2_filsys fs = ctx->fs;
4053 errcode_t retval;
4054 blk_t blk;
4055
4056 if ((!LINUX_S_ISDIR(inode->i_mode) &&
4057 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
4058 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
4059 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
4060 return 1;
4061
4062 blk = inode->i_block[0];
4063 if (((blk == 0) ||
4064 (blk < fs->super->s_first_data_block) ||
4065 (blk >= fs->super->s_blocks_count)) &&
4066 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
4067 return 1;
4068
4069 retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
4070 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
4071 return 1;
4072
4073
4074 root = (struct ext2_dx_root_info *) (block_buf + 24);
4075
4076 if ((root->reserved_zero || root->info_length < 8) &&
4077 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
4078 return 1;
4079
4080 pctx->num = root->hash_version;
4081 if ((root->hash_version != EXT2_HASH_LEGACY) &&
4082 (root->hash_version != EXT2_HASH_HALF_MD4) &&
4083 (root->hash_version != EXT2_HASH_TEA) &&
4084 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
4085 return 1;
4086
4087 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
4088 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
4089 return 1;
4090
4091 pctx->num = root->indirect_levels;
4092 if ((root->indirect_levels > 1) &&
4093 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
4094 return 1;
4095
4096 return 0;
4097}
4098
4099
4100
4101
4102
4103static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
4104 char *block_buf)
4105{
4106 ext2_filsys fs = ctx->fs;
4107 struct process_block_struct_1 pb;
4108 ext2_ino_t ino = pctx->ino;
4109 struct ext2_inode *inode = pctx->inode;
4110 int bad_size = 0;
4111 int dirty_inode = 0;
4112 __u64 size;
4113
4114 pb.ino = ino;
4115 pb.num_blocks = 0;
4116 pb.last_block = -1;
4117 pb.num_illegal_blocks = 0;
4118 pb.suppress = 0; pb.clear = 0;
4119 pb.fragmented = 0;
4120 pb.compressed = 0;
4121 pb.previous_block = 0;
4122 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
4123 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
4124 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
4125 pb.inode = inode;
4126 pb.pctx = pctx;
4127 pb.ctx = ctx;
4128 pctx->ino = ino;
4129 pctx->errcode = 0;
4130
4131 if (inode->i_flags & EXT2_COMPRBLK_FL) {
4132 if (fs->super->s_feature_incompat &
4133 EXT2_FEATURE_INCOMPAT_COMPRESSION)
4134 pb.compressed = 1;
4135 else {
4136 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
4137 inode->i_flags &= ~EXT2_COMPRBLK_FL;
4138 dirty_inode++;
4139 }
4140 }
4141 }
4142
4143 if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
4144 pb.num_blocks++;
4145
4146 if (ext2fs_inode_has_valid_blocks(inode))
4147 pctx->errcode = ext2fs_block_iterate2(fs, ino,
4148 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
4149 block_buf, process_block, &pb);
4150 end_problem_latch(ctx, PR_LATCH_BLOCK);
4151 end_problem_latch(ctx, PR_LATCH_TOOBIG);
4152 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4153 goto out;
4154 if (pctx->errcode)
4155 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
4156
4157 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
4158 ctx->fs_fragmented++;
4159
4160 if (pb.clear) {
4161 inode->i_links_count = 0;
4162 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
4163 inode->i_dtime = time(NULL);
4164 dirty_inode++;
4165 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
4166 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
4167 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
4168
4169
4170
4171
4172
4173 ctx->flags |= E2F_FLAG_RESTART;
4174 goto out;
4175 }
4176
4177 if (inode->i_flags & EXT2_INDEX_FL) {
4178 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
4179 inode->i_flags &= ~EXT2_INDEX_FL;
4180 dirty_inode++;
4181 } else {
4182#ifdef ENABLE_HTREE
4183 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
4184#endif
4185 }
4186 }
4187 if (ctx->dirs_to_hash && pb.is_dir &&
4188 !(inode->i_flags & EXT2_INDEX_FL) &&
4189 ((inode->i_size / fs->blocksize) >= 3))
4190 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
4191
4192 if (!pb.num_blocks && pb.is_dir) {
4193 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
4194 inode->i_links_count = 0;
4195 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
4196 inode->i_dtime = time(NULL);
4197 dirty_inode++;
4198 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
4199 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
4200 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
4201 ctx->fs_directory_count--;
4202 goto out;
4203 }
4204 }
4205
4206 pb.num_blocks *= (fs->blocksize / 512);
4207
4208 if (pb.is_dir) {
4209 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
4210 if (nblock > (pb.last_block + 1))
4211 bad_size = 1;
4212 else if (nblock < (pb.last_block + 1)) {
4213 if (((pb.last_block + 1) - nblock) >
4214 fs->super->s_prealloc_dir_blocks)
4215 bad_size = 2;
4216 }
4217 } else {
4218 size = EXT2_I_SIZE(inode);
4219 if ((pb.last_block >= 0) &&
4220 (size < (__u64) pb.last_block * fs->blocksize))
4221 bad_size = 3;
4222 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
4223 bad_size = 4;
4224 }
4225
4226 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
4227 pctx->num = (pb.last_block+1) * fs->blocksize;
4228 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
4229 inode->i_size = pctx->num;
4230 if (!LINUX_S_ISDIR(inode->i_mode))
4231 inode->i_size_high = pctx->num >> 32;
4232 dirty_inode++;
4233 }
4234 pctx->num = 0;
4235 }
4236 if (LINUX_S_ISREG(inode->i_mode) &&
4237 (inode->i_size_high || inode->i_size & 0x80000000UL))
4238 ctx->large_files++;
4239 if (pb.num_blocks != inode->i_blocks) {
4240 pctx->num = pb.num_blocks;
4241 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
4242 inode->i_blocks = pb.num_blocks;
4243 dirty_inode++;
4244 }
4245 pctx->num = 0;
4246 }
4247out:
4248 if (dirty_inode)
4249 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
4250}
4251
4252
4253
4254
4255
4256static int process_block(ext2_filsys fs,
4257 blk_t *block_nr,
4258 e2_blkcnt_t blockcnt,
4259 blk_t ref_block FSCK_ATTR((unused)),
4260 int ref_offset FSCK_ATTR((unused)),
4261 void *priv_data)
4262{
4263 struct process_block_struct_1 *p;
4264 struct problem_context *pctx;
4265 blk_t blk = *block_nr;
4266 int ret_code = 0;
4267 int problem = 0;
4268 e2fsck_t ctx;
4269
4270 p = (struct process_block_struct_1 *) priv_data;
4271 pctx = p->pctx;
4272 ctx = p->ctx;
4273
4274 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293 return 0;
4294 }
4295
4296 if (blk == 0) {
4297 if (p->is_dir == 0) {
4298
4299
4300
4301
4302#ifdef DEBUG_E2FSCK
4303 printf("process_block() called with blk == 0, "
4304 "blockcnt=%d, inode %lu???\n",
4305 blockcnt, p->ino);
4306#endif
4307 return 0;
4308 }
4309 if (blockcnt < 0)
4310 return 0;
4311 if (blockcnt * fs->blocksize < p->inode->i_size) {
4312 goto mark_dir;
4313 }
4314 return 0;
4315 }
4316
4317
4318
4319
4320
4321
4322 if (!HOLE_BLKADDR(p->previous_block)) {
4323 if (p->previous_block+1 != blk)
4324 p->fragmented = 1;
4325 }
4326 p->previous_block = blk;
4327
4328 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
4329 problem = PR_1_TOOBIG_DIR;
4330 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
4331 problem = PR_1_TOOBIG_REG;
4332 if (!p->is_dir && !p->is_reg && blockcnt > 0)
4333 problem = PR_1_TOOBIG_SYMLINK;
4334
4335 if (blk < fs->super->s_first_data_block ||
4336 blk >= fs->super->s_blocks_count)
4337 problem = PR_1_ILLEGAL_BLOCK_NUM;
4338
4339 if (problem) {
4340 p->num_illegal_blocks++;
4341 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
4342 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
4343 p->clear = 1;
4344 return BLOCK_ABORT;
4345 }
4346 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
4347 p->suppress = 1;
4348 set_latch_flags(PR_LATCH_BLOCK,
4349 PRL_SUPPRESS, 0);
4350 }
4351 }
4352 pctx->blk = blk;
4353 pctx->blkcount = blockcnt;
4354 if (fix_problem(ctx, problem, pctx)) {
4355 blk = *block_nr = 0;
4356 ret_code = BLOCK_CHANGED;
4357 goto mark_dir;
4358 } else
4359 return 0;
4360 }
4361
4362 if (p->ino == EXT2_RESIZE_INO) {
4363
4364
4365
4366
4367
4368
4369
4370 if (blockcnt == BLOCK_COUNT_DIND)
4371 mark_block_used(ctx, blk);
4372 } else
4373 mark_block_used(ctx, blk);
4374 p->num_blocks++;
4375 if (blockcnt >= 0)
4376 p->last_block = blockcnt;
4377mark_dir:
4378 if (p->is_dir && (blockcnt >= 0)) {
4379 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
4380 blk, blockcnt);
4381 if (pctx->errcode) {
4382 pctx->blk = blk;
4383 pctx->num = blockcnt;
4384 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
4385
4386 ctx->flags |= E2F_FLAG_ABORT;
4387 return BLOCK_ABORT;
4388 }
4389 }
4390 return ret_code;
4391}
4392
4393static int process_bad_block(ext2_filsys fs FSCK_ATTR((unused)),
4394 blk_t *block_nr,
4395 e2_blkcnt_t blockcnt,
4396 blk_t ref_block FSCK_ATTR((unused)),
4397 int ref_offset FSCK_ATTR((unused)),
4398 void *priv_data EXT2FS_ATTR((unused)))
4399{
4400
4401
4402
4403
4404
4405 printf("Unrecoverable Error: Found %"PRIi64" bad blocks starting at block number: %u\n", blockcnt, *block_nr);
4406 return BLOCK_ERROR;
4407}
4408
4409
4410
4411
4412
4413
4414
4415
4416static void handle_fs_bad_blocks(e2fsck_t ctx)
4417{
4418 printf("Bad blocks detected on your filesystem\n"
4419 "You should get your data off as the device will soon die\n");
4420}
4421
4422
4423
4424
4425
4426static void mark_table_blocks(e2fsck_t ctx)
4427{
4428 ext2_filsys fs = ctx->fs;
4429 blk_t block, b;
4430 dgrp_t i;
4431 int j;
4432 struct problem_context pctx;
4433
4434 clear_problem_context(&pctx);
4435
4436 block = fs->super->s_first_data_block;
4437 for (i = 0; i < fs->group_desc_count; i++) {
4438 pctx.group = i;
4439
4440 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
4441
4442
4443
4444
4445 if (fs->group_desc[i].bg_inode_table) {
4446 for (j = 0, b = fs->group_desc[i].bg_inode_table;
4447 j < fs->inode_blocks_per_group;
4448 j++, b++) {
4449 if (ext2fs_test_block_bitmap(ctx->block_found_map,
4450 b)) {
4451 pctx.blk = b;
4452 if (fix_problem(ctx,
4453 PR_1_ITABLE_CONFLICT, &pctx)) {
4454 ctx->invalid_inode_table_flag[i]++;
4455 ctx->invalid_bitmaps++;
4456 }
4457 } else {
4458 ext2fs_mark_block_bitmap(ctx->block_found_map,
4459 b);
4460 }
4461 }
4462 }
4463
4464
4465
4466
4467 if (fs->group_desc[i].bg_block_bitmap) {
4468 if (ext2fs_test_block_bitmap(ctx->block_found_map,
4469 fs->group_desc[i].bg_block_bitmap)) {
4470 pctx.blk = fs->group_desc[i].bg_block_bitmap;
4471 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
4472 ctx->invalid_block_bitmap_flag[i]++;
4473 ctx->invalid_bitmaps++;
4474 }
4475 } else {
4476 ext2fs_mark_block_bitmap(ctx->block_found_map,
4477 fs->group_desc[i].bg_block_bitmap);
4478 }
4479
4480 }
4481
4482
4483
4484 if (fs->group_desc[i].bg_inode_bitmap) {
4485 if (ext2fs_test_block_bitmap(ctx->block_found_map,
4486 fs->group_desc[i].bg_inode_bitmap)) {
4487 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
4488 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
4489 ctx->invalid_inode_bitmap_flag[i]++;
4490 ctx->invalid_bitmaps++;
4491 }
4492 } else {
4493 ext2fs_mark_block_bitmap(ctx->block_found_map,
4494 fs->group_desc[i].bg_inode_bitmap);
4495 }
4496 }
4497 block += fs->super->s_blocks_per_group;
4498 }
4499}
4500
4501
4502
4503
4504
4505
4506
4507static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
4508 blk_t *blocks)
4509{
4510 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4511 int i;
4512
4513 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
4514 return EXT2_ET_CALLBACK_NOTHANDLED;
4515
4516 for (i=0; i < EXT2_N_BLOCKS; i++)
4517 blocks[i] = ctx->stashed_inode->i_block[i];
4518 return 0;
4519}
4520
4521static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
4522 struct ext2_inode *inode)
4523{
4524 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4525
4526 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
4527 return EXT2_ET_CALLBACK_NOTHANDLED;
4528 *inode = *ctx->stashed_inode;
4529 return 0;
4530}
4531
4532static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
4533 struct ext2_inode *inode)
4534{
4535 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4536
4537 if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
4538 *ctx->stashed_inode = *inode;
4539 return EXT2_ET_CALLBACK_NOTHANDLED;
4540}
4541
4542static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
4543{
4544 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4545
4546 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
4547 return EXT2_ET_CALLBACK_NOTHANDLED;
4548
4549 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
4550 return EXT2_ET_NO_DIRECTORY;
4551 return 0;
4552}
4553
4554void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
4555{
4556 ext2_filsys fs = ctx->fs;
4557
4558 if (bool) {
4559 fs->get_blocks = pass1_get_blocks;
4560 fs->check_directory = pass1_check_directory;
4561 fs->read_inode = pass1_read_inode;
4562 fs->write_inode = pass1_write_inode;
4563 ctx->stashed_ino = 0;
4564 } else {
4565 fs->get_blocks = 0;
4566 fs->check_directory = 0;
4567 fs->read_inode = 0;
4568 fs->write_inode = 0;
4569 }
4570}
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
4597#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
4598
4599
4600#define BLOCK_COUNT_EXTATTR (-5)
4601
4602struct block_el {
4603 blk_t block;
4604 struct block_el *next;
4605};
4606
4607struct inode_el {
4608 ext2_ino_t inode;
4609 struct inode_el *next;
4610};
4611
4612struct dup_block {
4613 int num_bad;
4614 struct inode_el *inode_list;
4615};
4616
4617
4618
4619
4620
4621
4622
4623
4624struct dup_inode {
4625 ext2_ino_t dir;
4626 int num_dupblocks;
4627 struct ext2_inode inode;
4628 struct block_el *block_list;
4629};
4630
4631static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
4632 e2_blkcnt_t blockcnt, blk_t ref_blk,
4633 int ref_offset, void *priv_data);
4634static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
4635 struct dup_inode *dp, char *block_buf);
4636static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
4637 struct dup_inode *dp, char* block_buf);
4638static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
4639
4640static void pass1b(e2fsck_t ctx, char *block_buf);
4641static void pass1c(e2fsck_t ctx, char *block_buf);
4642static void pass1d(e2fsck_t ctx, char *block_buf);
4643
4644static int dup_inode_count = 0;
4645
4646static dict_t blk_dict, ino_dict;
4647
4648static ext2fs_inode_bitmap inode_dup_map;
4649
4650static int dict_int_cmp(const void *a, const void *b)
4651{
4652 intptr_t ia, ib;
4653
4654 ia = (intptr_t)a;
4655 ib = (intptr_t)b;
4656
4657 return (ia-ib);
4658}
4659
4660
4661
4662
4663static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
4664 struct ext2_inode *inode)
4665{
4666 dnode_t *n;
4667 struct dup_block *db;
4668 struct dup_inode *di;
4669 struct block_el *blk_el;
4670 struct inode_el *ino_el;
4671
4672 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
4673 if (n)
4674 db = (struct dup_block *) dnode_get(n);
4675 else {
4676 db = (struct dup_block *) e2fsck_allocate_memory(ctx,
4677 sizeof(struct dup_block), "duplicate block header");
4678 db->num_bad = 0;
4679 db->inode_list = 0;
4680 dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
4681 }
4682 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
4683 sizeof(struct inode_el), "inode element");
4684 ino_el->inode = ino;
4685 ino_el->next = db->inode_list;
4686 db->inode_list = ino_el;
4687 db->num_bad++;
4688
4689 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
4690 if (n)
4691 di = (struct dup_inode *) dnode_get(n);
4692 else {
4693 di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
4694 sizeof(struct dup_inode), "duplicate inode header");
4695 di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0;
4696 di->num_dupblocks = 0;
4697 di->block_list = 0;
4698 di->inode = *inode;
4699 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
4700 }
4701 blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
4702 sizeof(struct block_el), "block element");
4703 blk_el->block = blk;
4704 blk_el->next = di->block_list;
4705 di->block_list = blk_el;
4706 di->num_dupblocks++;
4707}
4708
4709
4710
4711
4712static void inode_dnode_free(dnode_t *node)
4713{
4714 struct dup_inode *di;
4715 struct block_el *p, *next;
4716
4717 di = (struct dup_inode *) dnode_get(node);
4718 for (p = di->block_list; p; p = next) {
4719 next = p->next;
4720 free(p);
4721 }
4722 free(node);
4723}
4724
4725
4726
4727
4728static void block_dnode_free(dnode_t *node)
4729{
4730 struct dup_block *db;
4731 struct inode_el *p, *next;
4732
4733 db = (struct dup_block *) dnode_get(node);
4734 for (p = db->inode_list; p; p = next) {
4735 next = p->next;
4736 free(p);
4737 }
4738 free(node);
4739}
4740
4741
4742
4743
4744
4745void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
4746{
4747 ext2_filsys fs = ctx->fs;
4748 struct problem_context pctx;
4749
4750 clear_problem_context(&pctx);
4751
4752 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4753 _("multiply claimed inode map"), &inode_dup_map);
4754 if (pctx.errcode) {
4755 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
4756 ctx->flags |= E2F_FLAG_ABORT;
4757 return;
4758 }
4759
4760 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
4761 dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
4762 dict_set_allocator(&ino_dict, inode_dnode_free);
4763 dict_set_allocator(&blk_dict, block_dnode_free);
4764
4765 pass1b(ctx, block_buf);
4766 pass1c(ctx, block_buf);
4767 pass1d(ctx, block_buf);
4768
4769
4770
4771
4772
4773 dict_free_nodes(&ino_dict);
4774 dict_free_nodes(&blk_dict);
4775}
4776
4777
4778
4779
4780struct process_block_struct_1b {
4781 e2fsck_t ctx;
4782 ext2_ino_t ino;
4783 int dup_blocks;
4784 struct ext2_inode *inode;
4785 struct problem_context *pctx;
4786};
4787
4788static void pass1b(e2fsck_t ctx, char *block_buf)
4789{
4790 ext2_filsys fs = ctx->fs;
4791 ext2_ino_t ino;
4792 struct ext2_inode inode;
4793 ext2_inode_scan scan;
4794 struct process_block_struct_1b pb;
4795 struct problem_context pctx;
4796
4797 clear_problem_context(&pctx);
4798
4799 if (!(ctx->options & E2F_OPT_PREEN))
4800 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
4801 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
4802 &scan);
4803 if (pctx.errcode) {
4804 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
4805 ctx->flags |= E2F_FLAG_ABORT;
4806 return;
4807 }
4808 ctx->stashed_inode = &inode;
4809 pb.ctx = ctx;
4810 pb.pctx = &pctx;
4811 pctx.str = "pass1b";
4812 while (1) {
4813 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
4814 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
4815 continue;
4816 if (pctx.errcode) {
4817 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
4818 ctx->flags |= E2F_FLAG_ABORT;
4819 return;
4820 }
4821 if (!ino)
4822 break;
4823 pctx.ino = ctx->stashed_ino = ino;
4824 if ((ino != EXT2_BAD_INO) &&
4825 !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
4826 continue;
4827
4828 pb.ino = ino;
4829 pb.dup_blocks = 0;
4830 pb.inode = &inode;
4831
4832 if (ext2fs_inode_has_valid_blocks(&inode) ||
4833 (ino == EXT2_BAD_INO))
4834 pctx.errcode = ext2fs_block_iterate2(fs, ino,
4835 0, block_buf, process_pass1b_block, &pb);
4836 if (inode.i_file_acl)
4837 process_pass1b_block(fs, &inode.i_file_acl,
4838 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
4839 if (pb.dup_blocks) {
4840 end_problem_latch(ctx, PR_LATCH_DBLOCK);
4841 if (ino >= EXT2_FIRST_INODE(fs->super) ||
4842 ino == EXT2_ROOT_INO)
4843 dup_inode_count++;
4844 }
4845 if (pctx.errcode)
4846 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
4847 }
4848 ext2fs_close_inode_scan(scan);
4849 e2fsck_use_inode_shortcuts(ctx, 0);
4850}
4851
4852static int process_pass1b_block(ext2_filsys fs FSCK_ATTR((unused)),
4853 blk_t *block_nr,
4854 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
4855 blk_t ref_blk FSCK_ATTR((unused)),
4856 int ref_offset FSCK_ATTR((unused)),
4857 void *priv_data)
4858{
4859 struct process_block_struct_1b *p;
4860 e2fsck_t ctx;
4861
4862 if (HOLE_BLKADDR(*block_nr))
4863 return 0;
4864 p = (struct process_block_struct_1b *) priv_data;
4865 ctx = p->ctx;
4866
4867 if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
4868 return 0;
4869
4870
4871 if (p->ino != EXT2_BAD_INO) {
4872 p->pctx->blk = *block_nr;
4873 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
4874 }
4875 p->dup_blocks++;
4876 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
4877
4878 add_dupe(ctx, p->ino, *block_nr, p->inode);
4879
4880 return 0;
4881}
4882
4883
4884
4885
4886
4887
4888struct search_dir_struct {
4889 int count;
4890 ext2_ino_t first_inode;
4891 ext2_ino_t max_inode;
4892};
4893
4894static int search_dirent_proc(ext2_ino_t dir, int entry,
4895 struct ext2_dir_entry *dirent,
4896 int offset FSCK_ATTR((unused)),
4897 int blocksize FSCK_ATTR((unused)),
4898 char *buf FSCK_ATTR((unused)),
4899 void *priv_data)
4900{
4901 struct search_dir_struct *sd;
4902 struct dup_inode *p;
4903 dnode_t *n;
4904
4905 sd = (struct search_dir_struct *) priv_data;
4906
4907 if (dirent->inode > sd->max_inode)
4908
4909 return 0;
4910
4911 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
4912 !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
4913 return 0;
4914
4915 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
4916 if (!n)
4917 return 0;
4918 p = (struct dup_inode *) dnode_get(n);
4919 p->dir = dir;
4920 sd->count--;
4921
4922 return sd->count ? 0 : DIRENT_ABORT;
4923}
4924
4925
4926static void pass1c(e2fsck_t ctx, char *block_buf)
4927{
4928 ext2_filsys fs = ctx->fs;
4929 struct search_dir_struct sd;
4930 struct problem_context pctx;
4931
4932 clear_problem_context(&pctx);
4933
4934 if (!(ctx->options & E2F_OPT_PREEN))
4935 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
4936
4937
4938
4939
4940
4941 sd.count = dup_inode_count;
4942 sd.first_inode = EXT2_FIRST_INODE(fs->super);
4943 sd.max_inode = fs->super->s_inodes_count;
4944 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
4945 search_dirent_proc, &sd);
4946}
4947
4948static void pass1d(e2fsck_t ctx, char *block_buf)
4949{
4950 ext2_filsys fs = ctx->fs;
4951 struct dup_inode *p, *t;
4952 struct dup_block *q;
4953 ext2_ino_t *shared, ino;
4954 int shared_len;
4955 int i;
4956 int file_ok;
4957 int meta_data = 0;
4958 struct problem_context pctx;
4959 dnode_t *n, *m;
4960 struct block_el *s;
4961 struct inode_el *r;
4962
4963 clear_problem_context(&pctx);
4964
4965 if (!(ctx->options & E2F_OPT_PREEN))
4966 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
4967 e2fsck_read_bitmaps(ctx);
4968
4969 pctx.num = dup_inode_count;
4970 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
4971 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
4972 sizeof(ext2_ino_t) * dict_count(&ino_dict),
4973 "Shared inode list");
4974 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
4975 p = (struct dup_inode *) dnode_get(n);
4976 shared_len = 0;
4977 file_ok = 1;
4978 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
4979 if (ino == EXT2_BAD_INO || ino == EXT2_RESIZE_INO)
4980 continue;
4981
4982
4983
4984
4985
4986
4987
4988 for (s = p->block_list; s; s = s->next) {
4989 m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
4990 if (!m)
4991 continue;
4992 q = (struct dup_block *) dnode_get(m);
4993 if (q->num_bad > 1)
4994 file_ok = 0;
4995 if (check_if_fs_block(ctx, s->block)) {
4996 file_ok = 0;
4997 meta_data = 1;
4998 }
4999
5000
5001
5002
5003
5004
5005
5006 for (r = q->inode_list; r; r = r->next) {
5007 if (r->inode == ino)
5008 continue;
5009 for (i = 0; i < shared_len; i++)
5010 if (shared[i] == r->inode)
5011 break;
5012 if (i == shared_len) {
5013 shared[shared_len++] = r->inode;
5014 }
5015 }
5016 }
5017
5018
5019
5020
5021 pctx.inode = &p->inode;
5022 pctx.ino = ino;
5023 pctx.dir = p->dir;
5024 pctx.blkcount = p->num_dupblocks;
5025 pctx.num = meta_data ? shared_len+1 : shared_len;
5026 fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
5027 pctx.blkcount = 0;
5028 pctx.num = 0;
5029
5030 if (meta_data)
5031 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
5032
5033 for (i = 0; i < shared_len; i++) {
5034 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
5035 if (!m)
5036 continue;
5037 t = (struct dup_inode *) dnode_get(m);
5038
5039
5040
5041 pctx.inode = &t->inode;
5042 pctx.ino = shared[i];
5043 pctx.dir = t->dir;
5044 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
5045 }
5046 if (file_ok) {
5047 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
5048 continue;
5049 }
5050 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
5051 pctx.errcode = clone_file(ctx, ino, p, block_buf);
5052 if (pctx.errcode)
5053 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
5054 else
5055 continue;
5056 }
5057 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
5058 delete_file(ctx, ino, p, block_buf);
5059 else
5060 ext2fs_unmark_valid(fs);
5061 }
5062 ext2fs_free_mem(&shared);
5063}
5064
5065
5066
5067
5068
5069static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
5070{
5071 p->num_bad--;
5072 if (p->num_bad <= 0 ||
5073 (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
5074 ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
5075}
5076
5077static int delete_file_block(ext2_filsys fs,
5078 blk_t *block_nr,
5079 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
5080 blk_t ref_block FSCK_ATTR((unused)),
5081 int ref_offset FSCK_ATTR((unused)),
5082 void *priv_data)
5083{
5084 struct process_block_struct_1b *pb;
5085 struct dup_block *p;
5086 dnode_t *n;
5087 e2fsck_t ctx;
5088
5089 pb = (struct process_block_struct_1b *) priv_data;
5090 ctx = pb->ctx;
5091
5092 if (HOLE_BLKADDR(*block_nr))
5093 return 0;
5094
5095 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
5096 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
5097 if (n) {
5098 p = (struct dup_block *) dnode_get(n);
5099 decrement_badcount(ctx, *block_nr, p);
5100 } else
5101 bb_error_msg(_("internal error; can't find dup_blk for %d"),
5102 *block_nr);
5103 } else {
5104 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
5105 ext2fs_block_alloc_stats(fs, *block_nr, -1);
5106 }
5107
5108 return 0;
5109}
5110
5111static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
5112 struct dup_inode *dp, char* block_buf)
5113{
5114 ext2_filsys fs = ctx->fs;
5115 struct process_block_struct_1b pb;
5116 struct ext2_inode inode;
5117 struct problem_context pctx;
5118 unsigned int count;
5119
5120 clear_problem_context(&pctx);
5121 pctx.ino = pb.ino = ino;
5122 pb.dup_blocks = dp->num_dupblocks;
5123 pb.ctx = ctx;
5124 pctx.str = "delete_file";
5125
5126 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
5127 if (ext2fs_inode_has_valid_blocks(&inode))
5128 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
5129 delete_file_block, &pb);
5130 if (pctx.errcode)
5131 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
5132 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5133 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5134 if (ctx->inode_bad_map)
5135 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
5136 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
5137
5138
5139 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
5140 inode.i_links_count = 0;
5141 inode.i_dtime = time(NULL);
5142 if (inode.i_file_acl &&
5143 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
5144 count = 1;
5145 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
5146 block_buf, -1, &count);
5147 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
5148 pctx.errcode = 0;
5149 count = 1;
5150 }
5151 if (pctx.errcode) {
5152 pctx.blk = inode.i_file_acl;
5153 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
5154 }
5155
5156
5157
5158
5159
5160
5161 if ((count == 0) ||
5162 ext2fs_test_block_bitmap(ctx->block_dup_map,
5163 inode.i_file_acl))
5164 delete_file_block(fs, &inode.i_file_acl,
5165 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
5166 }
5167 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
5168}
5169
5170struct clone_struct {
5171 errcode_t errcode;
5172 ext2_ino_t dir;
5173 char *buf;
5174 e2fsck_t ctx;
5175};
5176
5177static int clone_file_block(ext2_filsys fs,
5178 blk_t *block_nr,
5179 e2_blkcnt_t blockcnt,
5180 blk_t ref_block FSCK_ATTR((unused)),
5181 int ref_offset FSCK_ATTR((unused)),
5182 void *priv_data)
5183{
5184 struct dup_block *p;
5185 blk_t new_block;
5186 errcode_t retval;
5187 struct clone_struct *cs = (struct clone_struct *) priv_data;
5188 dnode_t *n;
5189 e2fsck_t ctx;
5190
5191 ctx = cs->ctx;
5192
5193 if (HOLE_BLKADDR(*block_nr))
5194 return 0;
5195
5196 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
5197 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
5198 if (n) {
5199 p = (struct dup_block *) dnode_get(n);
5200 retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
5201 &new_block);
5202 if (retval) {
5203 cs->errcode = retval;
5204 return BLOCK_ABORT;
5205 }
5206 if (cs->dir && (blockcnt >= 0)) {
5207 retval = ext2fs_set_dir_block(fs->dblist,
5208 cs->dir, new_block, blockcnt);
5209 if (retval) {
5210 cs->errcode = retval;
5211 return BLOCK_ABORT;
5212 }
5213 }
5214
5215 retval = io_channel_read_blk(fs->io, *block_nr, 1,
5216 cs->buf);
5217 if (retval) {
5218 cs->errcode = retval;
5219 return BLOCK_ABORT;
5220 }
5221 retval = io_channel_write_blk(fs->io, new_block, 1,
5222 cs->buf);
5223 if (retval) {
5224 cs->errcode = retval;
5225 return BLOCK_ABORT;
5226 }
5227 decrement_badcount(ctx, *block_nr, p);
5228 *block_nr = new_block;
5229 ext2fs_mark_block_bitmap(ctx->block_found_map,
5230 new_block);
5231 ext2fs_mark_block_bitmap(fs->block_map, new_block);
5232 return BLOCK_CHANGED;
5233 } else
5234 bb_error_msg(_("internal error; can't find dup_blk for %d"),
5235 *block_nr);
5236 }
5237 return 0;
5238}
5239
5240static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
5241 struct dup_inode *dp, char* block_buf)
5242{
5243 ext2_filsys fs = ctx->fs;
5244 errcode_t retval;
5245 struct clone_struct cs;
5246 struct problem_context pctx;
5247 blk_t blk;
5248 dnode_t *n;
5249 struct inode_el *ino_el;
5250 struct dup_block *db;
5251 struct dup_inode *di;
5252
5253 clear_problem_context(&pctx);
5254 cs.errcode = 0;
5255 cs.dir = 0;
5256 cs.ctx = ctx;
5257 retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
5258 if (retval)
5259 return retval;
5260
5261 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
5262 cs.dir = ino;
5263
5264 pctx.ino = ino;
5265 pctx.str = "clone_file";
5266 if (ext2fs_inode_has_valid_blocks(&dp->inode))
5267 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
5268 clone_file_block, &cs);
5269 ext2fs_mark_bb_dirty(fs);
5270 if (pctx.errcode) {
5271 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
5272 retval = pctx.errcode;
5273 goto errout;
5274 }
5275 if (cs.errcode) {
5276 bb_error_msg(_("returned from clone_file_block"));
5277 retval = cs.errcode;
5278 goto errout;
5279 }
5280
5281 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
5282 blk = dp->inode.i_file_acl;
5283 if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
5284 BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
5285 BLOCK_CHANGED)) {
5286 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
5287
5288
5289
5290
5291
5292 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
5293 db = (struct dup_block *) dnode_get(n);
5294 for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
5295 if (ino_el->inode == ino)
5296 continue;
5297 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
5298 di = (struct dup_inode *) dnode_get(n);
5299 if (di->inode.i_file_acl == blk) {
5300 di->inode.i_file_acl = dp->inode.i_file_acl;
5301 e2fsck_write_inode(ctx, ino_el->inode,
5302 &di->inode, "clone file EA");
5303 decrement_badcount(ctx, blk, db);
5304 }
5305 }
5306 }
5307 retval = 0;
5308errout:
5309 ext2fs_free_mem(&cs.buf);
5310 return retval;
5311}
5312
5313
5314
5315
5316
5317static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
5318{
5319 ext2_filsys fs = ctx->fs;
5320 blk_t block;
5321 dgrp_t i;
5322
5323 block = fs->super->s_first_data_block;
5324 for (i = 0; i < fs->group_desc_count; i++) {
5325
5326
5327 if (ext2fs_bg_has_super(fs, i)) {
5328 if (test_block >= block &&
5329 (test_block <= block + fs->desc_blocks))
5330 return 1;
5331 }
5332
5333
5334 if ((fs->group_desc[i].bg_inode_table) &&
5335 (test_block >= fs->group_desc[i].bg_inode_table) &&
5336 (test_block < (fs->group_desc[i].bg_inode_table +
5337 fs->inode_blocks_per_group)))
5338 return 1;
5339
5340
5341 if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
5342 (test_block == fs->group_desc[i].bg_inode_bitmap))
5343 return 1;
5344
5345 block += fs->super->s_blocks_per_group;
5346 }
5347 return 0;
5348}
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
5389static int check_dir_block(ext2_filsys fs,
5390 struct ext2_db_entry *dir_blocks_info,
5391 void *priv_data);
5392static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info,
5393 struct problem_context *pctx);
5394static int update_dir_block(ext2_filsys fs,
5395 blk_t *block_nr,
5396 e2_blkcnt_t blockcnt,
5397 blk_t ref_block,
5398 int ref_offset,
5399 void *priv_data);
5400static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
5401static int htree_depth(struct dx_dir_info *dx_dir,
5402 struct dx_dirblock_info *dx_db);
5403static int special_dir_block_cmp(const void *a, const void *b);
5404
5405struct check_dir_struct {
5406 char *buf;
5407 struct problem_context pctx;
5408 int count, max;
5409 e2fsck_t ctx;
5410};
5411
5412static void e2fsck_pass2(e2fsck_t ctx)
5413{
5414 struct ext2_super_block *sb = ctx->fs->super;
5415 struct problem_context pctx;
5416 ext2_filsys fs = ctx->fs;
5417 char *buf;
5418 struct dir_info *dir;
5419 struct check_dir_struct cd;
5420 struct dx_dir_info *dx_dir;
5421 struct dx_dirblock_info *dx_db, *dx_parent;
5422 int b;
5423 int i, depth;
5424 problem_t code;
5425 int bad_dir;
5426
5427 clear_problem_context(&cd.pctx);
5428
5429
5430
5431 if (!(ctx->options & E2F_OPT_PREEN))
5432 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
5433
5434 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
5435 0, ctx->inode_link_info,
5436 &ctx->inode_count);
5437 if (cd.pctx.errcode) {
5438 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
5439 ctx->flags |= E2F_FLAG_ABORT;
5440 return;
5441 }
5442 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
5443 "directory scan buffer");
5444
5445
5446
5447
5448
5449
5450 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
5451 if (dir)
5452 dir->parent = EXT2_ROOT_INO;
5453
5454 cd.buf = buf;
5455 cd.ctx = ctx;
5456 cd.count = 1;
5457 cd.max = ext2fs_dblist_count(fs->dblist);
5458
5459 if (ctx->progress)
5460 (void) (ctx->progress)(ctx, 2, 0, cd.max);
5461
5462 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
5463 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
5464
5465 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
5466 &cd);
5467 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5468 return;
5469 if (cd.pctx.errcode) {
5470 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
5471 ctx->flags |= E2F_FLAG_ABORT;
5472 return;
5473 }
5474
5475#ifdef ENABLE_HTREE
5476 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
5477 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5478 return;
5479 if (dx_dir->numblocks == 0)
5480 continue;
5481 clear_problem_context(&pctx);
5482 bad_dir = 0;
5483 pctx.dir = dx_dir->ino;
5484 dx_db = dx_dir->dx_block;
5485 if (dx_db->flags & DX_FLAG_REFERENCED)
5486 dx_db->flags |= DX_FLAG_DUP_REF;
5487 else
5488 dx_db->flags |= DX_FLAG_REFERENCED;
5489
5490
5491
5492
5493 for (b=0, dx_db = dx_dir->dx_block;
5494 b < dx_dir->numblocks;
5495 b++, dx_db++) {
5496 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
5497 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
5498 continue;
5499 dx_parent = &dx_dir->dx_block[dx_db->parent];
5500
5501
5502
5503 if (dx_db->flags & DX_FLAG_FIRST)
5504 dx_parent->min_hash = dx_db->min_hash;
5505
5506
5507
5508 if (dx_db->flags & DX_FLAG_LAST)
5509 dx_parent->max_hash = dx_db->max_hash;
5510 }
5511
5512 for (b=0, dx_db = dx_dir->dx_block;
5513 b < dx_dir->numblocks;
5514 b++, dx_db++) {
5515 pctx.blkcount = b;
5516 pctx.group = dx_db->parent;
5517 code = 0;
5518 if (!(dx_db->flags & DX_FLAG_FIRST) &&
5519 (dx_db->min_hash < dx_db->node_min_hash)) {
5520 pctx.blk = dx_db->min_hash;
5521 pctx.blk2 = dx_db->node_min_hash;
5522 code = PR_2_HTREE_MIN_HASH;
5523 fix_problem(ctx, code, &pctx);
5524 bad_dir++;
5525 }
5526 if (dx_db->type == DX_DIRBLOCK_LEAF) {
5527 depth = htree_depth(dx_dir, dx_db);
5528 if (depth != dx_dir->depth) {
5529 code = PR_2_HTREE_BAD_DEPTH;
5530 fix_problem(ctx, code, &pctx);
5531 bad_dir++;
5532 }
5533 }
5534
5535
5536
5537
5538 if (b &&
5539 (dx_db->max_hash > dx_db->node_max_hash)) {
5540 pctx.blk = dx_db->max_hash;
5541 pctx.blk2 = dx_db->node_max_hash;
5542 code = PR_2_HTREE_MAX_HASH;
5543 fix_problem(ctx, code, &pctx);
5544 bad_dir++;
5545 }
5546 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
5547 code = PR_2_HTREE_NOTREF;
5548 fix_problem(ctx, code, &pctx);
5549 bad_dir++;
5550 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
5551 code = PR_2_HTREE_DUPREF;
5552 fix_problem(ctx, code, &pctx);
5553 bad_dir++;
5554 }
5555 if (code == 0)
5556 continue;
5557 }
5558 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
5559 clear_htree(ctx, dx_dir->ino);
5560 dx_dir->numblocks = 0;
5561 }
5562 }
5563#endif
5564 ext2fs_free_mem(&buf);
5565 ext2fs_free_dblist(fs->dblist);
5566
5567 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
5568 ctx->inode_bad_map = 0;
5569 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
5570 ctx->inode_reg_map = 0;
5571
5572 clear_problem_context(&pctx);
5573 if (ctx->large_files) {
5574 if (!(sb->s_feature_ro_compat &
5575 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
5576 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
5577 sb->s_feature_ro_compat |=
5578 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
5579 ext2fs_mark_super_dirty(fs);
5580 }
5581 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
5582 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
5583 ext2fs_update_dynamic_rev(fs);
5584 ext2fs_mark_super_dirty(fs);
5585 }
5586 } else if (!ctx->large_files &&
5587 (sb->s_feature_ro_compat &
5588 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
5589 if (fs->flags & EXT2_FLAG_RW) {
5590 sb->s_feature_ro_compat &=
5591 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
5592 ext2fs_mark_super_dirty(fs);
5593 }
5594 }
5595
5596}
5597
5598#define MAX_DEPTH 32000
5599static int htree_depth(struct dx_dir_info *dx_dir,
5600 struct dx_dirblock_info *dx_db)
5601{
5602 int depth = 0;
5603
5604 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
5605 dx_db = &dx_dir->dx_block[dx_db->parent];
5606 depth++;
5607 }
5608 return depth;
5609}
5610
5611static int dict_de_cmp(const void *a, const void *b)
5612{
5613 const struct ext2_dir_entry *de_a, *de_b;
5614 int a_len, b_len;
5615
5616 de_a = (const struct ext2_dir_entry *) a;
5617 a_len = de_a->name_len & 0xFF;
5618 de_b = (const struct ext2_dir_entry *) b;
5619 b_len = de_b->name_len & 0xFF;
5620
5621 if (a_len != b_len)
5622 return (a_len - b_len);
5623
5624 return strncmp(de_a->name, de_b->name, a_len);
5625}
5626
5627
5628
5629
5630
5631
5632
5633static int special_dir_block_cmp(const void *a, const void *b)
5634{
5635 const struct ext2_db_entry *db_a =
5636 (const struct ext2_db_entry *) a;
5637 const struct ext2_db_entry *db_b =
5638 (const struct ext2_db_entry *) b;
5639
5640 if (db_a->blockcnt && !db_b->blockcnt)
5641 return 1;
5642
5643 if (!db_a->blockcnt && db_b->blockcnt)
5644 return -1;
5645
5646 if (db_a->blk != db_b->blk)
5647 return (int) (db_a->blk - db_b->blk);
5648
5649 if (db_a->ino != db_b->ino)
5650 return (int) (db_a->ino - db_b->ino);
5651
5652 return (int) (db_a->blockcnt - db_b->blockcnt);
5653}
5654
5655
5656
5657
5658
5659
5660static int check_dot(e2fsck_t ctx,
5661 struct ext2_dir_entry *dirent,
5662 ext2_ino_t ino, struct problem_context *pctx)
5663{
5664 struct ext2_dir_entry *nextdir;
5665 int status = 0;
5666 int created = 0;
5667 int new_len;
5668 int problem = 0;
5669
5670 if (!dirent->inode)
5671 problem = PR_2_MISSING_DOT;
5672 else if (((dirent->name_len & 0xFF) != 1) ||
5673 (dirent->name[0] != '.'))
5674 problem = PR_2_1ST_NOT_DOT;
5675 else if (dirent->name[1] != '\0')
5676 problem = PR_2_DOT_NULL_TERM;
5677
5678 if (problem) {
5679 if (fix_problem(ctx, problem, pctx)) {
5680 if (dirent->rec_len < 12)
5681 dirent->rec_len = 12;
5682 dirent->inode = ino;
5683 dirent->name_len = 1;
5684 dirent->name[0] = '.';
5685 dirent->name[1] = '\0';
5686 status = 1;
5687 created = 1;
5688 }
5689 }
5690 if (dirent->inode != ino) {
5691 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
5692 dirent->inode = ino;
5693 status = 1;
5694 }
5695 }
5696 if (dirent->rec_len > 12) {
5697 new_len = dirent->rec_len - 12;
5698 if (new_len > 12) {
5699 if (created ||
5700 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
5701 nextdir = (struct ext2_dir_entry *)
5702 ((char *) dirent + 12);
5703 dirent->rec_len = 12;
5704 nextdir->rec_len = new_len;
5705 nextdir->inode = 0;
5706 nextdir->name_len = 0;
5707 status = 1;
5708 }
5709 }
5710 }
5711 return status;
5712}
5713
5714
5715
5716
5717
5718
5719static int check_dotdot(e2fsck_t ctx,
5720 struct ext2_dir_entry *dirent,
5721 struct dir_info *dir, struct problem_context *pctx)
5722{
5723 int problem = 0;
5724
5725 if (!dirent->inode)
5726 problem = PR_2_MISSING_DOT_DOT;
5727 else if (((dirent->name_len & 0xFF) != 2) ||
5728 (dirent->name[0] != '.') ||
5729 (dirent->name[1] != '.'))
5730 problem = PR_2_2ND_NOT_DOT_DOT;
5731 else if (dirent->name[2] != '\0')
5732 problem = PR_2_DOT_DOT_NULL_TERM;
5733
5734 if (problem) {
5735 if (fix_problem(ctx, problem, pctx)) {
5736 if (dirent->rec_len < 12)
5737 dirent->rec_len = 12;
5738
5739
5740
5741
5742
5743 dirent->inode = EXT2_ROOT_INO;
5744 dirent->name_len = 2;
5745 dirent->name[0] = '.';
5746 dirent->name[1] = '.';
5747 dirent->name[2] = '\0';
5748 return 1;
5749 }
5750 return 0;
5751 }
5752 dir->dotdot = dirent->inode;
5753 return 0;
5754}
5755
5756
5757
5758
5759
5760static int check_name(e2fsck_t ctx,
5761 struct ext2_dir_entry *dirent,
5762 struct problem_context *pctx)
5763{
5764 int i;
5765 int fixup = -1;
5766 int ret = 0;
5767
5768 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
5769 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
5770 if (fixup < 0) {
5771 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
5772 }
5773 if (fixup) {
5774 dirent->name[i] = '.';
5775 ret = 1;
5776 }
5777 }
5778 }
5779 return ret;
5780}
5781
5782
5783
5784
5785
5786
5787
5788
5789static int ext2_file_type(unsigned int mode)
5790{
5791 if (LINUX_S_ISREG(mode))
5792 return EXT2_FT_REG_FILE;
5793
5794 if (LINUX_S_ISDIR(mode))
5795 return EXT2_FT_DIR;
5796
5797 if (LINUX_S_ISCHR(mode))
5798 return EXT2_FT_CHRDEV;
5799
5800 if (LINUX_S_ISBLK(mode))
5801 return EXT2_FT_BLKDEV;
5802
5803 if (LINUX_S_ISLNK(mode))
5804 return EXT2_FT_SYMLINK;
5805
5806 if (LINUX_S_ISFIFO(mode))
5807 return EXT2_FT_FIFO;
5808
5809 if (LINUX_S_ISSOCK(mode))
5810 return EXT2_FT_SOCK;
5811
5812 return 0;
5813}
5814
5815static int check_filetype(e2fsck_t ctx,
5816 struct ext2_dir_entry *dirent,
5817 struct problem_context *pctx)
5818{
5819 int filetype = dirent->name_len >> 8;
5820 int should_be = EXT2_FT_UNKNOWN;
5821 struct ext2_inode inode;
5822
5823 if (!(ctx->fs->super->s_feature_incompat &
5824 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
5825 if (filetype == 0 ||
5826 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
5827 return 0;
5828 dirent->name_len = dirent->name_len & 0xFF;
5829 return 1;
5830 }
5831
5832 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
5833 should_be = EXT2_FT_DIR;
5834 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
5835 dirent->inode)) {
5836 should_be = EXT2_FT_REG_FILE;
5837 } else if (ctx->inode_bad_map &&
5838 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
5839 dirent->inode))
5840 should_be = 0;
5841 else {
5842 e2fsck_read_inode(ctx, dirent->inode, &inode,
5843 "check_filetype");
5844 should_be = ext2_file_type(inode.i_mode);
5845 }
5846 if (filetype == should_be)
5847 return 0;
5848 pctx->num = should_be;
5849
5850 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
5851 pctx) == 0)
5852 return 0;
5853
5854 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
5855 return 1;
5856}
5857
5858#ifdef ENABLE_HTREE
5859static void parse_int_node(ext2_filsys fs,
5860 struct ext2_db_entry *db,
5861 struct check_dir_struct *cd,
5862 struct dx_dir_info *dx_dir,
5863 char *block_buf)
5864{
5865 struct ext2_dx_root_info *root;
5866 struct ext2_dx_entry *ent;
5867 struct ext2_dx_countlimit *limit;
5868 struct dx_dirblock_info *dx_db;
5869 int i, expect_limit, count;
5870 blk_t blk;
5871 ext2_dirhash_t min_hash = 0xffffffff;
5872 ext2_dirhash_t max_hash = 0;
5873 ext2_dirhash_t hash = 0, prev_hash;
5874
5875 if (db->blockcnt == 0) {
5876 root = (struct ext2_dx_root_info *) (block_buf + 24);
5877 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
5878 } else {
5879 ent = (struct ext2_dx_entry *) (block_buf+8);
5880 }
5881 limit = (struct ext2_dx_countlimit *) ent;
5882
5883 count = ext2fs_le16_to_cpu(limit->count);
5884 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
5885 sizeof(struct ext2_dx_entry);
5886 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
5887 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
5888 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
5889 goto clear_and_exit;
5890 }
5891 if (count > expect_limit) {
5892 cd->pctx.num = count;
5893 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
5894 goto clear_and_exit;
5895 count = expect_limit;
5896 }
5897
5898 for (i=0; i < count; i++) {
5899 prev_hash = hash;
5900 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
5901 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
5902
5903 if (blk > (blk_t) dx_dir->numblocks) {
5904 cd->pctx.blk = blk;
5905 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
5906 &cd->pctx))
5907 goto clear_and_exit;
5908 }
5909 if (hash < prev_hash &&
5910 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
5911 goto clear_and_exit;
5912 dx_db = &dx_dir->dx_block[blk];
5913 if (dx_db->flags & DX_FLAG_REFERENCED) {
5914 dx_db->flags |= DX_FLAG_DUP_REF;
5915 } else {
5916 dx_db->flags |= DX_FLAG_REFERENCED;
5917 dx_db->parent = db->blockcnt;
5918 }
5919 if (hash < min_hash)
5920 min_hash = hash;
5921 if (hash > max_hash)
5922 max_hash = hash;
5923 dx_db->node_min_hash = hash;
5924 if ((i+1) < count)
5925 dx_db->node_max_hash =
5926 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
5927 else {
5928 dx_db->node_max_hash = 0xfffffffe;
5929 dx_db->flags |= DX_FLAG_LAST;
5930 }
5931 if (i == 0)
5932 dx_db->flags |= DX_FLAG_FIRST;
5933 }
5934 dx_db = &dx_dir->dx_block[db->blockcnt];
5935 dx_db->min_hash = min_hash;
5936 dx_db->max_hash = max_hash;
5937 return;
5938
5939clear_and_exit:
5940 clear_htree(cd->ctx, cd->pctx.ino);
5941 dx_dir->numblocks = 0;
5942}
5943#endif
5944
5945
5946
5947
5948
5949static void salvage_directory(ext2_filsys fs,
5950 struct ext2_dir_entry *dirent,
5951 struct ext2_dir_entry *prev,
5952 unsigned int *offset)
5953{
5954 char *cp = (char *) dirent;
5955 int left = fs->blocksize - *offset - dirent->rec_len;
5956 int name_len = dirent->name_len & 0xFF;
5957
5958
5959
5960
5961
5962 if ((left >= 12) && (dirent->rec_len == 8)) {
5963 memmove(cp, cp+8, left);
5964 memset(cp + left, 0, 8);
5965 return;
5966 }
5967
5968
5969
5970
5971
5972 if ((left < 0) &&
5973 (name_len + 8 <= dirent->rec_len + left) &&
5974 dirent->inode <= fs->super->s_inodes_count &&
5975 strnlen(dirent->name, name_len) == name_len) {
5976 dirent->rec_len += left;
5977 return;
5978 }
5979
5980
5981
5982
5983
5984 if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
5985 prev->rec_len += dirent->rec_len;
5986 *offset += dirent->rec_len;
5987 return;
5988 }
5989
5990
5991
5992
5993
5994
5995 if (prev) {
5996 prev->rec_len += fs->blocksize - *offset;
5997 *offset = fs->blocksize;
5998 } else {
5999 dirent->rec_len = fs->blocksize - *offset;
6000 dirent->name_len = 0;
6001 dirent->inode = 0;
6002 }
6003}
6004
6005static int check_dir_block(ext2_filsys fs,
6006 struct ext2_db_entry *db,
6007 void *priv_data)
6008{
6009 struct dir_info *subdir, *dir;
6010 struct dx_dir_info *dx_dir;
6011#ifdef ENABLE_HTREE
6012 struct dx_dirblock_info *dx_db = 0;
6013#endif
6014 struct ext2_dir_entry *dirent, *prev;
6015 ext2_dirhash_t hash;
6016 unsigned int offset = 0;
6017 int dir_modified = 0;
6018 int dot_state;
6019 blk_t block_nr = db->blk;
6020 ext2_ino_t ino = db->ino;
6021 __u16 links;
6022 struct check_dir_struct *cd;
6023 char *buf;
6024 e2fsck_t ctx;
6025 int problem;
6026 struct ext2_dx_root_info *root;
6027 struct ext2_dx_countlimit *limit;
6028 static dict_t de_dict;
6029 struct problem_context pctx;
6030 int dups_found = 0;
6031
6032 cd = (struct check_dir_struct *) priv_data;
6033 buf = cd->buf;
6034 ctx = cd->ctx;
6035
6036 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6037 return DIRENT_ABORT;
6038
6039 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
6040 return DIRENT_ABORT;
6041
6042
6043
6044
6045
6046 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
6047 return 0;
6048
6049 cd->pctx.ino = ino;
6050 cd->pctx.blk = block_nr;
6051 cd->pctx.blkcount = db->blockcnt;
6052 cd->pctx.ino2 = 0;
6053 cd->pctx.dirent = 0;
6054 cd->pctx.num = 0;
6055
6056 if (db->blk == 0) {
6057 if (allocate_dir_block(ctx, db, &cd->pctx))
6058 return 0;
6059 block_nr = db->blk;
6060 }
6061
6062 if (db->blockcnt)
6063 dot_state = 2;
6064 else
6065 dot_state = 0;
6066
6067 if (ctx->dirs_to_hash &&
6068 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
6069 dups_found++;
6070
6071 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
6072 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
6073 cd->pctx.errcode = 0;
6074 if (cd->pctx.errcode) {
6075 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
6076 ctx->flags |= E2F_FLAG_ABORT;
6077 return DIRENT_ABORT;
6078 }
6079 memset(buf, 0, fs->blocksize);
6080 }
6081#ifdef ENABLE_HTREE
6082 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
6083 if (dx_dir && dx_dir->numblocks) {
6084 if (db->blockcnt >= dx_dir->numblocks) {
6085 printf("XXX should never happen!!!\n");
6086 abort();
6087 }
6088 dx_db = &dx_dir->dx_block[db->blockcnt];
6089 dx_db->type = DX_DIRBLOCK_LEAF;
6090 dx_db->phys = block_nr;
6091 dx_db->min_hash = ~0;
6092 dx_db->max_hash = 0;
6093
6094 dirent = (struct ext2_dir_entry *) buf;
6095 limit = (struct ext2_dx_countlimit *) (buf+8);
6096 if (db->blockcnt == 0) {
6097 root = (struct ext2_dx_root_info *) (buf + 24);
6098 dx_db->type = DX_DIRBLOCK_ROOT;
6099 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
6100 if ((root->reserved_zero ||
6101 root->info_length < 8 ||
6102 root->indirect_levels > 1) &&
6103 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
6104 clear_htree(ctx, ino);
6105 dx_dir->numblocks = 0;
6106 dx_db = 0;
6107 }
6108 dx_dir->hashversion = root->hash_version;
6109 dx_dir->depth = root->indirect_levels + 1;
6110 } else if ((dirent->inode == 0) &&
6111 (dirent->rec_len == fs->blocksize) &&
6112 (dirent->name_len == 0) &&
6113 (ext2fs_le16_to_cpu(limit->limit) ==
6114 ((fs->blocksize-8) /
6115 sizeof(struct ext2_dx_entry))))
6116 dx_db->type = DX_DIRBLOCK_NODE;
6117 }
6118#endif
6119
6120 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
6121 prev = 0;
6122 do {
6123 problem = 0;
6124 dirent = (struct ext2_dir_entry *) (buf + offset);
6125 cd->pctx.dirent = dirent;
6126 cd->pctx.num = offset;
6127 if (((offset + dirent->rec_len) > fs->blocksize) ||
6128 (dirent->rec_len < 12) ||
6129 ((dirent->rec_len % 4) != 0) ||
6130 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
6131 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
6132 salvage_directory(fs, dirent, prev, &offset);
6133 dir_modified++;
6134 continue;
6135 } else
6136 goto abort_free_dict;
6137 }
6138 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
6139 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
6140 dirent->name_len = EXT2_NAME_LEN;
6141 dir_modified++;
6142 }
6143 }
6144
6145 if (dot_state == 0) {
6146 if (check_dot(ctx, dirent, ino, &cd->pctx))
6147 dir_modified++;
6148 } else if (dot_state == 1) {
6149 dir = e2fsck_get_dir_info(ctx, ino);
6150 if (!dir) {
6151 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
6152 goto abort_free_dict;
6153 }
6154 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
6155 dir_modified++;
6156 } else if (dirent->inode == ino) {
6157 problem = PR_2_LINK_DOT;
6158 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
6159 dirent->inode = 0;
6160 dir_modified++;
6161 goto next;
6162 }
6163 }
6164 if (!dirent->inode)
6165 goto next;
6166
6167
6168
6169
6170 if (((dirent->inode != EXT2_ROOT_INO) &&
6171 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
6172 (dirent->inode > fs->super->s_inodes_count)) {
6173 problem = PR_2_BAD_INO;
6174 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
6175 dirent->inode))) {
6176
6177
6178
6179 problem = PR_2_UNUSED_INODE;
6180 } else if ((dot_state > 1) &&
6181 ((dirent->name_len & 0xFF) == 1) &&
6182 (dirent->name[0] == '.')) {
6183
6184
6185
6186
6187
6188 problem = PR_2_DUP_DOT;
6189 } else if ((dot_state > 1) &&
6190 ((dirent->name_len & 0xFF) == 2) &&
6191 (dirent->name[0] == '.') &&
6192 (dirent->name[1] == '.')) {
6193
6194
6195
6196
6197
6198 problem = PR_2_DUP_DOT_DOT;
6199 } else if ((dot_state > 1) &&
6200 (dirent->inode == EXT2_ROOT_INO)) {
6201
6202
6203
6204
6205
6206
6207 problem = PR_2_LINK_ROOT;
6208 } else if ((dot_state > 1) &&
6209 (dirent->name_len & 0xFF) == 0) {
6210
6211
6212
6213 problem = PR_2_NULL_NAME;
6214 }
6215
6216 if (problem) {
6217 if (fix_problem(ctx, problem, &cd->pctx)) {
6218 dirent->inode = 0;
6219 dir_modified++;
6220 goto next;
6221 } else {
6222 ext2fs_unmark_valid(fs);
6223 if (problem == PR_2_BAD_INO)
6224 goto next;
6225 }
6226 }
6227
6228
6229
6230
6231
6232
6233
6234 if (ctx->inode_bad_map &&
6235 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
6236 dirent->inode)) {
6237 if (e2fsck_process_bad_inode(ctx, ino,
6238 dirent->inode,
6239 buf + fs->blocksize)) {
6240 dirent->inode = 0;
6241 dir_modified++;
6242 goto next;
6243 }
6244 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6245 return DIRENT_ABORT;
6246 }
6247
6248 if (check_name(ctx, dirent, &cd->pctx))
6249 dir_modified++;
6250
6251 if (check_filetype(ctx, dirent, &cd->pctx))
6252 dir_modified++;
6253
6254#ifdef ENABLE_HTREE
6255 if (dx_db) {
6256 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
6257 (dirent->name_len & 0xFF),
6258 fs->super->s_hash_seed, &hash, 0);
6259 if (hash < dx_db->min_hash)
6260 dx_db->min_hash = hash;
6261 if (hash > dx_db->max_hash)
6262 dx_db->max_hash = hash;
6263 }
6264#endif
6265
6266
6267
6268
6269
6270
6271
6272
6273 if ((dot_state > 1) &&
6274 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
6275 dirent->inode))) {
6276 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
6277 if (!subdir) {
6278 cd->pctx.ino = dirent->inode;
6279 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
6280 goto abort_free_dict;
6281 }
6282 if (subdir->parent) {
6283 cd->pctx.ino2 = subdir->parent;
6284 if (fix_problem(ctx, PR_2_LINK_DIR,
6285 &cd->pctx)) {
6286 dirent->inode = 0;
6287 dir_modified++;
6288 goto next;
6289 }
6290 cd->pctx.ino2 = 0;
6291 } else
6292 subdir->parent = ino;
6293 }
6294
6295 if (dups_found) {
6296 ;
6297 } else if (dict_lookup(&de_dict, dirent)) {
6298 clear_problem_context(&pctx);
6299 pctx.ino = ino;
6300 pctx.dirent = dirent;
6301 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
6302 if (!ctx->dirs_to_hash)
6303 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
6304 if (ctx->dirs_to_hash)
6305 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
6306 dups_found++;
6307 } else
6308 dict_alloc_insert(&de_dict, dirent, dirent);
6309
6310 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
6311 &links);
6312 if (links > 1)
6313 ctx->fs_links_count++;
6314 ctx->fs_total_count++;
6315 next:
6316 prev = dirent;
6317 offset += dirent->rec_len;
6318 dot_state++;
6319 } while (offset < fs->blocksize);
6320#ifdef ENABLE_HTREE
6321 if (dx_db) {
6322 cd->pctx.dir = cd->pctx.ino;
6323 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
6324 (dx_db->type == DX_DIRBLOCK_NODE))
6325 parse_int_node(fs, db, cd, dx_dir, buf);
6326 }
6327#endif
6328 if (offset != fs->blocksize) {
6329 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
6330 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
6331 dirent->rec_len = cd->pctx.num;
6332 dir_modified++;
6333 }
6334 }
6335 if (dir_modified) {
6336 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
6337 if (cd->pctx.errcode) {
6338 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
6339 &cd->pctx))
6340 goto abort_free_dict;
6341 }
6342 ext2fs_mark_changed(fs);
6343 }
6344 dict_free_nodes(&de_dict);
6345 return 0;
6346abort_free_dict:
6347 dict_free_nodes(&de_dict);
6348 ctx->flags |= E2F_FLAG_ABORT;
6349 return DIRENT_ABORT;
6350}
6351
6352
6353
6354
6355
6356static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr,
6357 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
6358 blk_t ref_block FSCK_ATTR((unused)),
6359 int ref_offset FSCK_ATTR((unused)),
6360 void *priv_data)
6361{
6362 e2fsck_t ctx = (e2fsck_t) priv_data;
6363
6364 if (HOLE_BLKADDR(*block_nr))
6365 return 0;
6366 if ((*block_nr < fs->super->s_first_data_block) ||
6367 (*block_nr >= fs->super->s_blocks_count))
6368 return 0;
6369 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
6370 ext2fs_block_alloc_stats(fs, *block_nr, -1);
6371 return 0;
6372}
6373
6374
6375
6376
6377static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
6378{
6379 ext2_filsys fs = ctx->fs;
6380 struct ext2_inode inode;
6381 struct problem_context pctx;
6382 __u32 count;
6383
6384 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
6385 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
6386 inode.i_links_count = 0;
6387 inode.i_dtime = time(NULL);
6388 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
6389 clear_problem_context(&pctx);
6390 pctx.ino = ino;
6391
6392
6393
6394
6395 e2fsck_read_bitmaps(ctx);
6396 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
6397 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
6398 if (ctx->inode_bad_map)
6399 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
6400 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
6401
6402 if (inode.i_file_acl &&
6403 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
6404 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
6405 block_buf, -1, &count);
6406 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
6407 pctx.errcode = 0;
6408 count = 1;
6409 }
6410 if (pctx.errcode) {
6411 pctx.blk = inode.i_file_acl;
6412 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
6413 ctx->flags |= E2F_FLAG_ABORT;
6414 return;
6415 }
6416 if (count == 0) {
6417 ext2fs_unmark_block_bitmap(ctx->block_found_map,
6418 inode.i_file_acl);
6419 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
6420 }
6421 inode.i_file_acl = 0;
6422 }
6423
6424 if (!ext2fs_inode_has_valid_blocks(&inode))
6425 return;
6426
6427 if (LINUX_S_ISREG(inode.i_mode) &&
6428 (inode.i_size_high || inode.i_size & 0x80000000UL))
6429 ctx->large_files--;
6430
6431 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
6432 deallocate_inode_block, ctx);
6433 if (pctx.errcode) {
6434 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
6435 ctx->flags |= E2F_FLAG_ABORT;
6436 return;
6437 }
6438}
6439
6440
6441
6442
6443static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
6444{
6445 struct ext2_inode inode;
6446
6447 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
6448 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
6449 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
6450 if (ctx->dirs_to_hash)
6451 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
6452}
6453
6454
6455static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
6456 ext2_ino_t ino, char *buf)
6457{
6458 ext2_filsys fs = ctx->fs;
6459 struct ext2_inode inode;
6460 int inode_modified = 0;
6461 int not_fixed = 0;
6462 unsigned char *frag, *fsize;
6463 struct problem_context pctx;
6464 int problem = 0;
6465
6466 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
6467
6468 clear_problem_context(&pctx);
6469 pctx.ino = ino;
6470 pctx.dir = dir;
6471 pctx.inode = &inode;
6472
6473 if (inode.i_file_acl &&
6474 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
6475 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
6476 inode.i_file_acl = 0;
6477#if BB_BIG_ENDIAN
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487 if (LINUX_S_ISLNK(inode.i_mode) &&
6488 (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
6489 (inode.i_blocks == fs->blocksize >> 9))
6490 inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
6491#endif
6492 inode_modified++;
6493 } else
6494 not_fixed++;
6495
6496 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
6497 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
6498 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
6499 !(LINUX_S_ISSOCK(inode.i_mode)))
6500 problem = PR_2_BAD_MODE;
6501 else if (LINUX_S_ISCHR(inode.i_mode)
6502 && !e2fsck_pass1_check_device_inode(fs, &inode))
6503 problem = PR_2_BAD_CHAR_DEV;
6504 else if (LINUX_S_ISBLK(inode.i_mode)
6505 && !e2fsck_pass1_check_device_inode(fs, &inode))
6506 problem = PR_2_BAD_BLOCK_DEV;
6507 else if (LINUX_S_ISFIFO(inode.i_mode)
6508 && !e2fsck_pass1_check_device_inode(fs, &inode))
6509 problem = PR_2_BAD_FIFO;
6510 else if (LINUX_S_ISSOCK(inode.i_mode)
6511 && !e2fsck_pass1_check_device_inode(fs, &inode))
6512 problem = PR_2_BAD_SOCKET;
6513 else if (LINUX_S_ISLNK(inode.i_mode)
6514 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
6515 problem = PR_2_INVALID_SYMLINK;
6516 }
6517
6518 if (problem) {
6519 if (fix_problem(ctx, problem, &pctx)) {
6520 deallocate_inode(ctx, ino, 0);
6521 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6522 return 0;
6523 return 1;
6524 } else
6525 not_fixed++;
6526 problem = 0;
6527 }
6528
6529 if (inode.i_faddr) {
6530 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
6531 inode.i_faddr = 0;
6532 inode_modified++;
6533 } else
6534 not_fixed++;
6535 }
6536
6537 switch (fs->super->s_creator_os) {
6538 case EXT2_OS_LINUX:
6539 frag = &inode.osd2.linux2.l_i_frag;
6540 fsize = &inode.osd2.linux2.l_i_fsize;
6541 break;
6542 case EXT2_OS_HURD:
6543 frag = &inode.osd2.hurd2.h_i_frag;
6544 fsize = &inode.osd2.hurd2.h_i_fsize;
6545 break;
6546 case EXT2_OS_MASIX:
6547 frag = &inode.osd2.masix2.m_i_frag;
6548 fsize = &inode.osd2.masix2.m_i_fsize;
6549 break;
6550 default:
6551 frag = fsize = 0;
6552 }
6553 if (frag && *frag) {
6554 pctx.num = *frag;
6555 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
6556 *frag = 0;
6557 inode_modified++;
6558 } else
6559 not_fixed++;
6560 pctx.num = 0;
6561 }
6562 if (fsize && *fsize) {
6563 pctx.num = *fsize;
6564 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
6565 *fsize = 0;
6566 inode_modified++;
6567 } else
6568 not_fixed++;
6569 pctx.num = 0;
6570 }
6571
6572 if (inode.i_file_acl &&
6573 ((inode.i_file_acl < fs->super->s_first_data_block) ||
6574 (inode.i_file_acl >= fs->super->s_blocks_count))) {
6575 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
6576 inode.i_file_acl = 0;
6577 inode_modified++;
6578 } else
6579 not_fixed++;
6580 }
6581 if (inode.i_dir_acl &&
6582 LINUX_S_ISDIR(inode.i_mode)) {
6583 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
6584 inode.i_dir_acl = 0;
6585 inode_modified++;
6586 } else
6587 not_fixed++;
6588 }
6589
6590 if (inode_modified)
6591 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
6592 if (!not_fixed)
6593 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
6594 return 0;
6595}
6596
6597
6598
6599
6600
6601
6602
6603
6604static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db,
6605 struct problem_context *pctx)
6606{
6607 ext2_filsys fs = ctx->fs;
6608 blk_t blk;
6609 char *block;
6610 struct ext2_inode inode;
6611
6612 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
6613 return 1;
6614
6615
6616
6617
6618
6619 e2fsck_read_bitmaps(ctx);
6620
6621
6622
6623
6624 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
6625 if (pctx->errcode) {
6626 pctx->str = "ext2fs_new_block";
6627 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
6628 return 1;
6629 }
6630 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
6631 ext2fs_mark_block_bitmap(fs->block_map, blk);
6632 ext2fs_mark_bb_dirty(fs);
6633
6634
6635
6636
6637 if (db->blockcnt)
6638 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
6639 else
6640 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
6641 EXT2_ROOT_INO, &block);
6642
6643 if (pctx->errcode) {
6644 pctx->str = "ext2fs_new_dir_block";
6645 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
6646 return 1;
6647 }
6648
6649 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
6650 ext2fs_free_mem(&block);
6651 if (pctx->errcode) {
6652 pctx->str = "ext2fs_write_dir_block";
6653 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
6654 return 1;
6655 }
6656
6657
6658
6659
6660 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
6661 inode.i_blocks += fs->blocksize / 512;
6662 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
6663 inode.i_size = (db->blockcnt+1) * fs->blocksize;
6664 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
6665
6666
6667
6668
6669 db->blk = blk;
6670 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
6671 0, update_dir_block, db);
6672 if (pctx->errcode) {
6673 pctx->str = "ext2fs_block_iterate";
6674 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
6675 return 1;
6676 }
6677
6678 return 0;
6679}
6680
6681
6682
6683
6684static int update_dir_block(ext2_filsys fs FSCK_ATTR((unused)),
6685 blk_t *block_nr,
6686 e2_blkcnt_t blockcnt,
6687 blk_t ref_block FSCK_ATTR((unused)),
6688 int ref_offset FSCK_ATTR((unused)),
6689 void *priv_data)
6690{
6691 struct ext2_db_entry *db;
6692
6693 db = (struct ext2_db_entry *) priv_data;
6694 if (db->blockcnt == (int) blockcnt) {
6695 *block_nr = db->blk;
6696 return BLOCK_CHANGED;
6697 }
6698 return 0;
6699}
6700
6701
6702
6703
6704
6705
6706
6707
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720
6721
6722
6723
6724
6725
6726
6727
6728
6729
6730static void check_root(e2fsck_t ctx);
6731static int check_directory(e2fsck_t ctx, struct dir_info *dir,
6732 struct problem_context *pctx);
6733static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
6734
6735static ext2fs_inode_bitmap inode_loop_detect;
6736static ext2fs_inode_bitmap inode_done_map;
6737
6738static void e2fsck_pass3(e2fsck_t ctx)
6739{
6740 ext2_filsys fs = ctx->fs;
6741 int i;
6742 struct problem_context pctx;
6743 struct dir_info *dir;
6744 unsigned long maxdirs, count;
6745
6746 clear_problem_context(&pctx);
6747
6748
6749
6750 if (!(ctx->options & E2F_OPT_PREEN))
6751 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
6752
6753
6754
6755
6756 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
6757 &inode_done_map);
6758 if (pctx.errcode) {
6759 pctx.num = 2;
6760 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
6761 ctx->flags |= E2F_FLAG_ABORT;
6762 goto abort_exit;
6763 }
6764 check_root(ctx);
6765 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6766 goto abort_exit;
6767
6768 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
6769
6770 maxdirs = e2fsck_get_num_dirinfo(ctx);
6771 count = 1;
6772
6773 if (ctx->progress)
6774 if ((ctx->progress)(ctx, 3, 0, maxdirs))
6775 goto abort_exit;
6776
6777 for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
6778 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6779 goto abort_exit;
6780 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
6781 goto abort_exit;
6782 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
6783 if (check_directory(ctx, dir, &pctx))
6784 goto abort_exit;
6785 }
6786
6787
6788
6789
6790 if ((ctx->flags & E2F_OPT_READONLY) == 0)
6791 e2fsck_get_lost_and_found(ctx, 1);
6792
6793
6794
6795
6796
6797 e2fsck_rehash_directories(ctx);
6798
6799abort_exit:
6800 e2fsck_free_dir_info(ctx);
6801 ext2fs_free_inode_bitmap(inode_loop_detect);
6802 inode_loop_detect = 0;
6803 ext2fs_free_inode_bitmap(inode_done_map);
6804 inode_done_map = 0;
6805}
6806
6807
6808
6809
6810
6811static void check_root(e2fsck_t ctx)
6812{
6813 ext2_filsys fs = ctx->fs;
6814 blk_t blk;
6815 struct ext2_inode inode;
6816 char * block;
6817 struct problem_context pctx;
6818
6819 clear_problem_context(&pctx);
6820
6821 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
6822
6823
6824
6825
6826
6827 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
6828 EXT2_ROOT_INO))) {
6829 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
6830 ctx->flags |= E2F_FLAG_ABORT;
6831 }
6832 return;
6833 }
6834
6835 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
6836 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
6837 ctx->flags |= E2F_FLAG_ABORT;
6838 return;
6839 }
6840
6841 e2fsck_read_bitmaps(ctx);
6842
6843
6844
6845
6846 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
6847 if (pctx.errcode) {
6848 pctx.str = "ext2fs_new_block";
6849 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
6850 ctx->flags |= E2F_FLAG_ABORT;
6851 return;
6852 }
6853 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
6854 ext2fs_mark_block_bitmap(fs->block_map, blk);
6855 ext2fs_mark_bb_dirty(fs);
6856
6857
6858
6859
6860 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
6861 &block);
6862 if (pctx.errcode) {
6863 pctx.str = "ext2fs_new_dir_block";
6864 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
6865 ctx->flags |= E2F_FLAG_ABORT;
6866 return;
6867 }
6868
6869 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
6870 if (pctx.errcode) {
6871 pctx.str = "ext2fs_write_dir_block";
6872 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
6873 ctx->flags |= E2F_FLAG_ABORT;
6874 return;
6875 }
6876 ext2fs_free_mem(&block);
6877
6878
6879
6880
6881 memset(&inode, 0, sizeof(inode));
6882 inode.i_mode = 040755;
6883 inode.i_size = fs->blocksize;
6884 inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL);
6885 inode.i_links_count = 2;
6886 inode.i_blocks = fs->blocksize / 512;
6887 inode.i_block[0] = blk;
6888
6889
6890
6891
6892 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
6893 if (pctx.errcode) {
6894 pctx.str = "ext2fs_write_inode";
6895 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
6896 ctx->flags |= E2F_FLAG_ABORT;
6897 return;
6898 }
6899
6900
6901
6902
6903 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
6904 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
6905 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
6906
6907 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
6908 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
6909 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
6910 ext2fs_mark_ib_dirty(fs);
6911}
6912
6913
6914
6915
6916
6917
6918
6919
6920
6921
6922
6923
6924
6925
6926
6927
6928
6929static int check_directory(e2fsck_t ctx, struct dir_info *dir,
6930 struct problem_context *pctx)
6931{
6932 ext2_filsys fs = ctx->fs;
6933 struct dir_info *p = dir;
6934 int loop_pass = 0, parent_count = 0;
6935
6936 if (!p)
6937 return 0;
6938
6939 while (1) {
6940
6941
6942
6943
6944
6945
6946
6947
6948
6949
6950 if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
6951 break;
6952
6953
6954
6955
6956
6957
6958 if (!p->parent ||
6959 (loop_pass &&
6960 (ext2fs_test_inode_bitmap(inode_loop_detect,
6961 p->parent)))) {
6962 pctx->ino = p->ino;
6963 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
6964 if (e2fsck_reconnect_file(ctx, pctx->ino))
6965 ext2fs_unmark_valid(fs);
6966 else {
6967 p = e2fsck_get_dir_info(ctx, pctx->ino);
6968 p->parent = ctx->lost_and_found;
6969 fix_dotdot(ctx, p, ctx->lost_and_found);
6970 }
6971 }
6972 break;
6973 }
6974 p = e2fsck_get_dir_info(ctx, p->parent);
6975 if (!p) {
6976 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
6977 return 0;
6978 }
6979 if (loop_pass) {
6980 ext2fs_mark_inode_bitmap(inode_loop_detect,
6981 p->ino);
6982 } else if (parent_count++ > 2048) {
6983
6984
6985
6986
6987
6988
6989 loop_pass = 1;
6990 if (inode_loop_detect)
6991 ext2fs_clear_inode_bitmap(inode_loop_detect);
6992 else {
6993 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
6994 if (pctx->errcode) {
6995 pctx->num = 1;
6996 fix_problem(ctx,
6997 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
6998 ctx->flags |= E2F_FLAG_ABORT;
6999 return -1;
7000 }
7001 }
7002 p = dir;
7003 }
7004 }
7005
7006
7007
7008
7009
7010 if (dir->parent != dir->dotdot) {
7011 pctx->ino = dir->ino;
7012 pctx->ino2 = dir->dotdot;
7013 pctx->dir = dir->parent;
7014 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
7015 fix_dotdot(ctx, dir, dir->parent);
7016 }
7017 return 0;
7018}
7019
7020
7021
7022
7023
7024ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
7025{
7026 ext2_filsys fs = ctx->fs;
7027 ext2_ino_t ino;
7028 blk_t blk;
7029 errcode_t retval;
7030 struct ext2_inode inode;
7031 char * block;
7032 static const char name[] = "lost+found";
7033 struct problem_context pctx;
7034 struct dir_info *dirinfo;
7035
7036 if (ctx->lost_and_found)
7037 return ctx->lost_and_found;
7038
7039 clear_problem_context(&pctx);
7040
7041 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
7042 sizeof(name)-1, 0, &ino);
7043 if (retval && !fix)
7044 return 0;
7045 if (!retval) {
7046 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
7047 ctx->lost_and_found = ino;
7048 return ino;
7049 }
7050
7051
7052 if (!fix)
7053 return 0;
7054 pctx.ino = ino;
7055 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
7056 return 0;
7057
7058
7059 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
7060 if (pctx.errcode) {
7061 pctx.str = "ext2fs_unlink";
7062 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
7063 return 0;
7064 }
7065 dirinfo = e2fsck_get_dir_info(ctx, ino);
7066 if (dirinfo)
7067 dirinfo->parent = 0;
7068 e2fsck_adjust_inode_count(ctx, ino, -1);
7069 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
7070 pctx.errcode = retval;
7071 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
7072 }
7073 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
7074 return 0;
7075
7076
7077
7078
7079
7080 e2fsck_read_bitmaps(ctx);
7081
7082
7083
7084
7085 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
7086 if (retval) {
7087 pctx.errcode = retval;
7088 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
7089 return 0;
7090 }
7091 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
7092 ext2fs_block_alloc_stats(fs, blk, +1);
7093
7094
7095
7096
7097 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
7098 ctx->inode_used_map, &ino);
7099 if (retval) {
7100 pctx.errcode = retval;
7101 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
7102 return 0;
7103 }
7104 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
7105 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
7106 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
7107
7108
7109
7110
7111 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
7112 if (retval) {
7113 pctx.errcode = retval;
7114 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
7115 return 0;
7116 }
7117
7118 retval = ext2fs_write_dir_block(fs, blk, block);
7119 ext2fs_free_mem(&block);
7120 if (retval) {
7121 pctx.errcode = retval;
7122 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
7123 return 0;
7124 }
7125
7126
7127
7128
7129 memset(&inode, 0, sizeof(inode));
7130 inode.i_mode = 040700;
7131 inode.i_size = fs->blocksize;
7132 inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL);
7133 inode.i_links_count = 2;
7134 inode.i_blocks = fs->blocksize / 512;
7135 inode.i_block[0] = blk;
7136
7137
7138
7139
7140 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
7141 if (pctx.errcode) {
7142 pctx.str = "ext2fs_write_inode";
7143 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
7144 return 0;
7145 }
7146
7147
7148
7149 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
7150 if (pctx.errcode) {
7151 pctx.str = "ext2fs_link";
7152 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
7153 return 0;
7154 }
7155
7156
7157
7158
7159 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
7160 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
7161 ext2fs_icount_store(ctx->inode_count, ino, 2);
7162 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
7163 ctx->lost_and_found = ino;
7164 return ino;
7165}
7166
7167
7168
7169
7170int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
7171{
7172 ext2_filsys fs = ctx->fs;
7173 errcode_t retval;
7174 char name[80];
7175 struct problem_context pctx;
7176 struct ext2_inode inode;
7177 int file_type = 0;
7178
7179 clear_problem_context(&pctx);
7180 pctx.ino = ino;
7181
7182 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
7183 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
7184 ctx->bad_lost_and_found++;
7185 }
7186 if (ctx->bad_lost_and_found) {
7187 fix_problem(ctx, PR_3_NO_LPF, &pctx);
7188 return 1;
7189 }
7190
7191 sprintf(name, "#%u", ino);
7192 if (ext2fs_read_inode(fs, ino, &inode) == 0)
7193 file_type = ext2_file_type(inode.i_mode);
7194 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
7195 if (retval == EXT2_ET_DIR_NO_SPACE) {
7196 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
7197 return 1;
7198 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
7199 1, 0);
7200 if (retval) {
7201 pctx.errcode = retval;
7202 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
7203 return 1;
7204 }
7205 retval = ext2fs_link(fs, ctx->lost_and_found, name,
7206 ino, file_type);
7207 }
7208 if (retval) {
7209 pctx.errcode = retval;
7210 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
7211 return 1;
7212 }
7213 e2fsck_adjust_inode_count(ctx, ino, 1);
7214
7215 return 0;
7216}
7217
7218
7219
7220
7221errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
7222{
7223 ext2_filsys fs = ctx->fs;
7224 errcode_t retval;
7225 struct ext2_inode inode;
7226
7227 if (!ino)
7228 return 0;
7229
7230 retval = ext2fs_read_inode(fs, ino, &inode);
7231 if (retval)
7232 return retval;
7233
7234 if (adj == 1) {
7235 ext2fs_icount_increment(ctx->inode_count, ino, 0);
7236 if (inode.i_links_count == (__u16) ~0)
7237 return 0;
7238 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
7239 inode.i_links_count++;
7240 } else if (adj == -1) {
7241 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
7242 if (inode.i_links_count == 0)
7243 return 0;
7244 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
7245 inode.i_links_count--;
7246 }
7247
7248 retval = ext2fs_write_inode(fs, ino, &inode);
7249 if (retval)
7250 return retval;
7251
7252 return 0;
7253}
7254
7255
7256
7257
7258struct fix_dotdot_struct {
7259 ext2_filsys fs;
7260 ext2_ino_t parent;
7261 int done;
7262 e2fsck_t ctx;
7263};
7264
7265static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
7266 int offset FSCK_ATTR((unused)),
7267 int blocksize FSCK_ATTR((unused)),
7268 char *buf FSCK_ATTR((unused)),
7269 void *priv_data)
7270{
7271 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
7272 errcode_t retval;
7273 struct problem_context pctx;
7274
7275 if ((dirent->name_len & 0xFF) != 2)
7276 return 0;
7277 if (strncmp(dirent->name, "..", 2))
7278 return 0;
7279
7280 clear_problem_context(&pctx);
7281
7282 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
7283 if (retval) {
7284 pctx.errcode = retval;
7285 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
7286 }
7287 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
7288 if (retval) {
7289 pctx.errcode = retval;
7290 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
7291 }
7292 dirent->inode = fp->parent;
7293
7294 fp->done++;
7295 return DIRENT_ABORT | DIRENT_CHANGED;
7296}
7297
7298static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
7299{
7300 ext2_filsys fs = ctx->fs;
7301 errcode_t retval;
7302 struct fix_dotdot_struct fp;
7303 struct problem_context pctx;
7304
7305 fp.fs = fs;
7306 fp.parent = parent;
7307 fp.done = 0;
7308 fp.ctx = ctx;
7309
7310 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
7311 0, fix_dotdot_proc, &fp);
7312 if (retval || !fp.done) {
7313 clear_problem_context(&pctx);
7314 pctx.ino = dir->ino;
7315 pctx.errcode = retval;
7316 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
7317 PR_3_FIX_PARENT_NOFIND, &pctx);
7318 ext2fs_unmark_valid(fs);
7319 }
7320 dir->dotdot = parent;
7321}
7322
7323
7324
7325
7326
7327
7328struct expand_dir_struct {
7329 int num;
7330 int guaranteed_size;
7331 int newblocks;
7332 int last_block;
7333 errcode_t err;
7334 e2fsck_t ctx;
7335};
7336
7337static int expand_dir_proc(ext2_filsys fs,
7338 blk_t *blocknr,
7339 e2_blkcnt_t blockcnt,
7340 blk_t ref_block FSCK_ATTR((unused)),
7341 int ref_offset FSCK_ATTR((unused)),
7342 void *priv_data)
7343{
7344 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
7345 blk_t new_blk;
7346 static blk_t last_blk = 0;
7347 char *block;
7348 errcode_t retval;
7349 e2fsck_t ctx;
7350
7351 ctx = es->ctx;
7352
7353 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
7354 return BLOCK_ABORT;
7355
7356 if (blockcnt > 0)
7357 es->last_block = blockcnt;
7358 if (*blocknr) {
7359 last_blk = *blocknr;
7360 return 0;
7361 }
7362 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
7363 &new_blk);
7364 if (retval) {
7365 es->err = retval;
7366 return BLOCK_ABORT;
7367 }
7368 if (blockcnt > 0) {
7369 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
7370 if (retval) {
7371 es->err = retval;
7372 return BLOCK_ABORT;
7373 }
7374 es->num--;
7375 retval = ext2fs_write_dir_block(fs, new_blk, block);
7376 } else {
7377 retval = ext2fs_get_mem(fs->blocksize, &block);
7378 if (retval) {
7379 es->err = retval;
7380 return BLOCK_ABORT;
7381 }
7382 memset(block, 0, fs->blocksize);
7383 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
7384 }
7385 if (retval) {
7386 es->err = retval;
7387 return BLOCK_ABORT;
7388 }
7389 ext2fs_free_mem(&block);
7390 *blocknr = new_blk;
7391 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
7392 ext2fs_block_alloc_stats(fs, new_blk, +1);
7393 es->newblocks++;
7394
7395 if (es->num == 0)
7396 return (BLOCK_CHANGED | BLOCK_ABORT);
7397 else
7398 return BLOCK_CHANGED;
7399}
7400
7401errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
7402 int num, int guaranteed_size)
7403{
7404 ext2_filsys fs = ctx->fs;
7405 errcode_t retval;
7406 struct expand_dir_struct es;
7407 struct ext2_inode inode;
7408
7409 if (!(fs->flags & EXT2_FLAG_RW))
7410 return EXT2_ET_RO_FILSYS;
7411
7412
7413
7414
7415
7416 e2fsck_read_bitmaps(ctx);
7417
7418 retval = ext2fs_check_directory(fs, dir);
7419 if (retval)
7420 return retval;
7421
7422 es.num = num;
7423 es.guaranteed_size = guaranteed_size;
7424 es.last_block = 0;
7425 es.err = 0;
7426 es.newblocks = 0;
7427 es.ctx = ctx;
7428
7429 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
7430 0, expand_dir_proc, &es);
7431
7432 if (es.err)
7433 return es.err;
7434
7435
7436
7437
7438 retval = ext2fs_read_inode(fs, dir, &inode);
7439 if (retval)
7440 return retval;
7441
7442 inode.i_size = (es.last_block + 1) * fs->blocksize;
7443 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
7444
7445 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
7446
7447 return 0;
7448}
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
7465{
7466 ext2_filsys fs = ctx->fs;
7467 struct ext2_inode inode;
7468 struct problem_context pctx;
7469
7470 e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
7471 clear_problem_context(&pctx);
7472 pctx.ino = i;
7473 pctx.inode = &inode;
7474
7475
7476
7477
7478
7479
7480
7481 if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
7482 LINUX_S_ISDIR(inode.i_mode))) {
7483 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
7484 ext2fs_icount_store(ctx->inode_link_info, i, 0);
7485 inode.i_links_count = 0;
7486 inode.i_dtime = time(NULL);
7487 e2fsck_write_inode(ctx, i, &inode,
7488 "disconnect_inode");
7489
7490
7491
7492 e2fsck_read_bitmaps(ctx);
7493 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
7494 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
7495 ext2fs_inode_alloc_stats2(fs, i, -1,
7496 LINUX_S_ISDIR(inode.i_mode));
7497 return 0;
7498 }
7499 }
7500
7501
7502
7503
7504 if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
7505 if (e2fsck_reconnect_file(ctx, i))
7506 ext2fs_unmark_valid(fs);
7507 } else {
7508
7509
7510
7511
7512
7513 ext2fs_unmark_valid(fs);
7514 return 1;
7515 }
7516 return 0;
7517}
7518
7519
7520static void e2fsck_pass4(e2fsck_t ctx)
7521{
7522 ext2_filsys fs = ctx->fs;
7523 ext2_ino_t i;
7524 struct ext2_inode inode;
7525 struct problem_context pctx;
7526 __u16 link_count, link_counted;
7527 char *buf = 0;
7528 int group, maxgroup;
7529
7530
7531
7532 clear_problem_context(&pctx);
7533
7534 if (!(ctx->options & E2F_OPT_PREEN))
7535 fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
7536
7537 group = 0;
7538 maxgroup = fs->group_desc_count;
7539 if (ctx->progress)
7540 if ((ctx->progress)(ctx, 4, 0, maxgroup))
7541 return;
7542
7543 for (i=1; i <= fs->super->s_inodes_count; i++) {
7544 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7545 return;
7546 if ((i % fs->super->s_inodes_per_group) == 0) {
7547 group++;
7548 if (ctx->progress)
7549 if ((ctx->progress)(ctx, 4, group, maxgroup))
7550 return;
7551 }
7552 if (i == EXT2_BAD_INO ||
7553 (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
7554 continue;
7555 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
7556 (ctx->inode_imagic_map &&
7557 ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)))
7558 continue;
7559 ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
7560 ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
7561 if (link_counted == 0) {
7562 if (!buf)
7563 buf = e2fsck_allocate_memory(ctx,
7564 fs->blocksize, "bad_inode buffer");
7565 if (e2fsck_process_bad_inode(ctx, 0, i, buf))
7566 continue;
7567 if (disconnect_inode(ctx, i))
7568 continue;
7569 ext2fs_icount_fetch(ctx->inode_link_info, i,
7570 &link_count);
7571 ext2fs_icount_fetch(ctx->inode_count, i,
7572 &link_counted);
7573 }
7574 if (link_counted != link_count) {
7575 e2fsck_read_inode(ctx, i, &inode, "pass4");
7576 pctx.ino = i;
7577 pctx.inode = &inode;
7578 if (link_count != inode.i_links_count) {
7579 pctx.num = link_count;
7580 fix_problem(ctx,
7581 PR_4_INCONSISTENT_COUNT, &pctx);
7582 }
7583 pctx.num = link_counted;
7584 if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
7585 inode.i_links_count = link_counted;
7586 e2fsck_write_inode(ctx, i, &inode, "pass4");
7587 }
7588 }
7589 }
7590 ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
7591 ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
7592 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
7593 ctx->inode_imagic_map = 0;
7594 ext2fs_free_mem(&buf);
7595}
7596
7597
7598
7599
7600
7601#define NO_BLK ((blk_t) -1)
7602
7603static void print_bitmap_problem(e2fsck_t ctx, int problem,
7604 struct problem_context *pctx)
7605{
7606 switch (problem) {
7607 case PR_5_BLOCK_UNUSED:
7608 if (pctx->blk == pctx->blk2)
7609 pctx->blk2 = 0;
7610 else
7611 problem = PR_5_BLOCK_RANGE_UNUSED;
7612 break;
7613 case PR_5_BLOCK_USED:
7614 if (pctx->blk == pctx->blk2)
7615 pctx->blk2 = 0;
7616 else
7617 problem = PR_5_BLOCK_RANGE_USED;
7618 break;
7619 case PR_5_INODE_UNUSED:
7620 if (pctx->ino == pctx->ino2)
7621 pctx->ino2 = 0;
7622 else
7623 problem = PR_5_INODE_RANGE_UNUSED;
7624 break;
7625 case PR_5_INODE_USED:
7626 if (pctx->ino == pctx->ino2)
7627 pctx->ino2 = 0;
7628 else
7629 problem = PR_5_INODE_RANGE_USED;
7630 break;
7631 }
7632 fix_problem(ctx, problem, pctx);
7633 pctx->blk = pctx->blk2 = NO_BLK;
7634 pctx->ino = pctx->ino2 = 0;
7635}
7636
7637static void check_block_bitmaps(e2fsck_t ctx)
7638{
7639 ext2_filsys fs = ctx->fs;
7640 blk_t i;
7641 int *free_array;
7642 int group = 0;
7643 unsigned int blocks = 0;
7644 unsigned int free_blocks = 0;
7645 int group_free = 0;
7646 int actual, bitmap;
7647 struct problem_context pctx;
7648 int problem, save_problem, fixit, had_problem;
7649 errcode_t retval;
7650
7651 clear_problem_context(&pctx);
7652 free_array = (int *) e2fsck_allocate_memory(ctx,
7653 fs->group_desc_count * sizeof(int), "free block count array");
7654
7655 if ((fs->super->s_first_data_block <
7656 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
7657 (fs->super->s_blocks_count-1 >
7658 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
7659 pctx.num = 1;
7660 pctx.blk = fs->super->s_first_data_block;
7661 pctx.blk2 = fs->super->s_blocks_count -1;
7662 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
7663 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
7664 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
7665
7666 ctx->flags |= E2F_FLAG_ABORT;
7667 return;
7668 }
7669
7670 if ((fs->super->s_first_data_block <
7671 ext2fs_get_block_bitmap_start(fs->block_map)) ||
7672 (fs->super->s_blocks_count-1 >
7673 ext2fs_get_block_bitmap_end(fs->block_map))) {
7674 pctx.num = 2;
7675 pctx.blk = fs->super->s_first_data_block;
7676 pctx.blk2 = fs->super->s_blocks_count -1;
7677 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
7678 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
7679 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
7680
7681 ctx->flags |= E2F_FLAG_ABORT;
7682 return;
7683 }
7684
7685redo_counts:
7686 had_problem = 0;
7687 save_problem = 0;
7688 pctx.blk = pctx.blk2 = NO_BLK;
7689 for (i = fs->super->s_first_data_block;
7690 i < fs->super->s_blocks_count;
7691 i++) {
7692 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
7693 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
7694
7695 if (actual == bitmap)
7696 goto do_counts;
7697
7698 if (!actual && bitmap) {
7699
7700
7701
7702 problem = PR_5_BLOCK_UNUSED;
7703 } else {
7704
7705
7706
7707 problem = PR_5_BLOCK_USED;
7708 }
7709 if (pctx.blk == NO_BLK) {
7710 pctx.blk = pctx.blk2 = i;
7711 save_problem = problem;
7712 } else {
7713 if ((problem == save_problem) &&
7714 (pctx.blk2 == i-1))
7715 pctx.blk2++;
7716 else {
7717 print_bitmap_problem(ctx, save_problem, &pctx);
7718 pctx.blk = pctx.blk2 = i;
7719 save_problem = problem;
7720 }
7721 }
7722 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
7723 had_problem++;
7724
7725 do_counts:
7726 if (!bitmap) {
7727 group_free++;
7728 free_blocks++;
7729 }
7730 blocks ++;
7731 if ((blocks == fs->super->s_blocks_per_group) ||
7732 (i == fs->super->s_blocks_count-1)) {
7733 free_array[group] = group_free;
7734 group ++;
7735 blocks = 0;
7736 group_free = 0;
7737 if (ctx->progress)
7738 if ((ctx->progress)(ctx, 5, group,
7739 fs->group_desc_count*2))
7740 return;
7741 }
7742 }
7743 if (pctx.blk != NO_BLK)
7744 print_bitmap_problem(ctx, save_problem, &pctx);
7745 if (had_problem)
7746 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
7747 else
7748 fixit = -1;
7749 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
7750
7751 if (fixit == 1) {
7752 ext2fs_free_block_bitmap(fs->block_map);
7753 retval = ext2fs_copy_bitmap(ctx->block_found_map,
7754 &fs->block_map);
7755 if (retval) {
7756 clear_problem_context(&pctx);
7757 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
7758 ctx->flags |= E2F_FLAG_ABORT;
7759 return;
7760 }
7761 ext2fs_set_bitmap_padding(fs->block_map);
7762 ext2fs_mark_bb_dirty(fs);
7763
7764
7765 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
7766 memset(free_array, 0, fs->group_desc_count * sizeof(int));
7767 goto redo_counts;
7768 } else if (fixit == 0)
7769 ext2fs_unmark_valid(fs);
7770
7771 for (i = 0; i < fs->group_desc_count; i++) {
7772 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
7773 pctx.group = i;
7774 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
7775 pctx.blk2 = free_array[i];
7776
7777 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
7778 &pctx)) {
7779 fs->group_desc[i].bg_free_blocks_count =
7780 free_array[i];
7781 ext2fs_mark_super_dirty(fs);
7782 } else
7783 ext2fs_unmark_valid(fs);
7784 }
7785 }
7786 if (free_blocks != fs->super->s_free_blocks_count) {
7787 pctx.group = 0;
7788 pctx.blk = fs->super->s_free_blocks_count;
7789 pctx.blk2 = free_blocks;
7790
7791 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
7792 fs->super->s_free_blocks_count = free_blocks;
7793 ext2fs_mark_super_dirty(fs);
7794 } else
7795 ext2fs_unmark_valid(fs);
7796 }
7797 ext2fs_free_mem(&free_array);
7798}
7799
7800static void check_inode_bitmaps(e2fsck_t ctx)
7801{
7802 ext2_filsys fs = ctx->fs;
7803 ext2_ino_t i;
7804 unsigned int free_inodes = 0;
7805 int group_free = 0;
7806 int dirs_count = 0;
7807 int group = 0;
7808 unsigned int inodes = 0;
7809 int *free_array;
7810 int *dir_array;
7811 int actual, bitmap;
7812 errcode_t retval;
7813 struct problem_context pctx;
7814 int problem, save_problem, fixit, had_problem;
7815
7816 clear_problem_context(&pctx);
7817 free_array = (int *) e2fsck_allocate_memory(ctx,
7818 fs->group_desc_count * sizeof(int), "free inode count array");
7819
7820 dir_array = (int *) e2fsck_allocate_memory(ctx,
7821 fs->group_desc_count * sizeof(int), "directory count array");
7822
7823 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
7824 (fs->super->s_inodes_count >
7825 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
7826 pctx.num = 3;
7827 pctx.blk = 1;
7828 pctx.blk2 = fs->super->s_inodes_count;
7829 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
7830 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
7831 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
7832
7833 ctx->flags |= E2F_FLAG_ABORT;
7834 return;
7835 }
7836 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
7837 (fs->super->s_inodes_count >
7838 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
7839 pctx.num = 4;
7840 pctx.blk = 1;
7841 pctx.blk2 = fs->super->s_inodes_count;
7842 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
7843 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
7844 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
7845
7846 ctx->flags |= E2F_FLAG_ABORT;
7847 return;
7848 }
7849
7850redo_counts:
7851 had_problem = 0;
7852 save_problem = 0;
7853 pctx.ino = pctx.ino2 = 0;
7854 for (i = 1; i <= fs->super->s_inodes_count; i++) {
7855 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
7856 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
7857
7858 if (actual == bitmap)
7859 goto do_counts;
7860
7861 if (!actual && bitmap) {
7862
7863
7864
7865 problem = PR_5_INODE_UNUSED;
7866 } else {
7867
7868
7869
7870 problem = PR_5_INODE_USED;
7871 }
7872 if (pctx.ino == 0) {
7873 pctx.ino = pctx.ino2 = i;
7874 save_problem = problem;
7875 } else {
7876 if ((problem == save_problem) &&
7877 (pctx.ino2 == i-1))
7878 pctx.ino2++;
7879 else {
7880 print_bitmap_problem(ctx, save_problem, &pctx);
7881 pctx.ino = pctx.ino2 = i;
7882 save_problem = problem;
7883 }
7884 }
7885 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
7886 had_problem++;
7887
7888do_counts:
7889 if (!bitmap) {
7890 group_free++;
7891 free_inodes++;
7892 } else {
7893 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
7894 dirs_count++;
7895 }
7896 inodes++;
7897 if ((inodes == fs->super->s_inodes_per_group) ||
7898 (i == fs->super->s_inodes_count)) {
7899 free_array[group] = group_free;
7900 dir_array[group] = dirs_count;
7901 group ++;
7902 inodes = 0;
7903 group_free = 0;
7904 dirs_count = 0;
7905 if (ctx->progress)
7906 if ((ctx->progress)(ctx, 5,
7907 group + fs->group_desc_count,
7908 fs->group_desc_count*2))
7909 return;
7910 }
7911 }
7912 if (pctx.ino)
7913 print_bitmap_problem(ctx, save_problem, &pctx);
7914
7915 if (had_problem)
7916 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
7917 else
7918 fixit = -1;
7919 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
7920
7921 if (fixit == 1) {
7922 ext2fs_free_inode_bitmap(fs->inode_map);
7923 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
7924 &fs->inode_map);
7925 if (retval) {
7926 clear_problem_context(&pctx);
7927 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
7928 ctx->flags |= E2F_FLAG_ABORT;
7929 return;
7930 }
7931 ext2fs_set_bitmap_padding(fs->inode_map);
7932 ext2fs_mark_ib_dirty(fs);
7933
7934
7935 inodes = 0; free_inodes = 0; group_free = 0;
7936 dirs_count = 0; group = 0;
7937 memset(free_array, 0, fs->group_desc_count * sizeof(int));
7938 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
7939 goto redo_counts;
7940 } else if (fixit == 0)
7941 ext2fs_unmark_valid(fs);
7942
7943 for (i = 0; i < fs->group_desc_count; i++) {
7944 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
7945 pctx.group = i;
7946 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
7947 pctx.ino2 = free_array[i];
7948 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
7949 &pctx)) {
7950 fs->group_desc[i].bg_free_inodes_count =
7951 free_array[i];
7952 ext2fs_mark_super_dirty(fs);
7953 } else
7954 ext2fs_unmark_valid(fs);
7955 }
7956 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
7957 pctx.group = i;
7958 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
7959 pctx.ino2 = dir_array[i];
7960
7961 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
7962 &pctx)) {
7963 fs->group_desc[i].bg_used_dirs_count =
7964 dir_array[i];
7965 ext2fs_mark_super_dirty(fs);
7966 } else
7967 ext2fs_unmark_valid(fs);
7968 }
7969 }
7970 if (free_inodes != fs->super->s_free_inodes_count) {
7971 pctx.group = -1;
7972 pctx.ino = fs->super->s_free_inodes_count;
7973 pctx.ino2 = free_inodes;
7974
7975 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
7976 fs->super->s_free_inodes_count = free_inodes;
7977 ext2fs_mark_super_dirty(fs);
7978 } else
7979 ext2fs_unmark_valid(fs);
7980 }
7981 ext2fs_free_mem(&free_array);
7982 ext2fs_free_mem(&dir_array);
7983}
7984
7985static void check_inode_end(e2fsck_t ctx)
7986{
7987 ext2_filsys fs = ctx->fs;
7988 ext2_ino_t end, save_inodes_count, i;
7989 struct problem_context pctx;
7990
7991 clear_problem_context(&pctx);
7992
7993 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
7994 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
7995 &save_inodes_count);
7996 if (pctx.errcode) {
7997 pctx.num = 1;
7998 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
7999 ctx->flags |= E2F_FLAG_ABORT;
8000 return;
8001 }
8002 if (save_inodes_count == end)
8003 return;
8004
8005 for (i = save_inodes_count + 1; i <= end; i++) {
8006 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
8007 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
8008 for (i = save_inodes_count + 1; i <= end; i++)
8009 ext2fs_mark_inode_bitmap(fs->inode_map,
8010 i);
8011 ext2fs_mark_ib_dirty(fs);
8012 } else
8013 ext2fs_unmark_valid(fs);
8014 break;
8015 }
8016 }
8017
8018 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
8019 save_inodes_count, 0);
8020 if (pctx.errcode) {
8021 pctx.num = 2;
8022 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8023 ctx->flags |= E2F_FLAG_ABORT;
8024 return;
8025 }
8026}
8027
8028static void check_block_end(e2fsck_t ctx)
8029{
8030 ext2_filsys fs = ctx->fs;
8031 blk_t end, save_blocks_count, i;
8032 struct problem_context pctx;
8033
8034 clear_problem_context(&pctx);
8035
8036 end = fs->block_map->start +
8037 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
8038 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
8039 &save_blocks_count);
8040 if (pctx.errcode) {
8041 pctx.num = 3;
8042 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8043 ctx->flags |= E2F_FLAG_ABORT;
8044 return;
8045 }
8046 if (save_blocks_count == end)
8047 return;
8048
8049 for (i = save_blocks_count + 1; i <= end; i++) {
8050 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
8051 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
8052 for (i = save_blocks_count + 1; i <= end; i++)
8053 ext2fs_mark_block_bitmap(fs->block_map,
8054 i);
8055 ext2fs_mark_bb_dirty(fs);
8056 } else
8057 ext2fs_unmark_valid(fs);
8058 break;
8059 }
8060 }
8061
8062 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
8063 save_blocks_count, 0);
8064 if (pctx.errcode) {
8065 pctx.num = 4;
8066 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8067 ctx->flags |= E2F_FLAG_ABORT;
8068 return;
8069 }
8070}
8071
8072static void e2fsck_pass5(e2fsck_t ctx)
8073{
8074 struct problem_context pctx;
8075
8076
8077
8078 clear_problem_context(&pctx);
8079
8080 if (!(ctx->options & E2F_OPT_PREEN))
8081 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
8082
8083 if (ctx->progress)
8084 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
8085 return;
8086
8087 e2fsck_read_bitmaps(ctx);
8088
8089 check_block_bitmaps(ctx);
8090 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8091 return;
8092 check_inode_bitmaps(ctx);
8093 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8094 return;
8095 check_inode_end(ctx);
8096 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8097 return;
8098 check_block_end(ctx);
8099 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8100 return;
8101
8102 ext2fs_free_inode_bitmap(ctx->inode_used_map);
8103 ctx->inode_used_map = 0;
8104 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
8105 ctx->inode_dir_map = 0;
8106 ext2fs_free_block_bitmap(ctx->block_found_map);
8107 ctx->block_found_map = 0;
8108}
8109
8110
8111
8112
8113
8114#define PR_PREEN_OK 0x000001
8115#define PR_NO_OK 0x000002
8116#define PR_NO_DEFAULT 0x000004
8117#define PR_MSG_ONLY 0x000008
8118
8119
8120
8121#define PR_FATAL 0x001000
8122#define PR_AFTER_CODE 0x002000
8123
8124#define PR_PREEN_NOMSG 0x004000
8125#define PR_NOCOLLATE 0x008000
8126#define PR_NO_NOMSG 0x010000
8127#define PR_PREEN_NO 0x020000
8128#define PR_PREEN_NOHDR 0x040000
8129
8130
8131#define PROMPT_NONE 0
8132#define PROMPT_FIX 1
8133#define PROMPT_CLEAR 2
8134#define PROMPT_RELOCATE 3
8135#define PROMPT_ALLOCATE 4
8136#define PROMPT_EXPAND 5
8137#define PROMPT_CONNECT 6
8138#define PROMPT_CREATE 7
8139#define PROMPT_SALVAGE 8
8140#define PROMPT_TRUNCATE 9
8141#define PROMPT_CLEAR_INODE 10
8142#define PROMPT_ABORT 11
8143#define PROMPT_SPLIT 12
8144#define PROMPT_CONTINUE 13
8145#define PROMPT_CLONE 14
8146#define PROMPT_DELETE 15
8147#define PROMPT_SUPPRESS 16
8148#define PROMPT_UNLINK 17
8149#define PROMPT_CLEAR_HTREE 18
8150#define PROMPT_RECREATE 19
8151#define PROMPT_NULL 20
8152
8153struct e2fsck_problem {
8154 problem_t e2p_code;
8155 const char * e2p_description;
8156 char prompt;
8157 int flags;
8158 problem_t second_code;
8159};
8160
8161struct latch_descr {
8162 int latch_code;
8163 problem_t question;
8164 problem_t end_message;
8165 int flags;
8166};
8167
8168
8169
8170
8171
8172static const char *const prompt[] = {
8173 N_("(no prompt)"),
8174 N_("Fix"),
8175 N_("Clear"),
8176 N_("Relocate"),
8177 N_("Allocate"),
8178 N_("Expand"),
8179 N_("Connect to /lost+found"),
8180 N_("Create"),
8181 N_("Salvage"),
8182 N_("Truncate"),
8183 N_("Clear inode"),
8184 N_("Abort"),
8185 N_("Split"),
8186 N_("Continue"),
8187 N_("Clone multiply-claimed blocks"),
8188 N_("Delete file"),
8189 N_("Suppress messages"),
8190 N_("Unlink"),
8191 N_("Clear HTree index"),
8192 N_("Recreate"),
8193 "",
8194};
8195
8196
8197
8198
8199
8200static const char *const preen_msg[] = {
8201 N_("(NONE)"),
8202 N_("FIXED"),
8203 N_("CLEARED"),
8204 N_("RELOCATED"),
8205 N_("ALLOCATED"),
8206 N_("EXPANDED"),
8207 N_("RECONNECTED"),
8208 N_("CREATED"),
8209 N_("SALVAGED"),
8210 N_("TRUNCATED"),
8211 N_("INODE CLEARED"),
8212 N_("ABORTED"),
8213 N_("SPLIT"),
8214 N_("CONTINUING"),
8215 N_("MULTIPLY-CLAIMED BLOCKS CLONED"),
8216 N_("FILE DELETED"),
8217 N_("SUPPRESSED"),
8218 N_("UNLINKED"),
8219 N_("HTREE INDEX CLEARED"),
8220 N_("WILL RECREATE"),
8221 "",
8222};
8223
8224static const struct e2fsck_problem problem_table[] = {
8225
8226
8227
8228
8229 { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
8230 PROMPT_RELOCATE, PR_LATCH_RELOC },
8231
8232
8233 { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
8234 PROMPT_RELOCATE, PR_LATCH_RELOC },
8235
8236
8237 { PR_0_ITABLE_NOT_GROUP,
8238 N_("@i table for @g %g is not in @g. (@b %b)\n"
8239 "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
8240 PROMPT_RELOCATE, PR_LATCH_RELOC },
8241
8242
8243 { PR_0_SB_CORRUPT,
8244 N_("\nThe @S could not be read or does not describe a correct ext2\n"
8245 "@f. If the @v is valid and it really contains an ext2\n"
8246 "@f (and not swap or ufs or something else), then the @S\n"
8247 "is corrupt, and you might try running e2fsck with an alternate @S:\n"
8248 " e2fsck -b %S <@v>\n\n"),
8249 PROMPT_NONE, PR_FATAL },
8250
8251
8252 { PR_0_FS_SIZE_WRONG,
8253 N_("The @f size (according to the @S) is %b @bs\n"
8254 "The physical size of the @v is %c @bs\n"
8255 "Either the @S or the partition table is likely to be corrupt!\n"),
8256 PROMPT_ABORT, 0 },
8257
8258
8259 { PR_0_NO_FRAGMENTS,
8260 N_("@S @b_size = %b, fragsize = %c.\n"
8261 "This version of e2fsck does not support fragment sizes different\n"
8262 "from the @b size.\n"),
8263 PROMPT_NONE, PR_FATAL },
8264
8265
8266 { PR_0_BLOCKS_PER_GROUP,
8267 N_("@S @bs_per_group = %b, should have been %c\n"),
8268 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
8269
8270
8271 { PR_0_FIRST_DATA_BLOCK,
8272 N_("@S first_data_@b = %b, should have been %c\n"),
8273 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
8274
8275
8276 { PR_0_ADD_UUID,
8277 N_("@f did not have a UUID; generating one.\n\n"),
8278 PROMPT_NONE, 0 },
8279
8280
8281 { PR_0_RELOCATE_HINT,
8282 N_("Note: if several inode or block bitmap blocks or part\n"
8283 "of the inode table require relocation, you may wish to try\n"
8284 "running e2fsck with the '-b %S' option first. The problem\n"
8285 "may lie only with the primary block group descriptors, and\n"
8286 "the backup block group descriptors may be OK.\n\n"),
8287 PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
8288
8289
8290 { PR_0_MISC_CORRUPT_SUPER,
8291 N_("Corruption found in @S. (%s = %N).\n"),
8292 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
8293
8294
8295 { PR_0_GETSIZE_ERROR,
8296 N_("Error determining size of the physical @v: %m\n"),
8297 PROMPT_NONE, PR_FATAL },
8298
8299
8300 { PR_0_INODE_COUNT_WRONG,
8301 N_("@i count in @S is %i, @s %j.\n"),
8302 PROMPT_FIX, 0 },
8303
8304 { PR_0_HURD_CLEAR_FILETYPE,
8305 N_("The Hurd does not support the filetype feature.\n"),
8306 PROMPT_CLEAR, 0 },
8307
8308
8309 { PR_0_JOURNAL_BAD_INODE,
8310 N_("@S has an @n ext3 @j (@i %i).\n"),
8311 PROMPT_CLEAR, PR_PREEN_OK },
8312
8313
8314 { PR_0_JOURNAL_UNSUPP_MULTIFS,
8315 N_("External @j has multiple @f users (unsupported).\n"),
8316 PROMPT_NONE, PR_FATAL },
8317
8318
8319 { PR_0_CANT_FIND_JOURNAL,
8320 N_("Can't find external @j\n"),
8321 PROMPT_NONE, PR_FATAL },
8322
8323
8324 { PR_0_EXT_JOURNAL_BAD_SUPER,
8325 N_("External @j has bad @S\n"),
8326 PROMPT_NONE, PR_FATAL },
8327
8328
8329 { PR_0_JOURNAL_BAD_UUID,
8330 N_("External @j does not support this @f\n"),
8331 PROMPT_NONE, PR_FATAL },
8332
8333
8334 { PR_0_JOURNAL_UNSUPP_SUPER,
8335 N_("Ext3 @j @S is unknown type %N (unsupported).\n"
8336 "It is likely that your copy of e2fsck is old and/or doesn't "
8337 "support this @j format.\n"
8338 "It is also possible the @j @S is corrupt.\n"),
8339 PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
8340
8341
8342 { PR_0_JOURNAL_BAD_SUPER,
8343 N_("Ext3 @j @S is corrupt.\n"),
8344 PROMPT_FIX, PR_PREEN_OK },
8345
8346
8347 { PR_0_JOURNAL_HAS_JOURNAL,
8348 N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
8349 PROMPT_CLEAR, PR_PREEN_OK },
8350
8351
8352 { PR_0_JOURNAL_RECOVER_SET,
8353 N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
8354 PROMPT_CLEAR, PR_PREEN_OK },
8355
8356
8357 { PR_0_JOURNAL_RECOVERY_CLEAR,
8358 N_("ext3 recovery flag is clear, but @j has data.\n"),
8359 PROMPT_NONE, 0 },
8360
8361
8362 { PR_0_JOURNAL_RESET_JOURNAL,
8363 N_("Clear @j"),
8364 PROMPT_NULL, PR_PREEN_NOMSG },
8365
8366
8367 { PR_0_JOURNAL_RUN,
8368 N_("Run @j anyway"),
8369 PROMPT_NULL, 0 },
8370
8371
8372 { PR_0_JOURNAL_RUN_DEFAULT,
8373 N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
8374 PROMPT_NONE, 0 },
8375
8376
8377 { PR_0_ORPHAN_CLEAR_INODE,
8378 N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
8379 PROMPT_NONE, 0 },
8380
8381
8382 { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
8383 N_("@I @b #%B (%b) found in @o @i %i.\n"),
8384 PROMPT_NONE, 0 },
8385
8386
8387 { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
8388 N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
8389 PROMPT_NONE, 0 },
8390
8391
8392 { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
8393 N_("@I @o @i %i in @S.\n"),
8394 PROMPT_NONE, 0 },
8395
8396
8397 { PR_0_ORPHAN_ILLEGAL_INODE,
8398 N_("@I @i %i in @o @i list.\n"),
8399 PROMPT_NONE, 0 },
8400
8401
8402 { PR_0_FS_REV_LEVEL,
8403 N_("@f has feature flag(s) set, but is a revision 0 @f. "),
8404 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
8405
8406
8407 { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
8408 N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
8409 PROMPT_ABORT, 0 },
8410
8411
8412 { PR_0_JOURNAL_UNSUPP_INCOMPAT,
8413 N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
8414 PROMPT_ABORT, 0 },
8415
8416
8417 { PR_0_JOURNAL_UNSUPP_VERSION,
8418 N_("@j version not supported by this e2fsck.\n"),
8419 PROMPT_ABORT, 0 },
8420
8421
8422 { PR_0_MOVE_JOURNAL,
8423 N_("Moving @j from /%s to hidden @i.\n\n"),
8424 PROMPT_NONE, 0 },
8425
8426
8427 { PR_0_ERR_MOVE_JOURNAL,
8428 N_("Error moving @j: %m\n\n"),
8429 PROMPT_NONE, 0 },
8430
8431
8432 { PR_0_CLEAR_V2_JOURNAL,
8433 N_("Found @n V2 @j @S fields (from V1 @j).\n"
8434 "Clearing fields beyond the V1 @j @S...\n\n"),
8435 PROMPT_NONE, 0 },
8436
8437
8438 { PR_0_BACKUP_JNL,
8439 N_("Backing up @j @i @b information.\n\n"),
8440 PROMPT_NONE, 0 },
8441
8442
8443 { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
8444 N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
8445 "is %N; @s zero. "),
8446 PROMPT_FIX, 0 },
8447
8448
8449 { PR_0_CLEAR_RESIZE_INODE,
8450 N_("Resize_@i not enabled, but the resize @i is non-zero. "),
8451 PROMPT_CLEAR, 0 },
8452
8453
8454 { PR_0_RESIZE_INODE_INVALID,
8455 N_("Resize @i not valid. "),
8456 PROMPT_RECREATE, 0 },
8457
8458
8459
8460
8461 { PR_1_PASS_HEADER,
8462 N_("Pass 1: Checking @is, @bs, and sizes\n"),
8463 PROMPT_NONE, 0 },
8464
8465
8466 { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
8467 PROMPT_CLEAR, 0 },
8468
8469
8470 { PR_1_ROOT_DTIME,
8471 N_("@r has dtime set (probably due to old mke2fs). "),
8472 PROMPT_FIX, PR_PREEN_OK },
8473
8474
8475 { PR_1_RESERVED_BAD_MODE,
8476 N_("Reserved @i %i (%Q) has @n mode. "),
8477 PROMPT_CLEAR, PR_PREEN_OK },
8478
8479
8480 { PR_1_ZERO_DTIME,
8481 N_("@D @i %i has zero dtime. "),
8482 PROMPT_FIX, PR_PREEN_OK },
8483
8484
8485 { PR_1_SET_DTIME,
8486 N_("@i %i is in use, but has dtime set. "),
8487 PROMPT_FIX, PR_PREEN_OK },
8488
8489
8490 { PR_1_ZERO_LENGTH_DIR,
8491 N_("@i %i is a @z @d. "),
8492 PROMPT_CLEAR, PR_PREEN_OK },
8493
8494
8495 { PR_1_BB_CONFLICT,
8496 N_("@g %g's @b @B at %b @C.\n"),
8497 PROMPT_RELOCATE, 0 },
8498
8499
8500 { PR_1_IB_CONFLICT,
8501 N_("@g %g's @i @B at %b @C.\n"),
8502 PROMPT_RELOCATE, 0 },
8503
8504
8505 { PR_1_ITABLE_CONFLICT,
8506 N_("@g %g's @i table at %b @C.\n"),
8507 PROMPT_RELOCATE, 0 },
8508
8509
8510 { PR_1_BB_BAD_BLOCK,
8511 N_("@g %g's @b @B (%b) is bad. "),
8512 PROMPT_RELOCATE, 0 },
8513
8514
8515 { PR_1_IB_BAD_BLOCK,
8516 N_("@g %g's @i @B (%b) is bad. "),
8517 PROMPT_RELOCATE, 0 },
8518
8519
8520 { PR_1_BAD_I_SIZE,
8521 N_("@i %i, i_size is %Is, @s %N. "),
8522 PROMPT_FIX, PR_PREEN_OK },
8523
8524
8525 { PR_1_BAD_I_BLOCKS,
8526 N_("@i %i, i_@bs is %Ib, @s %N. "),
8527 PROMPT_FIX, PR_PREEN_OK },
8528
8529
8530 { PR_1_ILLEGAL_BLOCK_NUM,
8531 N_("@I @b #%B (%b) in @i %i. "),
8532 PROMPT_CLEAR, PR_LATCH_BLOCK },
8533
8534
8535 { PR_1_BLOCK_OVERLAPS_METADATA,
8536 N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
8537 PROMPT_CLEAR, PR_LATCH_BLOCK },
8538
8539
8540 { PR_1_INODE_BLOCK_LATCH,
8541 N_("@i %i has illegal @b(s). "),
8542 PROMPT_CLEAR, 0 },
8543
8544
8545 { PR_1_TOO_MANY_BAD_BLOCKS,
8546 N_("Too many illegal @bs in @i %i.\n"),
8547 PROMPT_CLEAR_INODE, PR_NO_OK },
8548
8549
8550 { PR_1_BB_ILLEGAL_BLOCK_NUM,
8551 N_("@I @b #%B (%b) in bad @b @i. "),
8552 PROMPT_CLEAR, PR_LATCH_BBLOCK },
8553
8554
8555 { PR_1_INODE_BBLOCK_LATCH,
8556 N_("Bad @b @i has illegal @b(s). "),
8557 PROMPT_CLEAR, 0 },
8558
8559
8560 { PR_1_DUP_BLOCKS_PREENSTOP,
8561 N_("Duplicate or bad @b in use!\n"),
8562 PROMPT_NONE, 0 },
8563
8564
8565 { PR_1_BBINODE_BAD_METABLOCK,
8566 N_("Bad @b %b used as bad @b @i indirect @b. "),
8567 PROMPT_CLEAR, PR_LATCH_BBLOCK },
8568
8569
8570 { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
8571 N_("\nThe bad @b @i has probably been corrupted. You probably\n"
8572 "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
8573 "in the @f.\n"),
8574 PROMPT_CONTINUE, PR_PREEN_NOMSG },
8575
8576
8577 { PR_1_BAD_PRIMARY_BLOCK,
8578 N_("\nIf the @b is really bad, the @f cannot be fixed.\n"),
8579 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
8580
8581
8582 { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
8583 N_("You can remove this @b from the bad @b list and hope\n"
8584 "that the @b is really OK. But there are no guarantees.\n\n"),
8585 PROMPT_CLEAR, PR_PREEN_NOMSG },
8586
8587
8588 { PR_1_BAD_PRIMARY_SUPERBLOCK,
8589 N_("The primary @S (%b) is on the bad @b list.\n"),
8590 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
8591
8592
8593 { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
8594 N_("Block %b in the primary @g descriptors "
8595 "is on the bad @b list\n"),
8596 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
8597
8598
8599 { PR_1_BAD_SUPERBLOCK,
8600 N_("Warning: Group %g's @S (%b) is bad.\n"),
8601 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
8602
8603
8604 { PR_1_BAD_GROUP_DESCRIPTORS,
8605 N_("Warning: Group %g's copy of the @g descriptors has a bad "
8606 "@b (%b).\n"),
8607 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
8608
8609
8610 { PR_1_PROGERR_CLAIMED_BLOCK,
8611 N_("Programming error? @b #%b claimed for no reason in "
8612 "process_bad_@b.\n"),
8613 PROMPT_NONE, PR_PREEN_OK },
8614
8615
8616 { PR_1_RELOC_BLOCK_ALLOCATE,
8617 N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
8618 PROMPT_NONE, PR_PREEN_OK },
8619
8620
8621 { PR_1_RELOC_MEMORY_ALLOCATE,
8622 N_("@A @b buffer for relocating %s\n"),
8623 PROMPT_NONE, PR_PREEN_OK },
8624
8625
8626 { PR_1_RELOC_FROM_TO,
8627 N_("Relocating @g %g's %s from %b to %c...\n"),
8628 PROMPT_NONE, PR_PREEN_OK },
8629
8630
8631 { PR_1_RELOC_TO,
8632 N_("Relocating @g %g's %s to %c...\n"),
8633 PROMPT_NONE, PR_PREEN_OK },
8634
8635
8636 { PR_1_RELOC_READ_ERR,
8637 N_("Warning: could not read @b %b of %s: %m\n"),
8638 PROMPT_NONE, PR_PREEN_OK },
8639
8640
8641 { PR_1_RELOC_WRITE_ERR,
8642 N_("Warning: could not write @b %b for %s: %m\n"),
8643 PROMPT_NONE, PR_PREEN_OK },
8644
8645
8646 { PR_1_ALLOCATE_IBITMAP_ERROR,
8647 N_("@A @i @B (%N): %m\n"),
8648 PROMPT_NONE, PR_FATAL },
8649
8650
8651 { PR_1_ALLOCATE_BBITMAP_ERROR,
8652 N_("@A @b @B (%N): %m\n"),
8653 PROMPT_NONE, PR_FATAL },
8654
8655
8656 { PR_1_ALLOCATE_ICOUNT,
8657 N_("@A icount link information: %m\n"),
8658 PROMPT_NONE, PR_FATAL },
8659
8660
8661 { PR_1_ALLOCATE_DBCOUNT,
8662 N_("@A @d @b array: %m\n"),
8663 PROMPT_NONE, PR_FATAL },
8664
8665
8666 { PR_1_ISCAN_ERROR,
8667 N_("Error while scanning @is (%i): %m\n"),
8668 PROMPT_NONE, PR_FATAL },
8669
8670
8671 { PR_1_BLOCK_ITERATE,
8672 N_("Error while iterating over @bs in @i %i: %m\n"),
8673 PROMPT_NONE, PR_FATAL },
8674
8675
8676 { PR_1_ICOUNT_STORE,
8677 N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
8678 PROMPT_NONE, PR_FATAL },
8679
8680
8681 { PR_1_ADD_DBLOCK,
8682 N_("Error storing @d @b information "
8683 "(@i=%i, @b=%b, num=%N): %m\n"),
8684 PROMPT_NONE, PR_FATAL },
8685
8686
8687 { PR_1_READ_INODE,
8688 N_("Error reading @i %i: %m\n"),
8689 PROMPT_NONE, PR_FATAL },
8690
8691
8692 { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
8693
8694
8695 { PR_1_SET_IMAGIC,
8696 N_("@i %i has imagic flag set. "),
8697 PROMPT_CLEAR, 0 },
8698
8699
8700 { PR_1_SET_IMMUTABLE,
8701 N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
8702 "or append-only flag set. "),
8703 PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
8704
8705
8706 { PR_1_COMPR_SET,
8707 N_("@i %i has @cion flag set on @f without @cion support. "),
8708 PROMPT_CLEAR, 0 },
8709
8710
8711 { PR_1_SET_NONZSIZE,
8712 N_("Special (@v/socket/fifo) @i %i has non-zero size. "),
8713 PROMPT_FIX, PR_PREEN_OK },
8714
8715
8716 { PR_1_FS_REV_LEVEL,
8717 N_("@f has feature flag(s) set, but is a revision 0 @f. "),
8718 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
8719
8720
8721 { PR_1_JOURNAL_INODE_NOT_CLEAR,
8722 N_("@j @i is not in use, but contains data. "),
8723 PROMPT_CLEAR, PR_PREEN_OK },
8724
8725
8726 { PR_1_JOURNAL_BAD_MODE,
8727 N_("@j is not regular file. "),
8728 PROMPT_FIX, PR_PREEN_OK },
8729
8730
8731 { PR_1_LOW_DTIME,
8732 N_("@i %i was part of the @o @i list. "),
8733 PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
8734
8735
8736
8737 { PR_1_ORPHAN_LIST_REFUGEES,
8738 N_("@is that were part of a corrupted orphan linked list found. "),
8739 PROMPT_FIX, 0 },
8740
8741
8742 { PR_1_ALLOCATE_REFCOUNT,
8743 N_("@A refcount structure (%N): %m\n"),
8744 PROMPT_NONE, PR_FATAL },
8745
8746
8747 { PR_1_READ_EA_BLOCK,
8748 N_("Error reading @a @b %b for @i %i. "),
8749 PROMPT_CLEAR, 0 },
8750
8751
8752 { PR_1_BAD_EA_BLOCK,
8753 N_("@i %i has a bad @a @b %b. "),
8754 PROMPT_CLEAR, 0 },
8755
8756
8757 { PR_1_EXTATTR_READ_ABORT,
8758 N_("Error reading @a @b %b (%m). "),
8759 PROMPT_ABORT, 0 },
8760
8761
8762 { PR_1_EXTATTR_REFCOUNT,
8763 N_("@a @b %b has reference count %B, @s %N. "),
8764 PROMPT_FIX, 0 },
8765
8766
8767 { PR_1_EXTATTR_WRITE,
8768 N_("Error writing @a @b %b (%m). "),
8769 PROMPT_ABORT, 0 },
8770
8771
8772 { PR_1_EA_MULTI_BLOCK,
8773 N_("@a @b %b has h_@bs > 1. "),
8774 PROMPT_CLEAR, 0},
8775
8776
8777 { PR_1_EA_ALLOC_REGION,
8778 N_("@A @a @b %b. "),
8779 PROMPT_ABORT, 0},
8780
8781
8782 { PR_1_EA_ALLOC_COLLISION,
8783 N_("@a @b %b is corrupt (allocation collision). "),
8784 PROMPT_CLEAR, 0},
8785
8786
8787 { PR_1_EA_BAD_NAME,
8788 N_("@a @b %b is corrupt (@n name). "),
8789 PROMPT_CLEAR, 0},
8790
8791
8792 { PR_1_EA_BAD_VALUE,
8793 N_("@a @b %b is corrupt (@n value). "),
8794 PROMPT_CLEAR, 0},
8795
8796
8797 { PR_1_INODE_TOOBIG,
8798 N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
8799
8800
8801 { PR_1_TOOBIG_DIR,
8802 N_("@b #%B (%b) causes @d to be too big. "),
8803 PROMPT_CLEAR, PR_LATCH_TOOBIG },
8804
8805
8806 { PR_1_TOOBIG_REG,
8807 N_("@b #%B (%b) causes file to be too big. "),
8808 PROMPT_CLEAR, PR_LATCH_TOOBIG },
8809
8810
8811 { PR_1_TOOBIG_SYMLINK,
8812 N_("@b #%B (%b) causes symlink to be too big. "),
8813 PROMPT_CLEAR, PR_LATCH_TOOBIG },
8814
8815
8816 { PR_1_HTREE_SET,
8817 N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
8818 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8819
8820
8821 { PR_1_HTREE_NODIR,
8822 N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
8823 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8824
8825
8826 { PR_1_HTREE_BADROOT,
8827 N_("@h %i has an @n root node.\n"),
8828 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8829
8830
8831 { PR_1_HTREE_HASHV,
8832 N_("@h %i has an unsupported hash version (%N)\n"),
8833 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8834
8835
8836 { PR_1_HTREE_INCOMPAT,
8837 N_("@h %i uses an incompatible htree root node flag.\n"),
8838 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8839
8840
8841 { PR_1_HTREE_DEPTH,
8842 N_("@h %i has a tree depth (%N) which is too big\n"),
8843 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8844
8845
8846 { PR_1_BB_FS_BLOCK,
8847 N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
8848 "@f metadata. "),
8849 PROMPT_CLEAR, PR_LATCH_BBLOCK },
8850
8851
8852 { PR_1_RESIZE_INODE_CREATE,
8853 N_("Resize @i (re)creation failed: %m."),
8854 PROMPT_ABORT, 0 },
8855
8856
8857 { PR_1_EXTRA_ISIZE,
8858 N_("@i %i has a extra size (%IS) which is @n\n"),
8859 PROMPT_FIX, PR_PREEN_OK },
8860
8861
8862 { PR_1_ATTR_NAME_LEN,
8863 N_("@a in @i %i has a namelen (%N) which is @n\n"),
8864 PROMPT_CLEAR, PR_PREEN_OK },
8865
8866
8867 { PR_1_ATTR_VALUE_SIZE,
8868 N_("@a in @i %i has a value size (%N) which is @n\n"),
8869 PROMPT_CLEAR, PR_PREEN_OK },
8870
8871
8872 { PR_1_ATTR_VALUE_OFFSET,
8873 N_("@a in @i %i has a value offset (%N) which is @n\n"),
8874 PROMPT_CLEAR, PR_PREEN_OK },
8875
8876
8877 { PR_1_ATTR_VALUE_BLOCK,
8878 N_("@a in @i %i has a value @b (%N) which is @n (must be 0)\n"),
8879 PROMPT_CLEAR, PR_PREEN_OK },
8880
8881
8882 { PR_1_ATTR_HASH,
8883 N_("@a in @i %i has a hash (%N) which is @n (must be 0)\n"),
8884 PROMPT_CLEAR, PR_PREEN_OK },
8885
8886
8887
8888
8889 { PR_1B_PASS_HEADER,
8890 N_("\nRunning additional passes to resolve @bs claimed by more than one @i...\n"
8891 "Pass 1B: Rescanning for @m @bs\n"),
8892 PROMPT_NONE, 0 },
8893
8894
8895 { PR_1B_DUP_BLOCK_HEADER,
8896 N_("@m @b(s) in @i %i:"),
8897 PROMPT_NONE, 0 },
8898
8899
8900 { PR_1B_DUP_BLOCK,
8901 " %b",
8902 PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
8903
8904
8905 { PR_1B_DUP_BLOCK_END,
8906 "\n",
8907 PROMPT_NONE, PR_PREEN_NOHDR },
8908
8909
8910 { PR_1B_ISCAN_ERROR,
8911 N_("Error while scanning inodes (%i): %m\n"),
8912 PROMPT_NONE, PR_FATAL },
8913
8914
8915 { PR_1B_ALLOCATE_IBITMAP_ERROR,
8916 N_("@A @i @B (@i_dup_map): %m\n"),
8917 PROMPT_NONE, PR_FATAL },
8918
8919
8920 { PR_1B_BLOCK_ITERATE,
8921 N_("Error while iterating over @bs in @i %i (%s): %m\n"),
8922 PROMPT_NONE, 0 },
8923
8924
8925 { PR_1B_ADJ_EA_REFCOUNT,
8926 N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
8927 PROMPT_NONE, 0 },
8928
8929
8930
8931 { PR_1C_PASS_HEADER,
8932 N_("Pass 1C: Scanning directories for @is with @m @bs.\n"),
8933 PROMPT_NONE, 0 },
8934
8935
8936
8937 { PR_1D_PASS_HEADER,
8938 N_("Pass 1D: Reconciling @m @bs\n"),
8939 PROMPT_NONE, 0 },
8940
8941
8942 { PR_1D_DUP_FILE,
8943 N_("File %Q (@i #%i, mod time %IM)\n"
8944 " has %B @m @b(s), shared with %N file(s):\n"),
8945 PROMPT_NONE, 0 },
8946
8947
8948 { PR_1D_DUP_FILE_LIST,
8949 N_("\t%Q (@i #%i, mod time %IM)\n"),
8950 PROMPT_NONE, 0 },
8951
8952
8953 { PR_1D_SHARE_METADATA,
8954 N_("\t<@f metadata>\n"),
8955 PROMPT_NONE, 0 },
8956
8957
8958 { PR_1D_NUM_DUP_INODES,
8959 N_("(There are %N @is containing @m @bs.)\n\n"),
8960 PROMPT_NONE, 0 },
8961
8962
8963 { PR_1D_DUP_BLOCKS_DEALT,
8964 N_("@m @bs already reassigned or cloned.\n\n"),
8965 PROMPT_NONE, 0 },
8966
8967
8968 { PR_1D_CLONE_QUESTION,
8969 "", PROMPT_CLONE, PR_NO_OK },
8970
8971
8972 { PR_1D_DELETE_QUESTION,
8973 "", PROMPT_DELETE, 0 },
8974
8975
8976 { PR_1D_CLONE_ERROR,
8977 N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
8978
8979
8980
8981
8982 { PR_2_PASS_HEADER,
8983 N_("Pass 2: Checking @d structure\n"),
8984 PROMPT_NONE, 0 },
8985
8986
8987 { PR_2_BAD_INODE_DOT,
8988 N_("@n @i number for '.' in @d @i %i.\n"),
8989 PROMPT_FIX, 0 },
8990
8991
8992 { PR_2_BAD_INO,
8993 N_("@E has @n @i #: %Di.\n"),
8994 PROMPT_CLEAR, 0 },
8995
8996
8997 { PR_2_UNUSED_INODE,
8998 N_("@E has @D/unused @i %Di. "),
8999 PROMPT_CLEAR, PR_PREEN_OK },
9000
9001
9002 { PR_2_LINK_DOT,
9003 N_("@E @L to '.' "),
9004 PROMPT_CLEAR, 0 },
9005
9006
9007 { PR_2_BB_INODE,
9008 N_("@E points to @i (%Di) located in a bad @b.\n"),
9009 PROMPT_CLEAR, 0 },
9010
9011
9012 { PR_2_LINK_DIR,
9013 N_("@E @L to @d %P (%Di).\n"),
9014 PROMPT_CLEAR, 0 },
9015
9016
9017 { PR_2_LINK_ROOT,
9018 N_("@E @L to the @r.\n"),
9019 PROMPT_CLEAR, 0 },
9020
9021
9022 { PR_2_BAD_NAME,
9023 N_("@E has illegal characters in its name.\n"),
9024 PROMPT_FIX, 0 },
9025
9026
9027 { PR_2_MISSING_DOT,
9028 N_("Missing '.' in @d @i %i.\n"),
9029 PROMPT_FIX, 0 },
9030
9031
9032 { PR_2_MISSING_DOT_DOT,
9033 N_("Missing '..' in @d @i %i.\n"),
9034 PROMPT_FIX, 0 },
9035
9036
9037 { PR_2_1ST_NOT_DOT,
9038 N_("First @e '%Dn' (@i=%Di) in @d @i %i (%p) @s '.'\n"),
9039 PROMPT_FIX, 0 },
9040
9041
9042 { PR_2_2ND_NOT_DOT_DOT,
9043 N_("Second @e '%Dn' (@i=%Di) in @d @i %i @s '..'\n"),
9044 PROMPT_FIX, 0 },
9045
9046
9047 { PR_2_FADDR_ZERO,
9048 N_("i_faddr @F %IF, @s zero.\n"),
9049 PROMPT_CLEAR, 0 },
9050
9051
9052 { PR_2_FILE_ACL_ZERO,
9053 N_("i_file_acl @F %If, @s zero.\n"),
9054 PROMPT_CLEAR, 0 },
9055
9056
9057 { PR_2_DIR_ACL_ZERO,
9058 N_("i_dir_acl @F %Id, @s zero.\n"),
9059 PROMPT_CLEAR, 0 },
9060
9061
9062 { PR_2_FRAG_ZERO,
9063 N_("i_frag @F %N, @s zero.\n"),
9064 PROMPT_CLEAR, 0 },
9065
9066
9067 { PR_2_FSIZE_ZERO,
9068 N_("i_fsize @F %N, @s zero.\n"),
9069 PROMPT_CLEAR, 0 },
9070
9071
9072 { PR_2_BAD_MODE,
9073 N_("@i %i (%Q) has @n mode (%Im).\n"),
9074 PROMPT_CLEAR, 0 },
9075
9076
9077 { PR_2_DIR_CORRUPTED,
9078 N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
9079 PROMPT_SALVAGE, 0 },
9080
9081
9082 { PR_2_FILENAME_LONG,
9083 N_("@d @i %i, @b %B, offset %N: filename too long\n"),
9084 PROMPT_TRUNCATE, 0 },
9085
9086
9087 { PR_2_DIRECTORY_HOLE,
9088 N_("@d @i %i has an unallocated @b #%B. "),
9089 PROMPT_ALLOCATE, 0 },
9090
9091
9092 { PR_2_DOT_NULL_TERM,
9093 N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
9094 PROMPT_FIX, 0 },
9095
9096
9097 { PR_2_DOT_DOT_NULL_TERM,
9098 N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
9099 PROMPT_FIX, 0 },
9100
9101
9102 { PR_2_BAD_CHAR_DEV,
9103 N_("@i %i (%Q) is an @I character @v.\n"),
9104 PROMPT_CLEAR, 0 },
9105
9106
9107 { PR_2_BAD_BLOCK_DEV,
9108 N_("@i %i (%Q) is an @I @b @v.\n"),
9109 PROMPT_CLEAR, 0 },
9110
9111
9112 { PR_2_DUP_DOT,
9113 N_("@E is duplicate '.' @e.\n"),
9114 PROMPT_FIX, 0 },
9115
9116
9117 { PR_2_DUP_DOT_DOT,
9118 N_("@E is duplicate '..' @e.\n"),
9119 PROMPT_FIX, 0 },
9120
9121
9122 { PR_2_NO_DIRINFO,
9123 N_("Internal error: cannot find dir_info for %i.\n"),
9124 PROMPT_NONE, PR_FATAL },
9125
9126
9127 { PR_2_FINAL_RECLEN,
9128 N_("@E has rec_len of %Dr, @s %N.\n"),
9129 PROMPT_FIX, 0 },
9130
9131
9132 { PR_2_ALLOCATE_ICOUNT,
9133 N_("@A icount structure: %m\n"),
9134 PROMPT_NONE, PR_FATAL },
9135
9136
9137 { PR_2_DBLIST_ITERATE,
9138 N_("Error iterating over @d @bs: %m\n"),
9139 PROMPT_NONE, PR_FATAL },
9140
9141
9142 { PR_2_READ_DIRBLOCK,
9143 N_("Error reading @d @b %b (@i %i): %m\n"),
9144 PROMPT_CONTINUE, 0 },
9145
9146
9147 { PR_2_WRITE_DIRBLOCK,
9148 N_("Error writing @d @b %b (@i %i): %m\n"),
9149 PROMPT_CONTINUE, 0 },
9150
9151
9152 { PR_2_ALLOC_DIRBOCK,
9153 N_("@A new @d @b for @i %i (%s): %m\n"),
9154 PROMPT_NONE, 0 },
9155
9156
9157 { PR_2_DEALLOC_INODE,
9158 N_("Error deallocating @i %i: %m\n"),
9159 PROMPT_NONE, PR_FATAL },
9160
9161
9162 { PR_2_SPLIT_DOT,
9163 N_("@d @e for '.' is big. "),
9164 PROMPT_SPLIT, PR_NO_OK },
9165
9166
9167 { PR_2_BAD_FIFO,
9168 N_("@i %i (%Q) is an @I FIFO.\n"),
9169 PROMPT_CLEAR, 0 },
9170
9171
9172 { PR_2_BAD_SOCKET,
9173 N_("@i %i (%Q) is an @I socket.\n"),
9174 PROMPT_CLEAR, 0 },
9175
9176
9177 { PR_2_SET_FILETYPE,
9178 N_("Setting filetype for @E to %N.\n"),
9179 PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
9180
9181
9182 { PR_2_BAD_FILETYPE,
9183 N_("@E has an incorrect filetype (was %Dt, @s %N).\n"),
9184 PROMPT_FIX, 0 },
9185
9186
9187 { PR_2_CLEAR_FILETYPE,
9188 N_("@E has filetype set.\n"),
9189 PROMPT_CLEAR, PR_PREEN_OK },
9190
9191
9192 { PR_2_NULL_NAME,
9193 N_("@E has a @z name.\n"),
9194 PROMPT_CLEAR, 0 },
9195
9196
9197 { PR_2_INVALID_SYMLINK,
9198 N_("Symlink %Q (@i #%i) is @n.\n"),
9199 PROMPT_CLEAR, 0 },
9200
9201
9202 { PR_2_FILE_ACL_BAD,
9203 N_("@a @b @F @n (%If).\n"),
9204 PROMPT_CLEAR, 0 },
9205
9206
9207 { PR_2_FEATURE_LARGE_FILES,
9208 N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
9209 PROMPT_FIX, 0 },
9210
9211
9212 { PR_2_HTREE_NOTREF,
9213 N_("@p @h %d: node (%B) not referenced\n"),
9214 PROMPT_NONE, 0 },
9215
9216
9217 { PR_2_HTREE_DUPREF,
9218 N_("@p @h %d: node (%B) referenced twice\n"),
9219 PROMPT_NONE, 0 },
9220
9221
9222 { PR_2_HTREE_MIN_HASH,
9223 N_("@p @h %d: node (%B) has bad min hash\n"),
9224 PROMPT_NONE, 0 },
9225
9226
9227 { PR_2_HTREE_MAX_HASH,
9228 N_("@p @h %d: node (%B) has bad max hash\n"),
9229 PROMPT_NONE, 0 },
9230
9231
9232 { PR_2_HTREE_CLEAR,
9233 N_("@n @h %d (%q). "), PROMPT_CLEAR, 0 },
9234
9235
9236 { PR_2_HTREE_BADBLK,
9237 N_("@p @h %d (%q): bad @b number %b.\n"),
9238 PROMPT_CLEAR_HTREE, 0 },
9239
9240
9241 { PR_2_ADJ_EA_REFCOUNT,
9242 N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
9243 PROMPT_NONE, PR_FATAL },
9244
9245
9246 { PR_2_HTREE_BAD_ROOT,
9247 N_("@p @h %d: root node is @n\n"),
9248 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9249
9250
9251 { PR_2_HTREE_BAD_LIMIT,
9252 N_("@p @h %d: node (%B) has @n limit (%N)\n"),
9253 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9254
9255
9256 { PR_2_HTREE_BAD_COUNT,
9257 N_("@p @h %d: node (%B) has @n count (%N)\n"),
9258 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9259
9260
9261 { PR_2_HTREE_HASH_ORDER,
9262 N_("@p @h %d: node (%B) has an unordered hash table\n"),
9263 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9264
9265
9266 { PR_2_HTREE_BAD_DEPTH,
9267 N_("@p @h %d: node (%B) has @n depth\n"),
9268 PROMPT_NONE, 0 },
9269
9270
9271 { PR_2_DUPLICATE_DIRENT,
9272 N_("Duplicate @E found. "),
9273 PROMPT_CLEAR, 0 },
9274
9275
9276 { PR_2_NON_UNIQUE_FILE,
9277 N_("@E has a non-unique filename.\nRename to %s"),
9278 PROMPT_NULL, 0 },
9279
9280
9281 { PR_2_REPORT_DUP_DIRENT,
9282 N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
9283 PROMPT_NONE, 0 },
9284
9285
9286
9287
9288 { PR_3_PASS_HEADER,
9289 N_("Pass 3: Checking @d connectivity\n"),
9290 PROMPT_NONE, 0 },
9291
9292
9293 { PR_3_NO_ROOT_INODE,
9294 N_("@r not allocated. "),
9295 PROMPT_ALLOCATE, 0 },
9296
9297
9298 { PR_3_EXPAND_LF_DIR,
9299 N_("No room in @l @d. "),
9300 PROMPT_EXPAND, 0 },
9301
9302
9303 { PR_3_UNCONNECTED_DIR,
9304 N_("Unconnected @d @i %i (%p)\n"),
9305 PROMPT_CONNECT, 0 },
9306
9307
9308 { PR_3_NO_LF_DIR,
9309 N_("/@l not found. "),
9310 PROMPT_CREATE, PR_PREEN_OK },
9311
9312
9313 { PR_3_BAD_DOT_DOT,
9314 N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
9315 PROMPT_FIX, 0 },
9316
9317
9318 { PR_3_NO_LPF,
9319 N_("Bad or non-existent /@l. Cannot reconnect.\n"),
9320 PROMPT_NONE, 0 },
9321
9322
9323 { PR_3_CANT_EXPAND_LPF,
9324 N_("Could not expand /@l: %m\n"),
9325 PROMPT_NONE, 0 },
9326
9327
9328 { PR_3_CANT_RECONNECT,
9329 N_("Could not reconnect %i: %m\n"),
9330 PROMPT_NONE, 0 },
9331
9332
9333 { PR_3_ERR_FIND_LPF,
9334 N_("Error while trying to find /@l: %m\n"),
9335 PROMPT_NONE, 0 },
9336
9337
9338 { PR_3_ERR_LPF_NEW_BLOCK,
9339 N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
9340 PROMPT_NONE, 0 },
9341
9342
9343 { PR_3_ERR_LPF_NEW_INODE,
9344 N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
9345 PROMPT_NONE, 0 },
9346
9347
9348 { PR_3_ERR_LPF_NEW_DIR_BLOCK,
9349 N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
9350 PROMPT_NONE, 0 },
9351
9352
9353 { PR_3_ERR_LPF_WRITE_BLOCK,
9354 N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
9355 PROMPT_NONE, 0 },
9356
9357
9358 { PR_3_ADJUST_INODE,
9359 N_("Error while adjusting @i count on @i %i\n"),
9360 PROMPT_NONE, 0 },
9361
9362
9363 { PR_3_FIX_PARENT_ERR,
9364 N_("Couldn't fix parent of @i %i: %m\n\n"),
9365 PROMPT_NONE, 0 },
9366
9367
9368 { PR_3_FIX_PARENT_NOFIND,
9369 N_("Couldn't fix parent of @i %i: Couldn't find parent @d @e\n\n"),
9370 PROMPT_NONE, 0 },
9371
9372
9373 { PR_3_ALLOCATE_IBITMAP_ERROR,
9374 N_("@A @i @B (%N): %m\n"),
9375 PROMPT_NONE, PR_FATAL },
9376
9377
9378 { PR_3_CREATE_ROOT_ERROR,
9379 N_("Error creating root @d (%s): %m\n"),
9380 PROMPT_NONE, PR_FATAL },
9381
9382
9383 { PR_3_CREATE_LPF_ERROR,
9384 N_("Error creating /@l @d (%s): %m\n"),
9385 PROMPT_NONE, PR_FATAL },
9386
9387
9388 { PR_3_ROOT_NOT_DIR_ABORT,
9389 N_("@r is not a @d; aborting.\n"),
9390 PROMPT_NONE, PR_FATAL },
9391
9392
9393 { PR_3_NO_ROOT_INODE_ABORT,
9394 N_("can't proceed without a @r.\n"),
9395 PROMPT_NONE, PR_FATAL },
9396
9397
9398 { PR_3_NO_DIRINFO,
9399 N_("Internal error: cannot find dir_info for %i.\n"),
9400 PROMPT_NONE, PR_FATAL },
9401
9402
9403 { PR_3_LPF_NOTDIR,
9404 N_("/@l is not a @d (ino=%i)\n"),
9405 PROMPT_UNLINK, 0 },
9406
9407
9408
9409
9410 { PR_3A_PASS_HEADER,
9411 N_("Pass 3A: Optimizing directories\n"),
9412 PROMPT_NONE, PR_PREEN_NOMSG },
9413
9414
9415 { PR_3A_OPTIMIZE_ITER,
9416 N_("Failed to create dirs_to_hash iterator: %m"),
9417 PROMPT_NONE, 0 },
9418
9419
9420 { PR_3A_OPTIMIZE_DIR_ERR,
9421 N_("Failed to optimize directory %q (%d): %m"),
9422 PROMPT_NONE, 0 },
9423
9424
9425 { PR_3A_OPTIMIZE_DIR_HEADER,
9426 N_("Optimizing directories: "),
9427 PROMPT_NONE, PR_MSG_ONLY },
9428
9429
9430 { PR_3A_OPTIMIZE_DIR,
9431 " %d",
9432 PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
9433
9434
9435 { PR_3A_OPTIMIZE_DIR_END,
9436 "\n",
9437 PROMPT_NONE, PR_PREEN_NOHDR },
9438
9439
9440
9441
9442 { PR_4_PASS_HEADER,
9443 N_("Pass 4: Checking reference counts\n"),
9444 PROMPT_NONE, 0 },
9445
9446
9447 { PR_4_ZERO_LEN_INODE,
9448 N_("@u @z @i %i. "),
9449 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
9450
9451
9452 { PR_4_UNATTACHED_INODE,
9453 N_("@u @i %i\n"),
9454 PROMPT_CONNECT, 0 },
9455
9456
9457 { PR_4_BAD_REF_COUNT,
9458 N_("@i %i ref count is %Il, @s %N. "),
9459 PROMPT_FIX, PR_PREEN_OK },
9460
9461 { PR_4_INCONSISTENT_COUNT,
9462 N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
9463 "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
9464 "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
9465 "They @s the same!\n"),
9466 PROMPT_NONE, 0 },
9467
9468
9469
9470
9471 { PR_5_PASS_HEADER,
9472 N_("Pass 5: Checking @g summary information\n"),
9473 PROMPT_NONE, 0 },
9474
9475
9476 { PR_5_INODE_BMAP_PADDING,
9477 N_("Padding at end of @i @B is not set. "),
9478 PROMPT_FIX, PR_PREEN_OK },
9479
9480
9481 { PR_5_BLOCK_BMAP_PADDING,
9482 N_("Padding at end of @b @B is not set. "),
9483 PROMPT_FIX, PR_PREEN_OK },
9484
9485
9486 { PR_5_BLOCK_BITMAP_HEADER,
9487 N_("@b @B differences: "),
9488 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
9489
9490
9491 { PR_5_BLOCK_UNUSED,
9492 " -%b",
9493 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9494
9495
9496 { PR_5_BLOCK_USED,
9497 " +%b",
9498 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9499
9500
9501 { PR_5_BLOCK_BITMAP_END,
9502 "\n",
9503 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9504
9505
9506 { PR_5_INODE_BITMAP_HEADER,
9507 N_("@i @B differences: "),
9508 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
9509
9510
9511 { PR_5_INODE_UNUSED,
9512 " -%i",
9513 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9514
9515
9516 { PR_5_INODE_USED,
9517 " +%i",
9518 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9519
9520
9521 { PR_5_INODE_BITMAP_END,
9522 "\n",
9523 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9524
9525
9526 { PR_5_FREE_INODE_COUNT_GROUP,
9527 N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
9528 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9529
9530
9531 { PR_5_FREE_DIR_COUNT_GROUP,
9532 N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
9533 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9534
9535
9536 { PR_5_FREE_INODE_COUNT,
9537 N_("Free @is count wrong (%i, counted=%j).\n"),
9538 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9539
9540
9541 { PR_5_FREE_BLOCK_COUNT_GROUP,
9542 N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
9543 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9544
9545
9546 { PR_5_FREE_BLOCK_COUNT,
9547 N_("Free @bs count wrong (%b, counted=%c).\n"),
9548 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9549
9550
9551 { PR_5_BMAP_ENDPOINTS,
9552 N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
9553 "match calculated @B endpoints (%i, %j)\n"),
9554 PROMPT_NONE, PR_FATAL },
9555
9556
9557 { PR_5_FUDGE_BITMAP_ERROR,
9558 N_("Internal error: fudging end of bitmap (%N)\n"),
9559 PROMPT_NONE, PR_FATAL },
9560
9561
9562 { PR_5_COPY_IBITMAP_ERROR,
9563 N_("Error copying in replacement @i @B: %m\n"),
9564 PROMPT_NONE, PR_FATAL },
9565
9566
9567 { PR_5_COPY_BBITMAP_ERROR,
9568 N_("Error copying in replacement @b @B: %m\n"),
9569 PROMPT_NONE, PR_FATAL },
9570
9571
9572 { PR_5_BLOCK_RANGE_UNUSED,
9573 " -(%b--%c)",
9574 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9575
9576
9577 { PR_5_BLOCK_RANGE_USED,
9578 " +(%b--%c)",
9579 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9580
9581
9582 { PR_5_INODE_RANGE_UNUSED,
9583 " -(%i--%j)",
9584 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9585
9586
9587 { PR_5_INODE_RANGE_USED,
9588 " +(%i--%j)",
9589 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9590
9591 { 0 }
9592};
9593
9594
9595
9596
9597
9598
9599
9600static struct latch_descr pr_latch_info[] = {
9601 { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
9602 { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
9603 { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
9604 { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
9605 { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
9606 { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
9607 { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
9608 { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
9609 { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
9610 { -1, 0, 0 },
9611};
9612
9613static const struct e2fsck_problem *find_problem(problem_t code)
9614{
9615 int i;
9616
9617 for (i=0; problem_table[i].e2p_code; i++) {
9618 if (problem_table[i].e2p_code == code)
9619 return &problem_table[i];
9620 }
9621 return 0;
9622}
9623
9624static struct latch_descr *find_latch(int code)
9625{
9626 int i;
9627
9628 for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
9629 if (pr_latch_info[i].latch_code == code)
9630 return &pr_latch_info[i];
9631 }
9632 return 0;
9633}
9634
9635int end_problem_latch(e2fsck_t ctx, int mask)
9636{
9637 struct latch_descr *ldesc;
9638 struct problem_context pctx;
9639 int answer = -1;
9640
9641 ldesc = find_latch(mask);
9642 if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
9643 clear_problem_context(&pctx);
9644 answer = fix_problem(ctx, ldesc->end_message, &pctx);
9645 }
9646 ldesc->flags &= ~(PRL_VARIABLE);
9647 return answer;
9648}
9649
9650int set_latch_flags(int mask, int setflags, int clearflags)
9651{
9652 struct latch_descr *ldesc;
9653
9654 ldesc = find_latch(mask);
9655 if (!ldesc)
9656 return -1;
9657 ldesc->flags |= setflags;
9658 ldesc->flags &= ~clearflags;
9659 return 0;
9660}
9661
9662void clear_problem_context(struct problem_context *ctx)
9663{
9664 memset(ctx, 0, sizeof(struct problem_context));
9665 ctx->blkcount = -1;
9666 ctx->group = -1;
9667}
9668
9669int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
9670{
9671 ext2_filsys fs = ctx->fs;
9672 const struct e2fsck_problem *ptr;
9673 struct latch_descr *ldesc = 0;
9674 const char *message;
9675 int def_yn, answer, ans;
9676 int print_answer = 0;
9677 int suppress = 0;
9678
9679 ptr = find_problem(code);
9680 if (!ptr) {
9681 printf(_("Unhandled error code (0x%x)!\n"), code);
9682 return 0;
9683 }
9684 def_yn = 1;
9685 if ((ptr->flags & PR_NO_DEFAULT) ||
9686 ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
9687 (ctx->options & E2F_OPT_NO))
9688 def_yn= 0;
9689
9690
9691
9692
9693
9694 if (ptr->flags & PR_LATCH_MASK) {
9695 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
9696 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
9697 ans = fix_problem(ctx, ldesc->question, pctx);
9698 if (ans == 1)
9699 ldesc->flags |= PRL_YES;
9700 if (ans == 0)
9701 ldesc->flags |= PRL_NO;
9702 ldesc->flags |= PRL_LATCHED;
9703 }
9704 if (ldesc->flags & PRL_SUPPRESS)
9705 suppress++;
9706 }
9707 if ((ptr->flags & PR_PREEN_NOMSG) &&
9708 (ctx->options & E2F_OPT_PREEN))
9709 suppress++;
9710 if ((ptr->flags & PR_NO_NOMSG) &&
9711 (ctx->options & E2F_OPT_NO))
9712 suppress++;
9713 if (!suppress) {
9714 message = ptr->e2p_description;
9715 if ((ctx->options & E2F_OPT_PREEN) &&
9716 !(ptr->flags & PR_PREEN_NOHDR)) {
9717 printf("%s: ", ctx->device_name ?
9718 ctx->device_name : ctx->filesystem_name);
9719 }
9720 if (*message)
9721 print_e2fsck_message(ctx, _(message), pctx, 1);
9722 }
9723 if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
9724 preenhalt(ctx);
9725
9726 if (ptr->flags & PR_FATAL)
9727 bb_error_msg_and_die(0);
9728
9729 if (ptr->prompt == PROMPT_NONE) {
9730 if (ptr->flags & PR_NOCOLLATE)
9731 answer = -1;
9732 else
9733 answer = def_yn;
9734 } else {
9735 if (ctx->options & E2F_OPT_PREEN) {
9736 answer = def_yn;
9737 if (!(ptr->flags & PR_PREEN_NOMSG))
9738 print_answer = 1;
9739 } else if ((ptr->flags & PR_LATCH_MASK) &&
9740 (ldesc->flags & (PRL_YES | PRL_NO))) {
9741 if (!suppress)
9742 print_answer = 1;
9743 if (ldesc->flags & PRL_YES)
9744 answer = 1;
9745 else
9746 answer = 0;
9747 } else
9748 answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
9749 if (!answer && !(ptr->flags & PR_NO_OK))
9750 ext2fs_unmark_valid(fs);
9751
9752 if (print_answer)
9753 printf("%s.\n", answer ?
9754 _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
9755
9756 }
9757
9758 if ((ptr->prompt == PROMPT_ABORT) && answer)
9759 bb_error_msg_and_die(0);
9760
9761 if (ptr->flags & PR_AFTER_CODE)
9762 answer = fix_problem(ctx, ptr->second_code, pctx);
9763
9764 return answer;
9765}
9766
9767
9768
9769
9770
9771
9772
9773
9774
9775
9776
9777struct recovery_info
9778{
9779 tid_t start_transaction;
9780 tid_t end_transaction;
9781
9782 int nr_replays;
9783 int nr_revokes;
9784 int nr_revoke_hits;
9785};
9786
9787enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
9788static int do_one_pass(journal_t *journal,
9789 struct recovery_info *info, enum passtype pass);
9790static int scan_revoke_records(journal_t *, struct buffer_head *,
9791 tid_t, struct recovery_info *);
9792
9793
9794
9795
9796
9797static int jread(struct buffer_head **bhp, journal_t *journal,
9798 unsigned int offset)
9799{
9800 int err;
9801 unsigned long blocknr;
9802 struct buffer_head *bh;
9803
9804 *bhp = NULL;
9805
9806 err = journal_bmap(journal, offset, &blocknr);
9807
9808 if (err) {
9809 printf("JBD: bad block at offset %u\n", offset);
9810 return err;
9811 }
9812
9813 bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
9814 if (!bh)
9815 return -ENOMEM;
9816
9817 if (!buffer_uptodate(bh)) {
9818
9819
9820 if (!buffer_req(bh))
9821 do_readahead(journal, offset);
9822 wait_on_buffer(bh);
9823 }
9824
9825 if (!buffer_uptodate(bh)) {
9826 printf("JBD: Failed to read block at offset %u\n", offset);
9827 brelse(bh);
9828 return -EIO;
9829 }
9830
9831 *bhp = bh;
9832 return 0;
9833}
9834
9835
9836
9837
9838
9839
9840static int count_tags(struct buffer_head *bh, int size)
9841{
9842 char * tagp;
9843 journal_block_tag_t * tag;
9844 int nr = 0;
9845
9846 tagp = &bh->b_data[sizeof(journal_header_t)];
9847
9848 while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
9849 tag = (journal_block_tag_t *) tagp;
9850
9851 nr++;
9852 tagp += sizeof(journal_block_tag_t);
9853 if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
9854 tagp += 16;
9855
9856 if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
9857 break;
9858 }
9859
9860 return nr;
9861}
9862
9863
9864
9865#define wrap(journal, var) \
9866do { \
9867 if (var >= (journal)->j_last) \
9868 var -= ((journal)->j_last - (journal)->j_first); \
9869} while (0)
9870
9871
9872
9873
9874
9875
9876
9877
9878
9879
9880
9881
9882
9883int journal_recover(journal_t *journal)
9884{
9885 int err;
9886 journal_superblock_t * sb;
9887
9888 struct recovery_info info;
9889
9890 memset(&info, 0, sizeof(info));
9891 sb = journal->j_superblock;
9892
9893
9894
9895
9896
9897
9898
9899 if (!sb->s_start) {
9900 journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
9901 return 0;
9902 }
9903
9904 err = do_one_pass(journal, &info, PASS_SCAN);
9905 if (!err)
9906 err = do_one_pass(journal, &info, PASS_REVOKE);
9907 if (!err)
9908 err = do_one_pass(journal, &info, PASS_REPLAY);
9909
9910
9911
9912 journal->j_transaction_sequence = ++info.end_transaction;
9913
9914 journal_clear_revoke(journal);
9915 sync_blockdev(journal->j_fs_dev);
9916 return err;
9917}
9918
9919static int do_one_pass(journal_t *journal,
9920 struct recovery_info *info, enum passtype pass)
9921{
9922 unsigned int first_commit_ID, next_commit_ID;
9923 unsigned long next_log_block;
9924 int err, success = 0;
9925 journal_superblock_t * sb;
9926 journal_header_t * tmp;
9927 struct buffer_head * bh;
9928 unsigned int sequence;
9929 int blocktype;
9930
9931
9932 int MAX_BLOCKS_PER_DESC;
9933 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
9934 / sizeof(journal_block_tag_t));
9935
9936
9937
9938
9939
9940
9941
9942 sb = journal->j_superblock;
9943 next_commit_ID = ntohl(sb->s_sequence);
9944 next_log_block = ntohl(sb->s_start);
9945
9946 first_commit_ID = next_commit_ID;
9947 if (pass == PASS_SCAN)
9948 info->start_transaction = first_commit_ID;
9949
9950
9951
9952
9953
9954
9955
9956
9957 while (1) {
9958 int flags;
9959 char * tagp;
9960 journal_block_tag_t * tag;
9961 struct buffer_head * obh;
9962 struct buffer_head * nbh;
9963
9964
9965
9966
9967
9968 if (pass != PASS_SCAN)
9969 if (tid_geq(next_commit_ID, info->end_transaction))
9970 break;
9971
9972
9973
9974
9975
9976 err = jread(&bh, journal, next_log_block);
9977 if (err)
9978 goto failed;
9979
9980 next_log_block++;
9981 wrap(journal, next_log_block);
9982
9983
9984
9985
9986
9987
9988
9989 tmp = (journal_header_t *)bh->b_data;
9990
9991 if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
9992 brelse(bh);
9993 break;
9994 }
9995
9996 blocktype = ntohl(tmp->h_blocktype);
9997 sequence = ntohl(tmp->h_sequence);
9998
9999 if (sequence != next_commit_ID) {
10000 brelse(bh);
10001 break;
10002 }
10003
10004
10005
10006
10007
10008 switch (blocktype) {
10009 case JFS_DESCRIPTOR_BLOCK:
10010
10011
10012
10013 if (pass != PASS_REPLAY) {
10014 next_log_block +=
10015 count_tags(bh, journal->j_blocksize);
10016 wrap(journal, next_log_block);
10017 brelse(bh);
10018 continue;
10019 }
10020
10021
10022
10023
10024
10025 tagp = &bh->b_data[sizeof(journal_header_t)];
10026 while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
10027 <= journal->j_blocksize) {
10028 unsigned long io_block;
10029
10030 tag = (journal_block_tag_t *) tagp;
10031 flags = ntohl(tag->t_flags);
10032
10033 io_block = next_log_block++;
10034 wrap(journal, next_log_block);
10035 err = jread(&obh, journal, io_block);
10036 if (err) {
10037
10038
10039 success = err;
10040 printf("JBD: IO error %d recovering "
10041 "block %ld in log\n",
10042 err, io_block);
10043 } else {
10044 unsigned long blocknr;
10045
10046 blocknr = ntohl(tag->t_blocknr);
10047
10048
10049
10050
10051 if (journal_test_revoke
10052 (journal, blocknr,
10053 next_commit_ID)) {
10054 brelse(obh);
10055 ++info->nr_revoke_hits;
10056 goto skip_write;
10057 }
10058
10059
10060
10061 nbh = getblk(journal->j_fs_dev,
10062 blocknr,
10063 journal->j_blocksize);
10064 if (nbh == NULL) {
10065 printf("JBD: Out of memory "
10066 "during recovery.\n");
10067 err = -ENOMEM;
10068 brelse(bh);
10069 brelse(obh);
10070 goto failed;
10071 }
10072
10073 lock_buffer(nbh);
10074 memcpy(nbh->b_data, obh->b_data,
10075 journal->j_blocksize);
10076 if (flags & JFS_FLAG_ESCAPE) {
10077 *((unsigned int *)bh->b_data) =
10078 htonl(JFS_MAGIC_NUMBER);
10079 }
10080
10081 mark_buffer_uptodate(nbh, 1);
10082 mark_buffer_dirty(nbh);
10083 ++info->nr_replays;
10084
10085 unlock_buffer(nbh);
10086 brelse(obh);
10087 brelse(nbh);
10088 }
10089
10090 skip_write:
10091 tagp += sizeof(journal_block_tag_t);
10092 if (!(flags & JFS_FLAG_SAME_UUID))
10093 tagp += 16;
10094
10095 if (flags & JFS_FLAG_LAST_TAG)
10096 break;
10097 }
10098
10099 brelse(bh);
10100 continue;
10101
10102 case JFS_COMMIT_BLOCK:
10103
10104
10105
10106 brelse(bh);
10107 next_commit_ID++;
10108 continue;
10109
10110 case JFS_REVOKE_BLOCK:
10111
10112
10113 if (pass != PASS_REVOKE) {
10114 brelse(bh);
10115 continue;
10116 }
10117
10118 err = scan_revoke_records(journal, bh,
10119 next_commit_ID, info);
10120 brelse(bh);
10121 if (err)
10122 goto failed;
10123 continue;
10124
10125 default:
10126 goto done;
10127 }
10128 }
10129
10130 done:
10131
10132
10133
10134
10135
10136
10137
10138 if (pass == PASS_SCAN)
10139 info->end_transaction = next_commit_ID;
10140 else {
10141
10142
10143 if (info->end_transaction != next_commit_ID) {
10144 printf("JBD: recovery pass %d ended at "
10145 "transaction %u, expected %u\n",
10146 pass, next_commit_ID, info->end_transaction);
10147 if (!success)
10148 success = -EIO;
10149 }
10150 }
10151
10152 return success;
10153
10154 failed:
10155 return err;
10156}
10157
10158
10159
10160
10161static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
10162 tid_t sequence, struct recovery_info *info)
10163{
10164 journal_revoke_header_t *header;
10165 int offset, max;
10166
10167 header = (journal_revoke_header_t *) bh->b_data;
10168 offset = sizeof(journal_revoke_header_t);
10169 max = ntohl(header->r_count);
10170
10171 while (offset < max) {
10172 unsigned long blocknr;
10173 int err;
10174
10175 blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
10176 offset += 4;
10177 err = journal_set_revoke(journal, blocknr, sequence);
10178 if (err)
10179 return err;
10180 ++info->nr_revokes;
10181 }
10182 return 0;
10183}
10184
10185
10186
10187
10188
10189
10190
10191
10192
10193
10194
10195
10196
10197
10198
10199
10200
10201
10202
10203
10204
10205
10206
10207
10208
10209
10210
10211
10212
10213
10214
10215
10216
10217
10218
10219
10220
10221
10222
10223
10224
10225
10226struct fill_dir_struct {
10227 char *buf;
10228 struct ext2_inode *inode;
10229 int err;
10230 e2fsck_t ctx;
10231 struct hash_entry *harray;
10232 int max_array, num_array;
10233 int dir_size;
10234 int compress;
10235 ino_t parent;
10236};
10237
10238struct hash_entry {
10239 ext2_dirhash_t hash;
10240 ext2_dirhash_t minor_hash;
10241 struct ext2_dir_entry *dir;
10242};
10243
10244struct out_dir {
10245 int num;
10246 int max;
10247 char *buf;
10248 ext2_dirhash_t *hashes;
10249};
10250
10251static int fill_dir_block(ext2_filsys fs,
10252 blk_t *block_nr,
10253 e2_blkcnt_t blockcnt,
10254 blk_t ref_block FSCK_ATTR((unused)),
10255 int ref_offset FSCK_ATTR((unused)),
10256 void *priv_data)
10257{
10258 struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
10259 struct hash_entry *new_array, *ent;
10260 struct ext2_dir_entry *dirent;
10261 char *dir;
10262 unsigned int offset, dir_offset;
10263
10264 if (blockcnt < 0)
10265 return 0;
10266
10267 offset = blockcnt * fs->blocksize;
10268 if (offset + fs->blocksize > fd->inode->i_size) {
10269 fd->err = EXT2_ET_DIR_CORRUPTED;
10270 return BLOCK_ABORT;
10271 }
10272 dir = (fd->buf+offset);
10273 if (HOLE_BLKADDR(*block_nr)) {
10274 memset(dir, 0, fs->blocksize);
10275 dirent = (struct ext2_dir_entry *) dir;
10276 dirent->rec_len = fs->blocksize;
10277 } else {
10278 fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
10279 if (fd->err)
10280 return BLOCK_ABORT;
10281 }
10282
10283 dir_offset = 0;
10284 while (dir_offset < fs->blocksize) {
10285 dirent = (struct ext2_dir_entry *) (dir + dir_offset);
10286 if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
10287 (dirent->rec_len < 8) ||
10288 ((dirent->rec_len % 4) != 0) ||
10289 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
10290 fd->err = EXT2_ET_DIR_CORRUPTED;
10291 return BLOCK_ABORT;
10292 }
10293 dir_offset += dirent->rec_len;
10294 if (dirent->inode == 0)
10295 continue;
10296 if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
10297 (dirent->name[0] == '.'))
10298 continue;
10299 if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
10300 (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
10301 fd->parent = dirent->inode;
10302 continue;
10303 }
10304 if (fd->num_array >= fd->max_array) {
10305 new_array = xrealloc(fd->harray,
10306 sizeof(struct hash_entry) * (fd->max_array+500));
10307 fd->harray = new_array;
10308 fd->max_array += 500;
10309 }
10310 ent = fd->harray + fd->num_array++;
10311 ent->dir = dirent;
10312 fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
10313 if (fd->compress)
10314 ent->hash = ent->minor_hash = 0;
10315 else {
10316 fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
10317 dirent->name,
10318 dirent->name_len & 0xFF,
10319 fs->super->s_hash_seed,
10320 &ent->hash, &ent->minor_hash);
10321 if (fd->err)
10322 return BLOCK_ABORT;
10323 }
10324 }
10325
10326 return 0;
10327}
10328
10329
10330static int name_cmp(const void *a, const void *b)
10331{
10332 const struct hash_entry *he_a = (const struct hash_entry *) a;
10333 const struct hash_entry *he_b = (const struct hash_entry *) b;
10334 int ret;
10335 int min_len;
10336
10337 min_len = he_a->dir->name_len;
10338 if (min_len > he_b->dir->name_len)
10339 min_len = he_b->dir->name_len;
10340
10341 ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
10342 if (ret == 0) {
10343 if (he_a->dir->name_len > he_b->dir->name_len)
10344 ret = 1;
10345 else if (he_a->dir->name_len < he_b->dir->name_len)
10346 ret = -1;
10347 else
10348 ret = he_b->dir->inode - he_a->dir->inode;
10349 }
10350 return ret;
10351}
10352
10353
10354static int hash_cmp(const void *a, const void *b)
10355{
10356 const struct hash_entry *he_a = (const struct hash_entry *) a;
10357 const struct hash_entry *he_b = (const struct hash_entry *) b;
10358 int ret;
10359
10360 if (he_a->hash > he_b->hash)
10361 ret = 1;
10362 else if (he_a->hash < he_b->hash)
10363 ret = -1;
10364 else {
10365 if (he_a->minor_hash > he_b->minor_hash)
10366 ret = 1;
10367 else if (he_a->minor_hash < he_b->minor_hash)
10368 ret = -1;
10369 else
10370 ret = name_cmp(a, b);
10371 }
10372 return ret;
10373}
10374
10375static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
10376 int blocks)
10377{
10378 void *new_mem;
10379
10380 if (outdir->max) {
10381 new_mem = xrealloc(outdir->buf, blocks * fs->blocksize);
10382 outdir->buf = new_mem;
10383 new_mem = xrealloc(outdir->hashes,
10384 blocks * sizeof(ext2_dirhash_t));
10385 outdir->hashes = new_mem;
10386 } else {
10387 outdir->buf = xmalloc(blocks * fs->blocksize);
10388 outdir->hashes = xmalloc(blocks * sizeof(ext2_dirhash_t));
10389 outdir->num = 0;
10390 }
10391 outdir->max = blocks;
10392 return 0;
10393}
10394
10395static void free_out_dir(struct out_dir *outdir)
10396{
10397 free(outdir->buf);
10398 free(outdir->hashes);
10399 outdir->max = 0;
10400 outdir->num =0;
10401}
10402
10403static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
10404 char ** ret)
10405{
10406 errcode_t retval;
10407
10408 if (outdir->num >= outdir->max) {
10409 retval = alloc_size_dir(fs, outdir, outdir->max + 50);
10410 if (retval)
10411 return retval;
10412 }
10413 *ret = outdir->buf + (outdir->num++ * fs->blocksize);
10414 memset(*ret, 0, fs->blocksize);
10415 return 0;
10416}
10417
10418
10419
10420
10421
10422
10423
10424static void mutate_name(char *str, __u16 *len)
10425{
10426 int i;
10427 __u16 l = *len & 0xFF, h = *len & 0xff00;
10428
10429
10430
10431
10432
10433 for (i = l-1; i > 0; i--) {
10434 if (!isdigit(str[i]))
10435 break;
10436 }
10437 if ((i == l-1) || (str[i] != '~')) {
10438 if (((l-1) & 3) < 2)
10439 l += 2;
10440 else
10441 l = (l+3) & ~3;
10442 str[l-2] = '~';
10443 str[l-1] = '0';
10444 *len = l | h;
10445 return;
10446 }
10447 for (i = l-1; i >= 0; i--) {
10448 if (isdigit(str[i])) {
10449 if (str[i] == '9')
10450 str[i] = '0';
10451 else {
10452 str[i]++;
10453 return;
10454 }
10455 continue;
10456 }
10457 if (i == 1) {
10458 if (str[0] == 'z')
10459 str[0] = 'A';
10460 else if (str[0] == 'Z') {
10461 str[0] = '~';
10462 str[1] = '0';
10463 } else
10464 str[0]++;
10465 } else if (i > 0) {
10466 str[i] = '1';
10467 str[i-1] = '~';
10468 } else {
10469 if (str[0] == '~')
10470 str[0] = 'a';
10471 else
10472 str[0]++;
10473 }
10474 break;
10475 }
10476}
10477
10478static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
10479 ext2_ino_t ino,
10480 struct fill_dir_struct *fd)
10481{
10482 struct problem_context pctx;
10483 struct hash_entry *ent, *prev;
10484 int i, j;
10485 int fixed = 0;
10486 char new_name[256];
10487 __u16 new_len;
10488
10489 clear_problem_context(&pctx);
10490 pctx.ino = ino;
10491
10492 for (i=1; i < fd->num_array; i++) {
10493 ent = fd->harray + i;
10494 prev = ent - 1;
10495 if (!ent->dir->inode ||
10496 ((ent->dir->name_len & 0xFF) !=
10497 (prev->dir->name_len & 0xFF)) ||
10498 (strncmp(ent->dir->name, prev->dir->name,
10499 ent->dir->name_len & 0xFF)))
10500 continue;
10501 pctx.dirent = ent->dir;
10502 if ((ent->dir->inode == prev->dir->inode) &&
10503 fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
10504 e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
10505 ent->dir->inode = 0;
10506 fixed++;
10507 continue;
10508 }
10509 memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
10510 new_len = ent->dir->name_len;
10511 mutate_name(new_name, &new_len);
10512 for (j=0; j < fd->num_array; j++) {
10513 if ((i==j) ||
10514 ((ent->dir->name_len & 0xFF) !=
10515 (fd->harray[j].dir->name_len & 0xFF)) ||
10516 (strncmp(new_name, fd->harray[j].dir->name,
10517 new_len & 0xFF)))
10518 continue;
10519 mutate_name(new_name, &new_len);
10520
10521 j = -1;
10522 }
10523 new_name[new_len & 0xFF] = 0;
10524 pctx.str = new_name;
10525 if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
10526 memcpy(ent->dir->name, new_name, new_len & 0xFF);
10527 ent->dir->name_len = new_len;
10528 ext2fs_dirhash(fs->super->s_def_hash_version,
10529 ent->dir->name,
10530 ent->dir->name_len & 0xFF,
10531 fs->super->s_hash_seed,
10532 &ent->hash, &ent->minor_hash);
10533 fixed++;
10534 }
10535 }
10536 return fixed;
10537}
10538
10539
10540static errcode_t copy_dir_entries(ext2_filsys fs,
10541 struct fill_dir_struct *fd,
10542 struct out_dir *outdir)
10543{
10544 errcode_t retval;
10545 char *block_start;
10546 struct hash_entry *ent;
10547 struct ext2_dir_entry *dirent;
10548 int i, rec_len, left;
10549 ext2_dirhash_t prev_hash;
10550 int offset;
10551
10552 outdir->max = 0;
10553 retval = alloc_size_dir(fs, outdir,
10554 (fd->dir_size / fs->blocksize) + 2);
10555 if (retval)
10556 return retval;
10557 outdir->num = fd->compress ? 0 : 1;
10558 offset = 0;
10559 outdir->hashes[0] = 0;
10560 prev_hash = 1;
10561 if ((retval = get_next_block(fs, outdir, &block_start)))
10562 return retval;
10563 dirent = (struct ext2_dir_entry *) block_start;
10564 left = fs->blocksize;
10565 for (i=0; i < fd->num_array; i++) {
10566 ent = fd->harray + i;
10567 if (ent->dir->inode == 0)
10568 continue;
10569 rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
10570 if (rec_len > left) {
10571 if (left)
10572 dirent->rec_len += left;
10573 if ((retval = get_next_block(fs, outdir,
10574 &block_start)))
10575 return retval;
10576 offset = 0;
10577 }
10578 left = fs->blocksize - offset;
10579 dirent = (struct ext2_dir_entry *) (block_start + offset);
10580 if (offset == 0) {
10581 if (ent->hash == prev_hash)
10582 outdir->hashes[outdir->num-1] = ent->hash | 1;
10583 else
10584 outdir->hashes[outdir->num-1] = ent->hash;
10585 }
10586 dirent->inode = ent->dir->inode;
10587 dirent->name_len = ent->dir->name_len;
10588 dirent->rec_len = rec_len;
10589 memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
10590 offset += rec_len;
10591 left -= rec_len;
10592 if (left < 12) {
10593 dirent->rec_len += left;
10594 offset += left;
10595 left = 0;
10596 }
10597 prev_hash = ent->hash;
10598 }
10599 if (left)
10600 dirent->rec_len += left;
10601
10602 return 0;
10603}
10604
10605
10606static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
10607 ext2_ino_t ino, ext2_ino_t parent)
10608{
10609 struct ext2_dir_entry *dir;
10610 struct ext2_dx_root_info *root;
10611 struct ext2_dx_countlimit *limits;
10612 int filetype = 0;
10613
10614 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
10615 filetype = EXT2_FT_DIR << 8;
10616
10617 memset(buf, 0, fs->blocksize);
10618 dir = (struct ext2_dir_entry *) buf;
10619 dir->inode = ino;
10620 dir->name[0] = '.';
10621 dir->name_len = 1 | filetype;
10622 dir->rec_len = 12;
10623 dir = (struct ext2_dir_entry *) (buf + 12);
10624 dir->inode = parent;
10625 dir->name[0] = '.';
10626 dir->name[1] = '.';
10627 dir->name_len = 2 | filetype;
10628 dir->rec_len = fs->blocksize - 12;
10629
10630 root = (struct ext2_dx_root_info *) (buf+24);
10631 root->reserved_zero = 0;
10632 root->hash_version = fs->super->s_def_hash_version;
10633 root->info_length = 8;
10634 root->indirect_levels = 0;
10635 root->unused_flags = 0;
10636
10637 limits = (struct ext2_dx_countlimit *) (buf+32);
10638 limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
10639 limits->count = 0;
10640
10641 return root;
10642}
10643
10644
10645static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
10646{
10647 struct ext2_dir_entry *dir;
10648 struct ext2_dx_countlimit *limits;
10649
10650 memset(buf, 0, fs->blocksize);
10651 dir = (struct ext2_dir_entry *) buf;
10652 dir->inode = 0;
10653 dir->rec_len = fs->blocksize;
10654
10655 limits = (struct ext2_dx_countlimit *) (buf+8);
10656 limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
10657 limits->count = 0;
10658
10659 return (struct ext2_dx_entry *) limits;
10660}
10661
10662
10663
10664
10665
10666static errcode_t calculate_tree(ext2_filsys fs,
10667 struct out_dir *outdir,
10668 ext2_ino_t ino,
10669 ext2_ino_t parent)
10670{
10671 struct ext2_dx_root_info *root_info;
10672 struct ext2_dx_entry *root, *dx_ent = 0;
10673 struct ext2_dx_countlimit *root_limit, *limit;
10674 errcode_t retval;
10675 char * block_start;
10676 int i, c1, c2, nblks;
10677 int limit_offset, root_offset;
10678
10679 root_info = set_root_node(fs, outdir->buf, ino, parent);
10680 root_offset = limit_offset = ((char *) root_info - outdir->buf) +
10681 root_info->info_length;
10682 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
10683 c1 = root_limit->limit;
10684 nblks = outdir->num;
10685
10686
10687 if (nblks-1 <= c1) {
10688
10689 root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
10690 for (i=1; i < nblks; i++) {
10691 root->block = ext2fs_cpu_to_le32(i);
10692 if (i != 1)
10693 root->hash =
10694 ext2fs_cpu_to_le32(outdir->hashes[i]);
10695 root++;
10696 c1--;
10697 }
10698 } else {
10699 c2 = 0;
10700 limit = 0;
10701 root_info->indirect_levels = 1;
10702 for (i=1; i < nblks; i++) {
10703 if (c1 == 0)
10704 return ENOSPC;
10705 if (c2 == 0) {
10706 if (limit)
10707 limit->limit = limit->count =
10708 ext2fs_cpu_to_le16(limit->limit);
10709 root = (struct ext2_dx_entry *)
10710 (outdir->buf + root_offset);
10711 root->block = ext2fs_cpu_to_le32(outdir->num);
10712 if (i != 1)
10713 root->hash =
10714 ext2fs_cpu_to_le32(outdir->hashes[i]);
10715 if ((retval = get_next_block(fs, outdir,
10716 &block_start)))
10717 return retval;
10718 dx_ent = set_int_node(fs, block_start);
10719 limit = (struct ext2_dx_countlimit *) dx_ent;
10720 c2 = limit->limit;
10721 root_offset += sizeof(struct ext2_dx_entry);
10722 c1--;
10723 }
10724 dx_ent->block = ext2fs_cpu_to_le32(i);
10725 if (c2 != limit->limit)
10726 dx_ent->hash =
10727 ext2fs_cpu_to_le32(outdir->hashes[i]);
10728 dx_ent++;
10729 c2--;
10730 }
10731 limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
10732 limit->limit = ext2fs_cpu_to_le16(limit->limit);
10733 }
10734 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
10735 root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
10736 root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
10737
10738 return 0;
10739}
10740
10741struct write_dir_struct {
10742 struct out_dir *outdir;
10743 errcode_t err;
10744 e2fsck_t ctx;
10745 int cleared;
10746};
10747
10748
10749
10750
10751static int write_dir_block(ext2_filsys fs,
10752 blk_t *block_nr,
10753 e2_blkcnt_t blockcnt,
10754 blk_t ref_block FSCK_ATTR((unused)),
10755 int ref_offset FSCK_ATTR((unused)),
10756 void *priv_data)
10757{
10758 struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
10759 blk_t blk;
10760 char *dir;
10761
10762 if (*block_nr == 0)
10763 return 0;
10764 if (blockcnt >= wd->outdir->num) {
10765 e2fsck_read_bitmaps(wd->ctx);
10766 blk = *block_nr;
10767 ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
10768 ext2fs_block_alloc_stats(fs, blk, -1);
10769 *block_nr = 0;
10770 wd->cleared++;
10771 return BLOCK_CHANGED;
10772 }
10773 if (blockcnt < 0)
10774 return 0;
10775
10776 dir = wd->outdir->buf + (blockcnt * fs->blocksize);
10777 wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
10778 if (wd->err)
10779 return BLOCK_ABORT;
10780 return 0;
10781}
10782
10783static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
10784 struct out_dir *outdir,
10785 ext2_ino_t ino, int compress)
10786{
10787 struct write_dir_struct wd;
10788 errcode_t retval;
10789 struct ext2_inode inode;
10790
10791 retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
10792 if (retval)
10793 return retval;
10794
10795 wd.outdir = outdir;
10796 wd.err = 0;
10797 wd.ctx = ctx;
10798 wd.cleared = 0;
10799
10800 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
10801 write_dir_block, &wd);
10802 if (retval)
10803 return retval;
10804 if (wd.err)
10805 return wd.err;
10806
10807 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
10808 if (compress)
10809 inode.i_flags &= ~EXT2_INDEX_FL;
10810 else
10811 inode.i_flags |= EXT2_INDEX_FL;
10812 inode.i_size = outdir->num * fs->blocksize;
10813 inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
10814 e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
10815
10816 return 0;
10817}
10818
10819static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
10820{
10821 ext2_filsys fs = ctx->fs;
10822 errcode_t retval;
10823 struct ext2_inode inode;
10824 char *dir_buf = 0;
10825 struct fill_dir_struct fd;
10826 struct out_dir outdir;
10827
10828 outdir.max = outdir.num = 0;
10829 outdir.buf = 0;
10830 outdir.hashes = 0;
10831 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
10832
10833 retval = ENOMEM;
10834 fd.harray = 0;
10835 dir_buf = xmalloc(inode.i_size);
10836
10837 fd.max_array = inode.i_size / 32;
10838 fd.num_array = 0;
10839 fd.harray = xmalloc(fd.max_array * sizeof(struct hash_entry));
10840
10841 fd.ctx = ctx;
10842 fd.buf = dir_buf;
10843 fd.inode = &inode;
10844 fd.err = 0;
10845 fd.dir_size = 0;
10846 fd.compress = 0;
10847 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
10848 (inode.i_size / fs->blocksize) < 2)
10849 fd.compress = 1;
10850 fd.parent = 0;
10851
10852
10853 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
10854 fill_dir_block, &fd);
10855 if (fd.err) {
10856 retval = fd.err;
10857 goto errout;
10858 }
10859
10860
10861resort:
10862 if (fd.compress)
10863 qsort(fd.harray+2, fd.num_array-2,
10864 sizeof(struct hash_entry), name_cmp);
10865 else
10866 qsort(fd.harray, fd.num_array,
10867 sizeof(struct hash_entry), hash_cmp);
10868
10869
10870
10871
10872 if (duplicate_search_and_fix(ctx, fs, ino, &fd))
10873 goto resort;
10874
10875 if (ctx->options & E2F_OPT_NO) {
10876 retval = 0;
10877 goto errout;
10878 }
10879
10880
10881
10882
10883
10884 retval = copy_dir_entries(fs, &fd, &outdir);
10885 if (retval)
10886 goto errout;
10887
10888 free(dir_buf); dir_buf = 0;
10889
10890 if (!fd.compress) {
10891
10892 retval = calculate_tree(fs, &outdir, ino, fd.parent);
10893 if (retval)
10894 goto errout;
10895 }
10896
10897 retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
10898
10899errout:
10900 free(dir_buf);
10901 free(fd.harray);
10902
10903 free_out_dir(&outdir);
10904 return retval;
10905}
10906
10907void e2fsck_rehash_directories(e2fsck_t ctx)
10908{
10909 struct problem_context pctx;
10910 struct dir_info *dir;
10911 ext2_u32_iterate iter;
10912 ext2_ino_t ino;
10913 errcode_t retval;
10914 int i, cur, max, all_dirs, dir_index, first = 1;
10915
10916 all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
10917
10918 if (!ctx->dirs_to_hash && !all_dirs)
10919 return;
10920
10921 e2fsck_get_lost_and_found(ctx, 0);
10922
10923 clear_problem_context(&pctx);
10924
10925 dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
10926 cur = 0;
10927 if (all_dirs) {
10928 i = 0;
10929 max = e2fsck_get_num_dirinfo(ctx);
10930 } else {
10931 retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
10932 &iter);
10933 if (retval) {
10934 pctx.errcode = retval;
10935 fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
10936 return;
10937 }
10938 max = ext2fs_u32_list_count(ctx->dirs_to_hash);
10939 }
10940 while (1) {
10941 if (all_dirs) {
10942 if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
10943 break;
10944 ino = dir->ino;
10945 } else {
10946 if (!ext2fs_u32_list_iterate(iter, &ino))
10947 break;
10948 }
10949 if (ino == ctx->lost_and_found)
10950 continue;
10951 pctx.dir = ino;
10952 if (first) {
10953 fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
10954 first = 0;
10955 }
10956 pctx.errcode = e2fsck_rehash_dir(ctx, ino);
10957 if (pctx.errcode) {
10958 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
10959 fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
10960 }
10961 if (ctx->progress && !ctx->progress_fd)
10962 e2fsck_simple_progress(ctx, "Rebuilding directory",
10963 100.0 * (float) (++cur) / (float) max, ino);
10964 }
10965 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
10966 if (!all_dirs)
10967 ext2fs_u32_list_iterate_end(iter);
10968
10969 ext2fs_u32_list_free(ctx->dirs_to_hash);
10970 ctx->dirs_to_hash = 0;
10971}
10972
10973
10974
10975
10976
10977
10978
10979
10980
10981
10982
10983
10984
10985
10986
10987
10988
10989
10990
10991
10992
10993
10994
10995
10996
10997
10998
10999
11000
11001
11002
11003
11004
11005
11006
11007
11008
11009
11010
11011
11012
11013
11014
11015
11016
11017
11018
11019
11020
11021
11022
11023
11024static kmem_cache_t *revoke_record_cache;
11025static kmem_cache_t *revoke_table_cache;
11026
11027
11028
11029
11030
11031struct jbd_revoke_record_s
11032{
11033 struct list_head hash;
11034 tid_t sequence;
11035 unsigned long blocknr;
11036};
11037
11038
11039
11040struct jbd_revoke_table_s
11041{
11042
11043
11044 int hash_size;
11045 int hash_shift;
11046 struct list_head *hash_table;
11047};
11048
11049
11050
11051
11052
11053static int hash(journal_t *journal, unsigned long block)
11054{
11055 struct jbd_revoke_table_s *table = journal->j_revoke;
11056 int hash_shift = table->hash_shift;
11057
11058 return ((block << (hash_shift - 6)) ^
11059 (block >> 13) ^
11060 (block << (hash_shift - 12))) & (table->hash_size - 1);
11061}
11062
11063static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
11064 tid_t seq)
11065{
11066 struct list_head *hash_list;
11067 struct jbd_revoke_record_s *record;
11068
11069 record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
11070 if (!record)
11071 goto oom;
11072
11073 record->sequence = seq;
11074 record->blocknr = blocknr;
11075 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
11076 list_add(&record->hash, hash_list);
11077 return 0;
11078
11079oom:
11080 return -ENOMEM;
11081}
11082
11083
11084
11085static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
11086 unsigned long blocknr)
11087{
11088 struct list_head *hash_list;
11089 struct jbd_revoke_record_s *record;
11090
11091 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
11092
11093 record = (struct jbd_revoke_record_s *) hash_list->next;
11094 while (&(record->hash) != hash_list) {
11095 if (record->blocknr == blocknr)
11096 return record;
11097 record = (struct jbd_revoke_record_s *) record->hash.next;
11098 }
11099 return NULL;
11100}
11101
11102int journal_init_revoke_caches(void)
11103{
11104 revoke_record_cache = do_cache_create(sizeof(struct jbd_revoke_record_s));
11105 if (revoke_record_cache == 0)
11106 return -ENOMEM;
11107
11108 revoke_table_cache = do_cache_create(sizeof(struct jbd_revoke_table_s));
11109 if (revoke_table_cache == 0) {
11110 do_cache_destroy(revoke_record_cache);
11111 revoke_record_cache = NULL;
11112 return -ENOMEM;
11113 }
11114 return 0;
11115}
11116
11117void journal_destroy_revoke_caches(void)
11118{
11119 do_cache_destroy(revoke_record_cache);
11120 revoke_record_cache = 0;
11121 do_cache_destroy(revoke_table_cache);
11122 revoke_table_cache = 0;
11123}
11124
11125
11126
11127int journal_init_revoke(journal_t *journal, int hash_size)
11128{
11129 int shift, tmp;
11130
11131 journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
11132 if (!journal->j_revoke)
11133 return -ENOMEM;
11134
11135
11136 journal->j_revoke->hash_size = hash_size;
11137
11138 shift = 0;
11139 tmp = hash_size;
11140 while ((tmp >>= 1UL) != 0UL)
11141 shift++;
11142 journal->j_revoke->hash_shift = shift;
11143
11144 journal->j_revoke->hash_table = xmalloc(hash_size * sizeof(struct list_head));
11145
11146 for (tmp = 0; tmp < hash_size; tmp++)
11147 INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
11148
11149 return 0;
11150}
11151
11152
11153
11154void journal_destroy_revoke(journal_t *journal)
11155{
11156 struct jbd_revoke_table_s *table;
11157 struct list_head *hash_list;
11158 int i;
11159
11160 table = journal->j_revoke;
11161 if (!table)
11162 return;
11163
11164 for (i=0; i<table->hash_size; i++) {
11165 hash_list = &table->hash_table[i];
11166 }
11167
11168 free(table->hash_table);
11169 free(table);
11170 journal->j_revoke = NULL;
11171}
11172
11173
11174
11175
11176
11177
11178
11179
11180
11181
11182
11183
11184
11185
11186
11187
11188
11189
11190
11191
11192
11193
11194
11195int journal_set_revoke(journal_t *journal, unsigned long blocknr,
11196 tid_t sequence)
11197{
11198 struct jbd_revoke_record_s *record;
11199
11200 record = find_revoke_record(journal, blocknr);
11201 if (record) {
11202
11203
11204 if (tid_gt(sequence, record->sequence))
11205 record->sequence = sequence;
11206 return 0;
11207 }
11208 return insert_revoke_hash(journal, blocknr, sequence);
11209}
11210
11211
11212
11213
11214
11215
11216
11217
11218int journal_test_revoke(journal_t *journal, unsigned long blocknr,
11219 tid_t sequence)
11220{
11221 struct jbd_revoke_record_s *record;
11222
11223 record = find_revoke_record(journal, blocknr);
11224 if (!record)
11225 return 0;
11226 if (tid_gt(sequence, record->sequence))
11227 return 0;
11228 return 1;
11229}
11230
11231
11232
11233
11234
11235
11236void journal_clear_revoke(journal_t *journal)
11237{
11238 int i;
11239 struct list_head *hash_list;
11240 struct jbd_revoke_record_s *record;
11241 struct jbd_revoke_table_s *revoke_var;
11242
11243 revoke_var = journal->j_revoke;
11244
11245 for (i = 0; i < revoke_var->hash_size; i++) {
11246 hash_list = &revoke_var->hash_table[i];
11247 while (!list_empty(hash_list)) {
11248 record = (struct jbd_revoke_record_s*) hash_list->next;
11249 list_del(&record->hash);
11250 free(record);
11251 }
11252 }
11253}
11254
11255
11256
11257
11258
11259#define MIN_CHECK 1
11260#define MAX_CHECK 2
11261
11262static void check_super_value(e2fsck_t ctx, const char *descr,
11263 unsigned long value, int flags,
11264 unsigned long min_val, unsigned long max_val)
11265{
11266 struct problem_context pctx;
11267
11268 if (((flags & MIN_CHECK) && (value < min_val)) ||
11269 ((flags & MAX_CHECK) && (value > max_val))) {
11270 clear_problem_context(&pctx);
11271 pctx.num = value;
11272 pctx.str = descr;
11273 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
11274 ctx->flags |= E2F_FLAG_ABORT;
11275 }
11276}
11277
11278
11279
11280
11281
11282#ifndef EXT2_SPECIAL_DEVICE_SIZE
11283static errcode_t e2fsck_get_device_size(e2fsck_t ctx)
11284{
11285 return (ext2fs_get_device_size(ctx->filesystem_name,
11286 EXT2_BLOCK_SIZE(ctx->fs->super),
11287 &ctx->num_blocks));
11288}
11289#endif
11290
11291
11292
11293
11294struct process_block_struct {
11295 e2fsck_t ctx;
11296 char *buf;
11297 struct problem_context *pctx;
11298 int truncating;
11299 int truncate_offset;
11300 e2_blkcnt_t truncate_block;
11301 int truncated_blocks;
11302 int abort;
11303 errcode_t errcode;
11304};
11305
11306static int release_inode_block(ext2_filsys fs, blk_t *block_nr,
11307 e2_blkcnt_t blockcnt,
11308 blk_t ref_blk FSCK_ATTR((unused)),
11309 int ref_offset FSCK_ATTR((unused)),
11310 void *priv_data)
11311{
11312 struct process_block_struct *pb;
11313 e2fsck_t ctx;
11314 struct problem_context *pctx;
11315 blk_t blk = *block_nr;
11316 int retval = 0;
11317
11318 pb = (struct process_block_struct *) priv_data;
11319 ctx = pb->ctx;
11320 pctx = pb->pctx;
11321
11322 pctx->blk = blk;
11323 pctx->blkcount = blockcnt;
11324
11325 if (HOLE_BLKADDR(blk))
11326 return 0;
11327
11328 if ((blk < fs->super->s_first_data_block) ||
11329 (blk >= fs->super->s_blocks_count)) {
11330 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
11331 return_abort:
11332 pb->abort = 1;
11333 return BLOCK_ABORT;
11334 }
11335
11336 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
11337 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
11338 goto return_abort;
11339 }
11340
11341
11342
11343
11344
11345
11346 if (pb->truncating) {
11347
11348
11349
11350
11351 if (blockcnt < 0) {
11352 int i, limit;
11353 blk_t *bp;
11354
11355 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
11356 pb->buf);
11357 if (pb->errcode)
11358 goto return_abort;
11359
11360 limit = fs->blocksize >> 2;
11361 for (i = 0, bp = (blk_t *) pb->buf;
11362 i < limit; i++, bp++)
11363 if (*bp)
11364 return 0;
11365 }
11366
11367
11368
11369
11370 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
11371 return 0;
11372
11373
11374
11375
11376 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
11377 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
11378 pb->buf);
11379 if (pb->errcode)
11380 goto return_abort;
11381 memset(pb->buf + pb->truncate_offset, 0,
11382 fs->blocksize - pb->truncate_offset);
11383 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
11384 pb->buf);
11385 if (pb->errcode)
11386 goto return_abort;
11387 }
11388 pb->truncated_blocks++;
11389 *block_nr = 0;
11390 retval |= BLOCK_CHANGED;
11391 }
11392
11393 ext2fs_block_alloc_stats(fs, blk, -1);
11394 return retval;
11395}
11396
11397
11398
11399
11400
11401
11402static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
11403 struct ext2_inode *inode, char *block_buf,
11404 struct problem_context *pctx)
11405{
11406 struct process_block_struct pb;
11407 ext2_filsys fs = ctx->fs;
11408 errcode_t retval;
11409 __u32 count;
11410
11411 if (!ext2fs_inode_has_valid_blocks(inode))
11412 return 0;
11413
11414 pb.buf = block_buf + 3 * ctx->fs->blocksize;
11415 pb.ctx = ctx;
11416 pb.abort = 0;
11417 pb.errcode = 0;
11418 pb.pctx = pctx;
11419 if (inode->i_links_count) {
11420 pb.truncating = 1;
11421 pb.truncate_block = (e2_blkcnt_t)
11422 ((((long long)inode->i_size_high << 32) +
11423 inode->i_size + fs->blocksize - 1) /
11424 fs->blocksize);
11425 pb.truncate_offset = inode->i_size % fs->blocksize;
11426 } else {
11427 pb.truncating = 0;
11428 pb.truncate_block = 0;
11429 pb.truncate_offset = 0;
11430 }
11431 pb.truncated_blocks = 0;
11432 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
11433 block_buf, release_inode_block, &pb);
11434 if (retval) {
11435 bb_error_msg(_("while calling ext2fs_block_iterate for inode %d"),
11436 ino);
11437 return 1;
11438 }
11439 if (pb.abort)
11440 return 1;
11441
11442
11443 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
11444
11445 if (pb.truncated_blocks)
11446 inode->i_blocks -= pb.truncated_blocks *
11447 (fs->blocksize / 512);
11448
11449 if (inode->i_file_acl) {
11450 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
11451 block_buf, -1, &count);
11452 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
11453 retval = 0;
11454 count = 1;
11455 }
11456 if (retval) {
11457 bb_error_msg(_("while calling ext2fs_adjust_ea_refocunt for inode %d"),
11458 ino);
11459 return 1;
11460 }
11461 if (count == 0)
11462 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
11463 inode->i_file_acl = 0;
11464 }
11465 return 0;
11466}
11467
11468
11469
11470
11471
11472static int release_orphan_inodes(e2fsck_t ctx)
11473{
11474 ext2_filsys fs = ctx->fs;
11475 ext2_ino_t ino, next_ino;
11476 struct ext2_inode inode;
11477 struct problem_context pctx;
11478 char *block_buf;
11479
11480 if ((ino = fs->super->s_last_orphan) == 0)
11481 return 0;
11482
11483
11484
11485
11486
11487 fs->super->s_last_orphan = 0;
11488 ext2fs_mark_super_dirty(fs);
11489
11490
11491
11492
11493
11494
11495 if (fs->super->s_state & EXT2_ERROR_FS)
11496 return 0;
11497
11498 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
11499 (ino > fs->super->s_inodes_count)) {
11500 clear_problem_context(&pctx);
11501 pctx.ino = ino;
11502 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
11503 return 1;
11504 }
11505
11506 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
11507 "block iterate buffer");
11508 e2fsck_read_bitmaps(ctx);
11509
11510 while (ino) {
11511 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
11512 clear_problem_context(&pctx);
11513 pctx.ino = ino;
11514 pctx.inode = &inode;
11515 pctx.str = inode.i_links_count ? _("Truncating") :
11516 _("Clearing");
11517
11518 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
11519
11520 next_ino = inode.i_dtime;
11521 if (next_ino &&
11522 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
11523 (next_ino > fs->super->s_inodes_count))) {
11524 pctx.ino = next_ino;
11525 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
11526 goto return_abort;
11527 }
11528
11529 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
11530 goto return_abort;
11531
11532 if (!inode.i_links_count) {
11533 ext2fs_inode_alloc_stats2(fs, ino, -1,
11534 LINUX_S_ISDIR(inode.i_mode));
11535 inode.i_dtime = time(NULL);
11536 } else {
11537 inode.i_dtime = 0;
11538 }
11539 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
11540 ino = next_ino;
11541 }
11542 ext2fs_free_mem(&block_buf);
11543 return 0;
11544return_abort:
11545 ext2fs_free_mem(&block_buf);
11546 return 1;
11547}
11548
11549
11550
11551
11552
11553
11554
11555static void check_resize_inode(e2fsck_t ctx)
11556{
11557 ext2_filsys fs = ctx->fs;
11558 struct ext2_inode inode;
11559 struct problem_context pctx;
11560 int i, j, gdt_off, ind_off;
11561 blk_t blk, pblk, expect;
11562 __u32 *dind_buf = 0, *ind_buf;
11563 errcode_t retval;
11564
11565 clear_problem_context(&pctx);
11566
11567
11568
11569
11570
11571 if (!(fs->super->s_feature_compat &
11572 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
11573 if (fs->super->s_reserved_gdt_blocks) {
11574 pctx.num = fs->super->s_reserved_gdt_blocks;
11575 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
11576 &pctx)) {
11577 fs->super->s_reserved_gdt_blocks = 0;
11578 ext2fs_mark_super_dirty(fs);
11579 }
11580 }
11581 }
11582
11583
11584 pctx.ino = EXT2_RESIZE_INO;
11585 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
11586 if (retval) {
11587 if (fs->super->s_feature_compat &
11588 EXT2_FEATURE_COMPAT_RESIZE_INODE)
11589 ctx->flags |= E2F_FLAG_RESIZE_INODE;
11590 return;
11591 }
11592
11593
11594
11595
11596
11597 if (!(fs->super->s_feature_compat &
11598 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
11599 for (i=0; i < EXT2_N_BLOCKS; i++) {
11600 if (inode.i_block[i])
11601 break;
11602 }
11603 if ((i < EXT2_N_BLOCKS) &&
11604 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
11605 memset(&inode, 0, sizeof(inode));
11606 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
11607 "clear_resize");
11608 }
11609 return;
11610 }
11611
11612
11613
11614
11615
11616 blk = inode.i_block[EXT2_DIND_BLOCK];
11617 for (i=0; i < EXT2_N_BLOCKS; i++) {
11618 if (i != EXT2_DIND_BLOCK && inode.i_block[i])
11619 break;
11620 }
11621 if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
11622 !(inode.i_mode & LINUX_S_IFREG) ||
11623 (blk < fs->super->s_first_data_block ||
11624 blk >= fs->super->s_blocks_count)) {
11625 resize_inode_invalid:
11626 if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
11627 memset(&inode, 0, sizeof(inode));
11628 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
11629 "clear_resize");
11630 ctx->flags |= E2F_FLAG_RESIZE_INODE;
11631 }
11632 if (!(ctx->options & E2F_OPT_READONLY)) {
11633 fs->super->s_state &= ~EXT2_VALID_FS;
11634 ext2fs_mark_super_dirty(fs);
11635 }
11636 goto cleanup;
11637 }
11638 dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
11639 "resize dind buffer");
11640 ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
11641
11642 retval = ext2fs_read_ind_block(fs, blk, dind_buf);
11643 if (retval)
11644 goto resize_inode_invalid;
11645
11646 gdt_off = fs->desc_blocks;
11647 pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
11648 for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
11649 i++, gdt_off++, pblk++) {
11650 gdt_off %= fs->blocksize/4;
11651 if (dind_buf[gdt_off] != pblk)
11652 goto resize_inode_invalid;
11653 retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
11654 if (retval)
11655 goto resize_inode_invalid;
11656 ind_off = 0;
11657 for (j = 1; j < fs->group_desc_count; j++) {
11658 if (!ext2fs_bg_has_super(fs, j))
11659 continue;
11660 expect = pblk + (j * fs->super->s_blocks_per_group);
11661 if (ind_buf[ind_off] != expect)
11662 goto resize_inode_invalid;
11663 ind_off++;
11664 }
11665 }
11666
11667cleanup:
11668 ext2fs_free_mem(&dind_buf);
11669
11670 }
11671
11672static void check_super_block(e2fsck_t ctx)
11673{
11674 ext2_filsys fs = ctx->fs;
11675 blk_t first_block, last_block;
11676 struct ext2_super_block *sb = fs->super;
11677 struct ext2_group_desc *gd;
11678 blk_t blocks_per_group = fs->super->s_blocks_per_group;
11679 blk_t bpg_max;
11680 int inodes_per_block;
11681 int ipg_max;
11682 int inode_size;
11683 dgrp_t i;
11684 blk_t should_be;
11685 struct problem_context pctx;
11686 __u32 free_blocks = 0, free_inodes = 0;
11687
11688 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
11689 ipg_max = inodes_per_block * (blocks_per_group - 4);
11690 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
11691 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
11692 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
11693 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
11694 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
11695
11696 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
11697 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
11698 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
11699 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
11700 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
11701 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
11702
11703 clear_problem_context(&pctx);
11704
11705
11706
11707
11708 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
11709 MIN_CHECK, 1, 0);
11710 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
11711 MIN_CHECK, 1, 0);
11712 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
11713 MAX_CHECK, 0, sb->s_blocks_count);
11714 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
11715 MIN_CHECK | MAX_CHECK, 0,
11716 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
11717 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
11718 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
11719 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
11720 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
11721 bpg_max);
11722 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
11723 MIN_CHECK | MAX_CHECK, 8, bpg_max);
11724 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
11725 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
11726 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
11727 MAX_CHECK, 0, sb->s_blocks_count / 2);
11728 check_super_value(ctx, "reserved_gdt_blocks",
11729 sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
11730 fs->blocksize/4);
11731 inode_size = EXT2_INODE_SIZE(sb);
11732 check_super_value(ctx, "inode_size",
11733 inode_size, MIN_CHECK | MAX_CHECK,
11734 EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
11735 if (inode_size & (inode_size - 1)) {
11736 pctx.num = inode_size;
11737 pctx.str = "inode_size";
11738 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
11739 ctx->flags |= E2F_FLAG_ABORT;
11740 return;
11741 }
11742
11743 if (!ctx->num_blocks) {
11744 pctx.errcode = e2fsck_get_device_size(ctx);
11745 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
11746 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
11747 ctx->flags |= E2F_FLAG_ABORT;
11748 return;
11749 }
11750 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
11751 (ctx->num_blocks < sb->s_blocks_count)) {
11752 pctx.blk = sb->s_blocks_count;
11753 pctx.blk2 = ctx->num_blocks;
11754 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
11755 ctx->flags |= E2F_FLAG_ABORT;
11756 return;
11757 }
11758 }
11759 }
11760
11761 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
11762 pctx.blk = EXT2_BLOCK_SIZE(sb);
11763 pctx.blk2 = EXT2_FRAG_SIZE(sb);
11764 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
11765 ctx->flags |= E2F_FLAG_ABORT;
11766 return;
11767 }
11768
11769 should_be = sb->s_frags_per_group >>
11770 (sb->s_log_block_size - sb->s_log_frag_size);
11771 if (sb->s_blocks_per_group != should_be) {
11772 pctx.blk = sb->s_blocks_per_group;
11773 pctx.blk2 = should_be;
11774 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
11775 ctx->flags |= E2F_FLAG_ABORT;
11776 return;
11777 }
11778
11779 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
11780 if (sb->s_first_data_block != should_be) {
11781 pctx.blk = sb->s_first_data_block;
11782 pctx.blk2 = should_be;
11783 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
11784 ctx->flags |= E2F_FLAG_ABORT;
11785 return;
11786 }
11787
11788 should_be = sb->s_inodes_per_group * fs->group_desc_count;
11789 if (sb->s_inodes_count != should_be) {
11790 pctx.ino = sb->s_inodes_count;
11791 pctx.ino2 = should_be;
11792 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
11793 sb->s_inodes_count = should_be;
11794 ext2fs_mark_super_dirty(fs);
11795 }
11796 }
11797
11798
11799
11800
11801 first_block = sb->s_first_data_block;
11802 last_block = first_block + blocks_per_group;
11803
11804 for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
11805 pctx.group = i;
11806
11807 if (i == fs->group_desc_count - 1)
11808 last_block = sb->s_blocks_count;
11809 if ((gd->bg_block_bitmap < first_block) ||
11810 (gd->bg_block_bitmap >= last_block)) {
11811 pctx.blk = gd->bg_block_bitmap;
11812 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
11813 gd->bg_block_bitmap = 0;
11814 }
11815 if (gd->bg_block_bitmap == 0) {
11816 ctx->invalid_block_bitmap_flag[i]++;
11817 ctx->invalid_bitmaps++;
11818 }
11819 if ((gd->bg_inode_bitmap < first_block) ||
11820 (gd->bg_inode_bitmap >= last_block)) {
11821 pctx.blk = gd->bg_inode_bitmap;
11822 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
11823 gd->bg_inode_bitmap = 0;
11824 }
11825 if (gd->bg_inode_bitmap == 0) {
11826 ctx->invalid_inode_bitmap_flag[i]++;
11827 ctx->invalid_bitmaps++;
11828 }
11829 if ((gd->bg_inode_table < first_block) ||
11830 ((gd->bg_inode_table +
11831 fs->inode_blocks_per_group - 1) >= last_block)) {
11832 pctx.blk = gd->bg_inode_table;
11833 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
11834 gd->bg_inode_table = 0;
11835 }
11836 if (gd->bg_inode_table == 0) {
11837 ctx->invalid_inode_table_flag[i]++;
11838 ctx->invalid_bitmaps++;
11839 }
11840 free_blocks += gd->bg_free_blocks_count;
11841 free_inodes += gd->bg_free_inodes_count;
11842 first_block += sb->s_blocks_per_group;
11843 last_block += sb->s_blocks_per_group;
11844
11845 if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
11846 (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
11847 (gd->bg_used_dirs_count > sb->s_inodes_per_group))
11848 ext2fs_unmark_valid(fs);
11849
11850 }
11851
11852
11853
11854
11855
11856
11857
11858
11859 if ((free_blocks != sb->s_free_blocks_count) ||
11860 (free_inodes != sb->s_free_inodes_count)) {
11861 if (ctx->options & E2F_OPT_READONLY)
11862 ext2fs_unmark_valid(fs);
11863 else {
11864 sb->s_free_blocks_count = free_blocks;
11865 sb->s_free_inodes_count = free_inodes;
11866 ext2fs_mark_super_dirty(fs);
11867 }
11868 }
11869
11870 if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
11871 (sb->s_free_inodes_count > sb->s_inodes_count))
11872 ext2fs_unmark_valid(fs);
11873
11874
11875
11876
11877
11878
11879 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
11880 sb->s_state &= ~EXT2_VALID_FS;
11881 ext2fs_mark_super_dirty(fs);
11882 }
11883
11884 clear_problem_context(&pctx);
11885
11886
11887
11888
11889 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
11890 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
11891 uuid_generate(sb->s_uuid);
11892 ext2fs_mark_super_dirty(fs);
11893 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
11894 }
11895 }
11896
11897
11898
11899
11900
11901 if (!(ctx->options & E2F_OPT_READONLY) &&
11902 fs->super->s_creator_os == EXT2_OS_HURD &&
11903 (fs->super->s_feature_incompat &
11904 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
11905 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
11906 fs->super->s_feature_incompat &=
11907 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
11908 ext2fs_mark_super_dirty(fs);
11909
11910 }
11911 }
11912
11913
11914
11915
11916
11917
11918
11919 if (!(ctx->options & E2F_OPT_READONLY) &&
11920 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
11921 (fs->super->s_feature_compat ||
11922 fs->super->s_feature_ro_compat ||
11923 fs->super->s_feature_incompat) &&
11924 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
11925 ext2fs_update_dynamic_rev(fs);
11926 ext2fs_mark_super_dirty(fs);
11927 }
11928
11929 check_resize_inode(ctx);
11930
11931
11932
11933
11934 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
11935 fs->super->s_state &= ~EXT2_VALID_FS;
11936 ext2fs_mark_super_dirty(fs);
11937 }
11938
11939
11940
11941
11942 e2fsck_move_ext3_journal(ctx);
11943}
11944
11945
11946
11947
11948
11949#ifdef ENABLE_SWAPFS
11950
11951struct swap_block_struct {
11952 ext2_ino_t ino;
11953 int isdir;
11954 errcode_t errcode;
11955 char *dir_buf;
11956 struct ext2_inode *inode;
11957};
11958
11959
11960
11961
11962
11963
11964static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
11965 void *priv_data)
11966{
11967 errcode_t retval;
11968
11969 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
11970
11971 if (sb->isdir && (blockcnt >= 0) && *block_nr) {
11972 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
11973 if (retval) {
11974 sb->errcode = retval;
11975 return BLOCK_ABORT;
11976 }
11977 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
11978 if (retval) {
11979 sb->errcode = retval;
11980 return BLOCK_ABORT;
11981 }
11982 }
11983 if (blockcnt >= 0) {
11984 if (blockcnt < EXT2_NDIR_BLOCKS)
11985 return 0;
11986 return BLOCK_CHANGED;
11987 }
11988 if (blockcnt == BLOCK_COUNT_IND) {
11989 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
11990 return 0;
11991 return BLOCK_CHANGED;
11992 }
11993 if (blockcnt == BLOCK_COUNT_DIND) {
11994 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
11995 return 0;
11996 return BLOCK_CHANGED;
11997 }
11998 if (blockcnt == BLOCK_COUNT_TIND) {
11999 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
12000 return 0;
12001 return BLOCK_CHANGED;
12002 }
12003 return BLOCK_CHANGED;
12004}
12005
12006
12007
12008
12009
12010static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
12011 struct ext2_inode *inode)
12012{
12013 errcode_t retval;
12014 struct swap_block_struct sb;
12015
12016 sb.ino = ino;
12017 sb.inode = inode;
12018 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
12019 sb.errcode = 0;
12020 sb.isdir = 0;
12021 if (LINUX_S_ISDIR(inode->i_mode))
12022 sb.isdir = 1;
12023
12024 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
12025 swap_block, &sb);
12026 if (retval) {
12027 bb_error_msg(_("while calling ext2fs_block_iterate"));
12028 ctx->flags |= E2F_FLAG_ABORT;
12029 return;
12030 }
12031 if (sb.errcode) {
12032 bb_error_msg(_("while calling iterator function"));
12033 ctx->flags |= E2F_FLAG_ABORT;
12034 return;
12035 }
12036}
12037
12038static void swap_inodes(e2fsck_t ctx)
12039{
12040 ext2_filsys fs = ctx->fs;
12041 dgrp_t group;
12042 unsigned int i;
12043 ext2_ino_t ino = 1;
12044 char *buf, *block_buf;
12045 errcode_t retval;
12046 struct ext2_inode * inode;
12047
12048 e2fsck_use_inode_shortcuts(ctx, 1);
12049
12050 retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
12051 &buf);
12052 if (retval) {
12053 bb_error_msg(_("while allocating inode buffer"));
12054 ctx->flags |= E2F_FLAG_ABORT;
12055 return;
12056 }
12057 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
12058 "block interate buffer");
12059 for (group = 0; group < fs->group_desc_count; group++) {
12060 retval = io_channel_read_blk(fs->io,
12061 fs->group_desc[group].bg_inode_table,
12062 fs->inode_blocks_per_group, buf);
12063 if (retval) {
12064 bb_error_msg(_("while reading inode table (group %d)"),
12065 group);
12066 ctx->flags |= E2F_FLAG_ABORT;
12067 return;
12068 }
12069 inode = (struct ext2_inode *) buf;
12070 for (i=0; i < fs->super->s_inodes_per_group;
12071 i++, ino++, inode++) {
12072 ctx->stashed_ino = ino;
12073 ctx->stashed_inode = inode;
12074
12075 if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
12076 ext2fs_swap_inode(fs, inode, inode, 0);
12077
12078
12079
12080
12081 if (inode->i_links_count == 0)
12082 continue;
12083
12084 if (LINUX_S_ISDIR(inode->i_mode) ||
12085 ((inode->i_block[EXT2_IND_BLOCK] ||
12086 inode->i_block[EXT2_DIND_BLOCK] ||
12087 inode->i_block[EXT2_TIND_BLOCK]) &&
12088 ext2fs_inode_has_valid_blocks(inode)))
12089 swap_inode_blocks(ctx, ino, block_buf, inode);
12090
12091 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
12092 return;
12093
12094 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
12095 ext2fs_swap_inode(fs, inode, inode, 1);
12096 }
12097 retval = io_channel_write_blk(fs->io,
12098 fs->group_desc[group].bg_inode_table,
12099 fs->inode_blocks_per_group, buf);
12100 if (retval) {
12101 bb_error_msg(_("while writing inode table (group %d)"),
12102 group);
12103 ctx->flags |= E2F_FLAG_ABORT;
12104 return;
12105 }
12106 }
12107 ext2fs_free_mem(&buf);
12108 ext2fs_free_mem(&block_buf);
12109 e2fsck_use_inode_shortcuts(ctx, 0);
12110 ext2fs_flush_icache(fs);
12111}
12112
12113#if defined(__powerpc__) && BB_BIG_ENDIAN
12114
12115
12116
12117
12118
12119
12120
12121
12122
12123#define EXT2_BIG_ENDIAN_BITMAPS
12124#endif
12125
12126#ifdef EXT2_BIG_ENDIAN_BITMAPS
12127static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
12128{
12129 __u32 *p = (__u32 *) bmap->bitmap;
12130 int n, nbytes = (bmap->end - bmap->start + 7) / 8;
12131
12132 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
12133 *p = ext2fs_swab32(*p);
12134}
12135#endif
12136
12137
12138#ifdef ENABLE_SWAPFS
12139static void swap_filesys(e2fsck_t ctx)
12140{
12141 ext2_filsys fs = ctx->fs;
12142 if (!(ctx->options & E2F_OPT_PREEN))
12143 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
12144
12145
12146
12147 if (fs->super->s_mnt_count) {
12148 fprintf(stderr, _("%s: the filesystem must be freshly "
12149 "checked using fsck\n"
12150 "and not mounted before trying to "
12151 "byte-swap it.\n"), ctx->device_name);
12152 ctx->flags |= E2F_FLAG_ABORT;
12153 return;
12154 }
12155 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
12156 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
12157 EXT2_FLAG_SWAP_BYTES_WRITE);
12158 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
12159 } else {
12160 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
12161 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
12162 }
12163 swap_inodes(ctx);
12164 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
12165 return;
12166 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
12167 fs->flags |= EXT2_FLAG_SWAP_BYTES;
12168 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
12169 EXT2_FLAG_SWAP_BYTES_WRITE);
12170
12171#ifdef EXT2_BIG_ENDIAN_BITMAPS
12172 e2fsck_read_bitmaps(ctx);
12173 ext2fs_swap_bitmap(fs->inode_map);
12174 ext2fs_swap_bitmap(fs->block_map);
12175 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
12176#endif
12177 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
12178 ext2fs_flush(fs);
12179 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
12180}
12181#endif
12182
12183#endif
12184
12185
12186
12187
12188
12189
12190void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
12191 const char *description)
12192{
12193 void *ret;
12194 char buf[256];
12195
12196 ret = xzalloc(size);
12197 return ret;
12198}
12199
12200static char *string_copy(const char *str, int len)
12201{
12202 char *ret;
12203
12204 if (!str)
12205 return NULL;
12206 if (!len)
12207 len = strlen(str);
12208 ret = xmalloc(len+1);
12209 strncpy(ret, str, len);
12210 ret[len] = 0;
12211 return ret;
12212}
12213
12214#ifndef HAVE_CONIO_H
12215static int read_a_char(void)
12216{
12217 char c;
12218 int r;
12219 int fail = 0;
12220
12221 while (1) {
12222 if (e2fsck_global_ctx &&
12223 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
12224 return 3;
12225 }
12226 r = read(0, &c, 1);
12227 if (r == 1)
12228 return c;
12229 if (fail++ > 100)
12230 break;
12231 }
12232 return EOF;
12233}
12234#endif
12235
12236static int ask_yn(const char * string, int def)
12237{
12238 int c;
12239 const char *defstr;
12240 static const char short_yes[] = "yY";
12241 static const char short_no[] = "nN";
12242
12243#ifdef HAVE_TERMIOS_H
12244 struct termios termios, tmp;
12245
12246 tcgetattr (0, &termios);
12247 tmp = termios;
12248 tmp.c_lflag &= ~(ICANON | ECHO);
12249 tmp.c_cc[VMIN] = 1;
12250 tmp.c_cc[VTIME] = 0;
12251 tcsetattr_stdin_TCSANOW(&tmp);
12252#endif
12253
12254 if (def == 1)
12255 defstr = "<y>";
12256 else if (def == 0)
12257 defstr = "<n>";
12258 else
12259 defstr = " (y/n)";
12260 printf("%s%s? ", string, defstr);
12261 while (1) {
12262 fflush (stdout);
12263 if ((c = read_a_char()) == EOF)
12264 break;
12265 if (c == 3) {
12266#ifdef HAVE_TERMIOS_H
12267 tcsetattr_stdin_TCSANOW(&termios);
12268#endif
12269 if (e2fsck_global_ctx &&
12270 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
12271 puts("\n");
12272 longjmp(e2fsck_global_ctx->abort_loc, 1);
12273 }
12274 puts(_("cancelled!\n"));
12275 return 0;
12276 }
12277 if (strchr(short_yes, (char) c)) {
12278 def = 1;
12279 break;
12280 }
12281 else if (strchr(short_no, (char) c)) {
12282 def = 0;
12283 break;
12284 }
12285 else if ((c == ' ' || c == '\n') && (def != -1))
12286 break;
12287 }
12288 if (def)
12289 puts("yes\n");
12290 else
12291 puts ("no\n");
12292#ifdef HAVE_TERMIOS_H
12293 tcsetattr_stdin_TCSANOW(&termios);
12294#endif
12295 return def;
12296}
12297
12298int ask (e2fsck_t ctx, const char * string, int def)
12299{
12300 if (ctx->options & E2F_OPT_NO) {
12301 printf(_("%s? no\n\n"), string);
12302 return 0;
12303 }
12304 if (ctx->options & E2F_OPT_YES) {
12305 printf(_("%s? yes\n\n"), string);
12306 return 1;
12307 }
12308 if (ctx->options & E2F_OPT_PREEN) {
12309 printf("%s? %s\n\n", string, def ? _("yes") : _("no"));
12310 return def;
12311 }
12312 return ask_yn(string, def);
12313}
12314
12315void e2fsck_read_bitmaps(e2fsck_t ctx)
12316{
12317 ext2_filsys fs = ctx->fs;
12318 errcode_t retval;
12319
12320 if (ctx->invalid_bitmaps) {
12321 bb_error_msg(_("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
12322 ctx->device_name);
12323 bb_error_msg_and_die(0);
12324 }
12325
12326 ehandler_operation(_("reading inode and block bitmaps"));
12327 retval = ext2fs_read_bitmaps(fs);
12328 ehandler_operation(0);
12329 if (retval) {
12330 bb_error_msg(_("while retrying to read bitmaps for %s"),
12331 ctx->device_name);
12332 bb_error_msg_and_die(0);
12333 }
12334}
12335
12336static void e2fsck_write_bitmaps(e2fsck_t ctx)
12337{
12338 ext2_filsys fs = ctx->fs;
12339 errcode_t retval;
12340
12341 if (ext2fs_test_bb_dirty(fs)) {
12342 ehandler_operation(_("writing block bitmaps"));
12343 retval = ext2fs_write_block_bitmap(fs);
12344 ehandler_operation(0);
12345 if (retval) {
12346 bb_error_msg(_("while retrying to write block bitmaps for %s"),
12347 ctx->device_name);
12348 bb_error_msg_and_die(0);
12349 }
12350 }
12351
12352 if (ext2fs_test_ib_dirty(fs)) {
12353 ehandler_operation(_("writing inode bitmaps"));
12354 retval = ext2fs_write_inode_bitmap(fs);
12355 ehandler_operation(0);
12356 if (retval) {
12357 bb_error_msg(_("while retrying to write inode bitmaps for %s"),
12358 ctx->device_name);
12359 bb_error_msg_and_die(0);
12360 }
12361 }
12362}
12363
12364void preenhalt(e2fsck_t ctx)
12365{
12366 ext2_filsys fs = ctx->fs;
12367
12368 if (!(ctx->options & E2F_OPT_PREEN))
12369 return;
12370 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
12371 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
12372 ctx->device_name);
12373 if (fs != NULL) {
12374 fs->super->s_state |= EXT2_ERROR_FS;
12375 ext2fs_mark_super_dirty(fs);
12376 ext2fs_close(fs);
12377 }
12378 exit(EXIT_UNCORRECTED);
12379}
12380
12381void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
12382 struct ext2_inode * inode, const char *proc)
12383{
12384 int retval;
12385
12386 retval = ext2fs_read_inode(ctx->fs, ino, inode);
12387 if (retval) {
12388 bb_error_msg(_("while reading inode %ld in %s"), ino, proc);
12389 bb_error_msg_and_die(0);
12390 }
12391}
12392
12393extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
12394 struct ext2_inode * inode, int bufsize,
12395 const char *proc)
12396{
12397 int retval;
12398
12399 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
12400 if (retval) {
12401 bb_error_msg(_("while writing inode %ld in %s"), ino, proc);
12402 bb_error_msg_and_die(0);
12403 }
12404}
12405
12406extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
12407 struct ext2_inode * inode, const char *proc)
12408{
12409 int retval;
12410
12411 retval = ext2fs_write_inode(ctx->fs, ino, inode);
12412 if (retval) {
12413 bb_error_msg(_("while writing inode %ld in %s"), ino, proc);
12414 bb_error_msg_and_die(0);
12415 }
12416}
12417
12418blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
12419 io_manager manager)
12420{
12421 struct ext2_super_block *sb;
12422 io_channel io = NULL;
12423 void *buf = NULL;
12424 int blocksize;
12425 blk_t superblock, ret_sb = 8193;
12426
12427 if (fs && fs->super) {
12428 ret_sb = (fs->super->s_blocks_per_group +
12429 fs->super->s_first_data_block);
12430 if (ctx) {
12431 ctx->superblock = ret_sb;
12432 ctx->blocksize = fs->blocksize;
12433 }
12434 return ret_sb;
12435 }
12436
12437 if (ctx) {
12438 if (ctx->blocksize) {
12439 ret_sb = ctx->blocksize * 8;
12440 if (ctx->blocksize == 1024)
12441 ret_sb++;
12442 ctx->superblock = ret_sb;
12443 return ret_sb;
12444 }
12445 ctx->superblock = ret_sb;
12446 ctx->blocksize = 1024;
12447 }
12448
12449 if (!name || !manager)
12450 goto cleanup;
12451
12452 if (manager->open(name, 0, &io) != 0)
12453 goto cleanup;
12454
12455 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
12456 goto cleanup;
12457 sb = (struct ext2_super_block *) buf;
12458
12459 for (blocksize = EXT2_MIN_BLOCK_SIZE;
12460 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
12461 superblock = blocksize*8;
12462 if (blocksize == 1024)
12463 superblock++;
12464 io_channel_set_blksize(io, blocksize);
12465 if (io_channel_read_blk(io, superblock,
12466 -SUPERBLOCK_SIZE, buf))
12467 continue;
12468#if BB_BIG_ENDIAN
12469 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
12470 ext2fs_swap_super(sb);
12471#endif
12472 if (sb->s_magic == EXT2_SUPER_MAGIC) {
12473 ret_sb = superblock;
12474 if (ctx) {
12475 ctx->superblock = superblock;
12476 ctx->blocksize = blocksize;
12477 }
12478 break;
12479 }
12480 }
12481
12482cleanup:
12483 if (io)
12484 io_channel_close(io);
12485 ext2fs_free_mem(&buf);
12486 return ret_sb;
12487}
12488
12489
12490
12491
12492
12493
12494typedef void (*pass_t)(e2fsck_t ctx);
12495
12496static const pass_t e2fsck_passes[] = {
12497 e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
12498 e2fsck_pass5, 0 };
12499
12500#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
12501
12502static int e2fsck_run(e2fsck_t ctx)
12503{
12504 int i;
12505 pass_t e2fsck_pass;
12506
12507 if (setjmp(ctx->abort_loc)) {
12508 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
12509 return (ctx->flags & E2F_FLAG_RUN_RETURN);
12510 }
12511 ctx->flags |= E2F_FLAG_SETJMP_OK;
12512
12513 for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
12514 if (ctx->flags & E2F_FLAG_RUN_RETURN)
12515 break;
12516 e2fsck_pass(ctx);
12517 if (ctx->progress)
12518 (void) (ctx->progress)(ctx, 0, 0, 0);
12519 }
12520 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
12521
12522 if (ctx->flags & E2F_FLAG_RUN_RETURN)
12523 return (ctx->flags & E2F_FLAG_RUN_RETURN);
12524 return 0;
12525}
12526
12527
12528
12529
12530
12531
12532
12533
12534static int swapfs;
12535#ifdef ENABLE_SWAPFS
12536static int normalize_swapfs;
12537#endif
12538static int cflag;
12539static int show_version_only;
12540static int verbose;
12541
12542#define P_E2(singular, plural, n) n, ((n) == 1 ? singular : plural)
12543
12544static void show_stats(e2fsck_t ctx)
12545{
12546 ext2_filsys fs = ctx->fs;
12547 int inodes, inodes_used, blocks, blocks_used;
12548 int dir_links;
12549 int num_files, num_links;
12550 int frag_percent;
12551
12552 dir_links = 2 * ctx->fs_directory_count - 1;
12553 num_files = ctx->fs_total_count - dir_links;
12554 num_links = ctx->fs_links_count - dir_links;
12555 inodes = fs->super->s_inodes_count;
12556 inodes_used = (fs->super->s_inodes_count -
12557 fs->super->s_free_inodes_count);
12558 blocks = fs->super->s_blocks_count;
12559 blocks_used = (fs->super->s_blocks_count -
12560 fs->super->s_free_blocks_count);
12561
12562 frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
12563 frag_percent = (frag_percent + 5) / 10;
12564
12565 if (!verbose) {
12566 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
12567 ctx->device_name, inodes_used, inodes,
12568 frag_percent / 10, frag_percent % 10,
12569 blocks_used, blocks);
12570 return;
12571 }
12572 printf("\n%8d inode%s used (%d%%)\n", P_E2("", "s", inodes_used),
12573 100 * inodes_used / inodes);
12574 printf("%8d non-contiguous inode%s (%0d.%d%%)\n",
12575 P_E2("", "s", ctx->fs_fragmented),
12576 frag_percent / 10, frag_percent % 10);
12577 printf(_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"),
12578 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
12579 printf("%8d block%s used (%d%%)\n", P_E2("", "s", blocks_used),
12580 (int) ((long long) 100 * blocks_used / blocks));
12581 printf("%8d large file%s\n", P_E2("", "s", ctx->large_files));
12582 printf("\n%8d regular file%s\n", P_E2("", "s", ctx->fs_regular_count));
12583 printf("%8d director%s\n", P_E2("y", "ies", ctx->fs_directory_count));
12584 printf("%8d character device file%s\n", P_E2("", "s", ctx->fs_chardev_count));
12585 printf("%8d block device file%s\n", P_E2("", "s", ctx->fs_blockdev_count));
12586 printf("%8d fifo%s\n", P_E2("", "s", ctx->fs_fifo_count));
12587 printf("%8d link%s\n", P_E2("", "s", ctx->fs_links_count - dir_links));
12588 printf("%8d symbolic link%s", P_E2("", "s", ctx->fs_symlinks_count));
12589 printf(" (%d fast symbolic link%s)\n", P_E2("", "s", ctx->fs_fast_symlinks_count));
12590 printf("%8d socket%s--------\n\n", P_E2("", "s", ctx->fs_sockets_count));
12591 printf("%8d file%s\n", P_E2("", "s", ctx->fs_total_count - dir_links));
12592}
12593
12594static void check_mount(e2fsck_t ctx)
12595{
12596 errcode_t retval;
12597 int cont;
12598
12599 retval = ext2fs_check_if_mounted(ctx->filesystem_name,
12600 &ctx->mount_flags);
12601 if (retval) {
12602 bb_error_msg(_("while determining whether %s is mounted"),
12603 ctx->filesystem_name);
12604 return;
12605 }
12606
12607
12608
12609
12610
12611 if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) ||
12612 ((ctx->mount_flags & EXT2_MF_ISROOT) &&
12613 (ctx->mount_flags & EXT2_MF_READONLY)))
12614 return;
12615
12616 if (ctx->options & E2F_OPT_READONLY) {
12617 printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name);
12618 return;
12619 }
12620
12621 printf(_("%s is mounted. "), ctx->filesystem_name);
12622 if (!ctx->interactive)
12623 bb_error_msg_and_die(_("can't continue, aborting"));
12624 printf(_("\n\n\007\007\007\007WARNING!!! "
12625 "Running e2fsck on a mounted filesystem may cause\n"
12626 "SEVERE filesystem damage.\007\007\007\n\n"));
12627 cont = ask_yn(_("Do you really want to continue"), -1);
12628 if (!cont) {
12629 printf(_("check aborted.\n"));
12630 exit(0);
12631 }
12632}
12633
12634static int is_on_batt(void)
12635{
12636 FILE *f;
12637 DIR *d;
12638 char tmp[80], tmp2[80], fname[80];
12639 unsigned int acflag;
12640 struct dirent* de;
12641
12642 f = fopen_for_read("/proc/apm");
12643 if (f) {
12644 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
12645 acflag = 1;
12646 fclose(f);
12647 return (acflag != 1);
12648 }
12649 d = opendir("/proc/acpi/ac_adapter");
12650 if (d) {
12651 while ((de=readdir(d)) != NULL) {
12652 if (!strncmp(".", de->d_name, 1))
12653 continue;
12654 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state",
12655 de->d_name);
12656 f = fopen_for_read(fname);
12657 if (!f)
12658 continue;
12659 if (fscanf(f, "%s %s", tmp2, tmp) != 2)
12660 tmp[0] = 0;
12661 fclose(f);
12662 if (strncmp(tmp, "off-line", 8) == 0) {
12663 closedir(d);
12664 return 1;
12665 }
12666 }
12667 closedir(d);
12668 }
12669 return 0;
12670}
12671
12672
12673
12674
12675
12676
12677static void check_if_skip(e2fsck_t ctx)
12678{
12679 ext2_filsys fs = ctx->fs;
12680 const char *reason = NULL;
12681 unsigned int reason_arg = 0;
12682 long next_check;
12683 int batt = is_on_batt();
12684 time_t now = time(NULL);
12685
12686 if ((ctx->options & E2F_OPT_FORCE) || cflag || swapfs)
12687 return;
12688
12689 if ((fs->super->s_state & EXT2_ERROR_FS) ||
12690 !ext2fs_test_valid(fs))
12691 reason = _(" contains a file system with errors");
12692 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
12693 reason = _(" was not cleanly unmounted");
12694 else if ((fs->super->s_max_mnt_count > 0) &&
12695 (fs->super->s_mnt_count >=
12696 (unsigned) fs->super->s_max_mnt_count)) {
12697 reason = _(" has been mounted %u times without being checked");
12698 reason_arg = fs->super->s_mnt_count;
12699 if (batt && (fs->super->s_mnt_count <
12700 (unsigned) fs->super->s_max_mnt_count*2))
12701 reason = 0;
12702 } else if (fs->super->s_checkinterval &&
12703 ((now - fs->super->s_lastcheck) >=
12704 fs->super->s_checkinterval)) {
12705 reason = _(" has gone %u days without being checked");
12706 reason_arg = (now - fs->super->s_lastcheck)/(3600*24);
12707 if (batt && ((now - fs->super->s_lastcheck) <
12708 fs->super->s_checkinterval*2))
12709 reason = 0;
12710 }
12711 if (reason) {
12712 fputs(ctx->device_name, stdout);
12713 printf(reason, reason_arg);
12714 fputs(_(", check forced.\n"), stdout);
12715 return;
12716 }
12717 printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name,
12718 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
12719 fs->super->s_inodes_count,
12720 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
12721 fs->super->s_blocks_count);
12722 next_check = 100000;
12723 if (fs->super->s_max_mnt_count > 0) {
12724 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count;
12725 if (next_check <= 0)
12726 next_check = 1;
12727 }
12728 if (fs->super->s_checkinterval &&
12729 ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval))
12730 next_check = 1;
12731 if (next_check <= 5) {
12732 if (next_check == 1)
12733 fputs(_(" (check after next mount)"), stdout);
12734 else
12735 printf(_(" (check in %ld mounts)"), next_check);
12736 }
12737 bb_putchar('\n');
12738 ext2fs_close(fs);
12739 ctx->fs = NULL;
12740 e2fsck_free_context(ctx);
12741 exit(EXIT_OK);
12742}
12743
12744
12745
12746
12747struct percent_tbl {
12748 int max_pass;
12749 int table[32];
12750};
12751static const struct percent_tbl e2fsck_tbl = {
12752 5, { 0, 70, 90, 92, 95, 100 }
12753};
12754
12755static char bar[128], spaces[128];
12756
12757static float calc_percent(const struct percent_tbl *tbl, int pass, int curr,
12758 int max)
12759{
12760 float percent;
12761
12762 if (pass <= 0)
12763 return 0.0;
12764 if (pass > tbl->max_pass || max == 0)
12765 return 100.0;
12766 percent = ((float) curr) / ((float) max);
12767 return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
12768 + tbl->table[pass-1]);
12769}
12770
12771void e2fsck_clear_progbar(e2fsck_t ctx)
12772{
12773 if (!(ctx->flags & E2F_FLAG_PROG_BAR))
12774 return;
12775
12776 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80),
12777 ctx->stop_meta);
12778 fflush(stdout);
12779 ctx->flags &= ~E2F_FLAG_PROG_BAR;
12780}
12781
12782int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
12783 unsigned int dpynum)
12784{
12785 static const char spinner[] = "\\|/-";
12786 int i;
12787 unsigned int tick;
12788 struct timeval tv;
12789 int dpywidth;
12790 int fixed_percent;
12791
12792 if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
12793 return 0;
12794
12795
12796
12797
12798
12799
12800 fixed_percent = (int) ((10 * percent) + 0.5);
12801 if (ctx->progress_last_percent == fixed_percent)
12802 return 0;
12803 ctx->progress_last_percent = fixed_percent;
12804
12805
12806
12807
12808
12809
12810 gettimeofday(&tv, NULL);
12811 tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8));
12812 if ((tick == ctx->progress_last_time) &&
12813 (fixed_percent != 0) && (fixed_percent != 1000))
12814 return 0;
12815 ctx->progress_last_time = tick;
12816
12817
12818
12819
12820
12821 ctx->progress_pos = (ctx->progress_pos+1) & 3;
12822 ctx->flags |= E2F_FLAG_PROG_BAR;
12823
12824 dpywidth = 66 - strlen(label);
12825 dpywidth = 8 * (dpywidth / 8);
12826 if (dpynum)
12827 dpywidth -= 8;
12828
12829 i = ((percent * dpywidth) + 50) / 100;
12830 printf("%s%s: |%s%s", ctx->start_meta, label,
12831 bar + (sizeof(bar) - (i+1)),
12832 spaces + (sizeof(spaces) - (dpywidth - i + 1)));
12833 if (fixed_percent == 1000)
12834 bb_putchar('|');
12835 else
12836 bb_putchar(spinner[ctx->progress_pos & 3]);
12837 printf(" %4.1f%% ", percent);
12838 if (dpynum)
12839 printf("%u\r", dpynum);
12840 else
12841 fputs(" \r", stdout);
12842 fputs(ctx->stop_meta, stdout);
12843
12844 if (fixed_percent == 1000)
12845 e2fsck_clear_progbar(ctx);
12846 fflush(stdout);
12847
12848 return 0;
12849}
12850
12851static int e2fsck_update_progress(e2fsck_t ctx, int pass,
12852 unsigned long cur, unsigned long max)
12853{
12854 char buf[80];
12855 float percent;
12856
12857 if (pass == 0)
12858 return 0;
12859
12860 if (ctx->progress_fd) {
12861 sprintf(buf, "%d %lu %lu\n", pass, cur, max);
12862 xwrite_str(ctx->progress_fd, buf);
12863 } else {
12864 percent = calc_percent(&e2fsck_tbl, pass, cur, max);
12865 e2fsck_simple_progress(ctx, ctx->device_name,
12866 percent, 0);
12867 }
12868 return 0;
12869}
12870
12871static void reserve_stdio_fds(void)
12872{
12873 int fd;
12874
12875 while (1) {
12876 fd = open(bb_dev_null, O_RDWR);
12877 if (fd > 2)
12878 break;
12879 if (fd < 0) {
12880 fprintf(stderr, _("ERROR: Cannot open "
12881 "/dev/null (%s)\n"),
12882 strerror(errno));
12883 break;
12884 }
12885 }
12886 close(fd);
12887}
12888
12889static void signal_progress_on(int sig FSCK_ATTR((unused)))
12890{
12891 e2fsck_t ctx = e2fsck_global_ctx;
12892
12893 if (!ctx)
12894 return;
12895
12896 ctx->progress = e2fsck_update_progress;
12897 ctx->progress_fd = 0;
12898}
12899
12900static void signal_progress_off(int sig FSCK_ATTR((unused)))
12901{
12902 e2fsck_t ctx = e2fsck_global_ctx;
12903
12904 if (!ctx)
12905 return;
12906
12907 e2fsck_clear_progbar(ctx);
12908 ctx->progress = 0;
12909}
12910
12911static void signal_cancel(int sig FSCK_ATTR((unused)))
12912{
12913 e2fsck_t ctx = e2fsck_global_ctx;
12914
12915 if (!ctx)
12916 exit(FSCK_CANCELED);
12917
12918 ctx->flags |= E2F_FLAG_CANCEL;
12919}
12920
12921static void parse_extended_opts(e2fsck_t ctx, const char *opts)
12922{
12923 char *buf, *token, *next, *p, *arg;
12924 int ea_ver;
12925 int extended_usage = 0;
12926
12927 buf = string_copy(opts, 0);
12928 for (token = buf; token && *token; token = next) {
12929 p = strchr(token, ',');
12930 next = 0;
12931 if (p) {
12932 *p = 0;
12933 next = p+1;
12934 }
12935 arg = strchr(token, '=');
12936 if (arg) {
12937 *arg = 0;
12938 arg++;
12939 }
12940 if (strcmp(token, "ea_ver") == 0) {
12941 if (!arg) {
12942 extended_usage++;
12943 continue;
12944 }
12945 ea_ver = strtoul(arg, &p, 0);
12946 if (*p ||
12947 ((ea_ver != 1) && (ea_ver != 2))) {
12948 fprintf(stderr,
12949 _("Invalid EA version.\n"));
12950 extended_usage++;
12951 continue;
12952 }
12953 ctx->ext_attr_ver = ea_ver;
12954 } else {
12955 fprintf(stderr, _("Unknown extended option: %s\n"),
12956 token);
12957 extended_usage++;
12958 }
12959 }
12960 if (extended_usage) {
12961 bb_error_msg_and_die(
12962 "Extended options are separated by commas, "
12963 "and may take an argument which\n"
12964 "is set off by an equals ('=') sign. "
12965 "Valid extended options are:\n"
12966 "\tea_ver=<ea_version (1 or 2)>\n\n");
12967 }
12968}
12969
12970
12971static errcode_t PRS(int argc, char **argv, e2fsck_t *ret_ctx)
12972{
12973 int flush = 0;
12974 int c, fd;
12975 e2fsck_t ctx;
12976 errcode_t retval;
12977 struct sigaction sa;
12978 char *extended_opts = 0;
12979
12980 retval = e2fsck_allocate_context(&ctx);
12981 if (retval)
12982 return retval;
12983
12984 *ret_ctx = ctx;
12985
12986 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
12987 setvbuf(stderr, NULL, _IONBF, BUFSIZ);
12988 if (isatty(0) && isatty(1)) {
12989 ctx->interactive = 1;
12990 } else {
12991 ctx->start_meta[0] = '\001';
12992 ctx->stop_meta[0] = '\002';
12993 }
12994 memset(bar, '=', sizeof(bar)-1);
12995 memset(spaces, ' ', sizeof(spaces)-1);
12996 blkid_get_cache(&ctx->blkid, NULL);
12997
12998 if (argc && *argv)
12999 ctx->program_name = *argv;
13000 else
13001 ctx->program_name = "e2fsck";
13002 while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
13003 switch (c) {
13004 case 'C':
13005 ctx->progress = e2fsck_update_progress;
13006 ctx->progress_fd = atoi(optarg);
13007 if (!ctx->progress_fd)
13008 break;
13009
13010 fd = dup(ctx->progress_fd);
13011 if (fd < 0) {
13012 fprintf(stderr,
13013 _("Error validating file descriptor %d: %s\n"),
13014 ctx->progress_fd,
13015 error_message(errno));
13016 bb_error_msg_and_die(_("Invalid completion information file descriptor"));
13017 } else
13018 close(fd);
13019 break;
13020 case 'D':
13021 ctx->options |= E2F_OPT_COMPRESS_DIRS;
13022 break;
13023 case 'E':
13024 extended_opts = optarg;
13025 break;
13026 case 'p':
13027 case 'a':
13028 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) {
13029 conflict_opt:
13030 bb_error_msg_and_die(_("only one the options -p/-a, -n or -y may be specified"));
13031 }
13032 ctx->options |= E2F_OPT_PREEN;
13033 break;
13034 case 'n':
13035 if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
13036 goto conflict_opt;
13037 ctx->options |= E2F_OPT_NO;
13038 break;
13039 case 'y':
13040 if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO))
13041 goto conflict_opt;
13042 ctx->options |= E2F_OPT_YES;
13043 break;
13044 case 't':
13045
13046 fprintf(stderr, _("The -t option is not "
13047 "supported on this version of e2fsck.\n"));
13048 break;
13049 case 'c':
13050 if (cflag++)
13051 ctx->options |= E2F_OPT_WRITECHECK;
13052 ctx->options |= E2F_OPT_CHECKBLOCKS;
13053 break;
13054 case 'r':
13055
13056 break;
13057 case 'b':
13058 ctx->use_superblock = atoi(optarg);
13059 ctx->flags |= E2F_FLAG_SB_SPECIFIED;
13060 break;
13061 case 'B':
13062 ctx->blocksize = atoi(optarg);
13063 break;
13064 case 'I':
13065 ctx->inode_buffer_blocks = atoi(optarg);
13066 break;
13067 case 'j':
13068 ctx->journal_name = string_copy(optarg, 0);
13069 break;
13070 case 'P':
13071 ctx->process_inode_size = atoi(optarg);
13072 break;
13073 case 'd':
13074 ctx->options |= E2F_OPT_DEBUG;
13075 break;
13076 case 'f':
13077 ctx->options |= E2F_OPT_FORCE;
13078 break;
13079 case 'F':
13080 flush = 1;
13081 break;
13082 case 'v':
13083 verbose = 1;
13084 break;
13085 case 'V':
13086 show_version_only = 1;
13087 break;
13088 case 'N':
13089 ctx->device_name = optarg;
13090 break;
13091#ifdef ENABLE_SWAPFS
13092 case 's':
13093 normalize_swapfs = 1;
13094 case 'S':
13095 swapfs = 1;
13096 break;
13097#else
13098 case 's':
13099 case 'S':
13100 fprintf(stderr, _("Byte-swapping filesystems "
13101 "not compiled in this version "
13102 "of e2fsck\n"));
13103 exit(1);
13104#endif
13105 default:
13106 bb_show_usage();
13107 }
13108 if (show_version_only)
13109 return 0;
13110 if (optind != argc - 1)
13111 bb_show_usage();
13112 if ((ctx->options & E2F_OPT_NO) &&
13113 !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
13114 ctx->options |= E2F_OPT_READONLY;
13115 ctx->io_options = strchr(argv[optind], '?');
13116 if (ctx->io_options)
13117 *ctx->io_options++ = 0;
13118 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
13119 if (!ctx->filesystem_name) {
13120 bb_error_msg(_("Unable to resolve '%s'"), argv[optind]);
13121 bb_error_msg_and_die(0);
13122 }
13123 if (extended_opts)
13124 parse_extended_opts(ctx, extended_opts);
13125
13126 if (flush) {
13127 fd = open(ctx->filesystem_name, O_RDONLY, 0);
13128 if (fd < 0) {
13129 bb_error_msg(_("while opening %s for flushing"),
13130 ctx->filesystem_name);
13131 bb_error_msg_and_die(0);
13132 }
13133 if ((retval = ext2fs_sync_device(fd, 1))) {
13134 bb_error_msg(_("while trying to flush %s"),
13135 ctx->filesystem_name);
13136 bb_error_msg_and_die(0);
13137 }
13138 close(fd);
13139 }
13140#ifdef ENABLE_SWAPFS
13141 if (swapfs && cflag) {
13142 fprintf(stderr, _("Incompatible options not "
13143 "allowed when byte-swapping.\n"));
13144 exit(EXIT_USAGE);
13145 }
13146#endif
13147
13148
13149
13150 memset(&sa, 0, sizeof(struct sigaction));
13151 sa.sa_handler = signal_cancel;
13152 sigaction(SIGINT, &sa, 0);
13153 sigaction(SIGTERM, &sa, 0);
13154#ifdef SA_RESTART
13155 sa.sa_flags = SA_RESTART;
13156#endif
13157 e2fsck_global_ctx = ctx;
13158 sa.sa_handler = signal_progress_on;
13159 sigaction(SIGUSR1, &sa, 0);
13160 sa.sa_handler = signal_progress_off;
13161 sigaction(SIGUSR2, &sa, 0);
13162
13163
13164 if (cflag)
13165 e2fs_set_sbin_path();
13166 return 0;
13167}
13168
13169static const char my_ver_string[] = E2FSPROGS_VERSION;
13170static const char my_ver_date[] = E2FSPROGS_DATE;
13171
13172int e2fsck_main (int argc, char **argv);
13173int e2fsck_main (int argc, char **argv)
13174{
13175 errcode_t retval;
13176 int exit_value = EXIT_OK;
13177 ext2_filsys fs = 0;
13178 io_manager io_ptr;
13179 struct ext2_super_block *sb;
13180 const char *lib_ver_date;
13181 int my_ver, lib_ver;
13182 e2fsck_t ctx;
13183 struct problem_context pctx;
13184 int flags, run_result;
13185
13186 clear_problem_context(&pctx);
13187
13188 my_ver = ext2fs_parse_version_string(my_ver_string);
13189 lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
13190 if (my_ver > lib_ver) {
13191 fprintf( stderr, _("Error: ext2fs library version "
13192 "out of date!\n"));
13193 show_version_only++;
13194 }
13195
13196 retval = PRS(argc, argv, &ctx);
13197 if (retval) {
13198 bb_error_msg(_("while trying to initialize program"));
13199 exit(EXIT_ERROR);
13200 }
13201 reserve_stdio_fds();
13202
13203 if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
13204 fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string,
13205 my_ver_date);
13206
13207 if (show_version_only) {
13208 fprintf(stderr, _("\tUsing %s, %s\n"),
13209 error_message(EXT2_ET_BASE), lib_ver_date);
13210 exit(EXIT_OK);
13211 }
13212
13213 check_mount(ctx);
13214
13215 if (!(ctx->options & E2F_OPT_PREEN) &&
13216 !(ctx->options & E2F_OPT_NO) &&
13217 !(ctx->options & E2F_OPT_YES)) {
13218 if (!ctx->interactive)
13219 bb_error_msg_and_die(_("need terminal for interactive repairs"));
13220 }
13221 ctx->superblock = ctx->use_superblock;
13222restart:
13223#ifdef CONFIG_TESTIO_DEBUG
13224 io_ptr = test_io_manager;
13225 test_io_backing_manager = unix_io_manager;
13226#else
13227 io_ptr = unix_io_manager;
13228#endif
13229 flags = 0;
13230 if ((ctx->options & E2F_OPT_READONLY) == 0)
13231 flags |= EXT2_FLAG_RW;
13232
13233 if (ctx->superblock && ctx->blocksize) {
13234 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
13235 flags, ctx->superblock, ctx->blocksize,
13236 io_ptr, &fs);
13237 } else if (ctx->superblock) {
13238 int blocksize;
13239 for (blocksize = EXT2_MIN_BLOCK_SIZE;
13240 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
13241 retval = ext2fs_open2(ctx->filesystem_name,
13242 ctx->io_options, flags,
13243 ctx->superblock, blocksize,
13244 io_ptr, &fs);
13245 if (!retval)
13246 break;
13247 }
13248 } else
13249 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
13250 flags, 0, 0, io_ptr, &fs);
13251 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
13252 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
13253 ((retval == EXT2_ET_BAD_MAGIC) ||
13254 ((retval == 0) && ext2fs_check_desc(fs)))) {
13255 if (!fs || (fs->group_desc_count > 1)) {
13256 printf(_("%s trying backup blocks...\n"),
13257 retval ? _("Couldn't find ext2 superblock,") :
13258 _("Group descriptors look bad..."));
13259 get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
13260 if (fs)
13261 ext2fs_close(fs);
13262 goto restart;
13263 }
13264 }
13265 if (retval) {
13266 bb_error_msg(_("while trying to open %s"),
13267 ctx->filesystem_name);
13268 if (retval == EXT2_ET_REV_TOO_HIGH) {
13269 printf(_("The filesystem revision is apparently "
13270 "too high for this version of e2fsck.\n"
13271 "(Or the filesystem superblock "
13272 "is corrupt)\n\n"));
13273 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
13274 } else if (retval == EXT2_ET_SHORT_READ)
13275 printf(_("Could this be a zero-length partition?\n"));
13276 else if ((retval == EPERM) || (retval == EACCES))
13277 printf(_("You must have %s access to the "
13278 "filesystem or be root\n"),
13279 (ctx->options & E2F_OPT_READONLY) ?
13280 "r/o" : "r/w");
13281 else if (retval == ENXIO)
13282 printf(_("Possibly non-existent or swap device?\n"));
13283#ifdef EROFS
13284 else if (retval == EROFS)
13285 printf(_("Disk write-protected; use the -n option "
13286 "to do a read-only\n"
13287 "check of the device.\n"));
13288#endif
13289 else
13290 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
13291 bb_error_msg_and_die(0);
13292 }
13293 ctx->fs = fs;
13294 fs->priv_data = ctx;
13295 sb = fs->super;
13296 if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
13297 bb_error_msg(_("while trying to open %s"),
13298 ctx->filesystem_name);
13299 get_newer:
13300 bb_error_msg_and_die(_("Get a newer version of e2fsck!"));
13301 }
13302
13303
13304
13305
13306
13307 if (ctx->device_name == 0 &&
13308 (sb->s_volume_name[0] != 0)) {
13309 ctx->device_name = string_copy(sb->s_volume_name,
13310 sizeof(sb->s_volume_name));
13311 }
13312 if (ctx->device_name == 0)
13313 ctx->device_name = ctx->filesystem_name;
13314
13315
13316
13317
13318 retval = e2fsck_check_ext3_journal(ctx);
13319 if (retval) {
13320 bb_error_msg(_("while checking ext3 journal for %s"),
13321 ctx->device_name);
13322 bb_error_msg_and_die(0);
13323 }
13324
13325
13326
13327
13328
13329 if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
13330 if (ctx->options & E2F_OPT_READONLY) {
13331 printf(_("Warning: skipping journal recovery "
13332 "because doing a read-only filesystem "
13333 "check.\n"));
13334 io_channel_flush(ctx->fs->io);
13335 } else {
13336 if (ctx->flags & E2F_FLAG_RESTARTED) {
13337
13338
13339
13340
13341
13342
13343 bb_error_msg(_("can't set superblock flags on %s"), ctx->device_name);
13344 bb_error_msg_and_die(0);
13345 }
13346 retval = e2fsck_run_ext3_journal(ctx);
13347 if (retval) {
13348 bb_error_msg(_("while recovering ext3 journal of %s"),
13349 ctx->device_name);
13350 bb_error_msg_and_die(0);
13351 }
13352 ext2fs_close(ctx->fs);
13353 ctx->fs = 0;
13354 ctx->flags |= E2F_FLAG_RESTARTED;
13355 goto restart;
13356 }
13357 }
13358
13359
13360
13361
13362
13363 if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
13364 (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
13365 bb_error_msg("(%s)", ctx->device_name);
13366 goto get_newer;
13367 }
13368 if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
13369 bb_error_msg("(%s)", ctx->device_name);
13370 goto get_newer;
13371 }
13372#ifdef ENABLE_COMPRESSION
13373
13374 if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
13375 bb_error_msg(_("warning: compression support is experimental"));
13376#endif
13377#ifndef ENABLE_HTREE
13378 if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
13379 bb_error_msg(_("E2fsck not compiled with HTREE support,\n\t"
13380 "but filesystem %s has HTREE directories."),
13381 ctx->device_name);
13382 goto get_newer;
13383 }
13384#endif
13385
13386
13387
13388
13389
13390
13391 if (ctx->superblock &&
13392 !(ctx->options & E2F_OPT_READONLY))
13393 ext2fs_mark_super_dirty(fs);
13394
13395
13396
13397
13398
13399
13400
13401
13402 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
13403
13404 ehandler_init(fs->io);
13405
13406 if (ctx->superblock)
13407 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
13408 ext2fs_mark_valid(fs);
13409 check_super_block(ctx);
13410 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
13411 bb_error_msg_and_die(0);
13412 check_if_skip(ctx);
13413 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
13414 bb_error_msg_and_die(0);
13415#ifdef ENABLE_SWAPFS
13416
13417#ifdef WORDS_BIGENDIAN
13418#define NATIVE_FLAG EXT2_FLAG_SWAP_BYTES
13419#else
13420#define NATIVE_FLAG 0
13421#endif
13422
13423
13424 if (normalize_swapfs) {
13425 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == NATIVE_FLAG) {
13426 fprintf(stderr, _("%s: Filesystem byte order "
13427 "already normalized.\n"), ctx->device_name);
13428 bb_error_msg_and_die(0);
13429 }
13430 }
13431 if (swapfs) {
13432 swap_filesys(ctx);
13433 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
13434 bb_error_msg_and_die(0);
13435 }
13436#endif
13437
13438
13439
13440
13441 ext2fs_mark_valid(fs);
13442
13443 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
13444 if (retval) {
13445 bb_error_msg(_("while reading bad blocks inode"));
13446 preenhalt(ctx);
13447 printf(_("This doesn't bode well,"
13448 " but we'll try to go on...\n"));
13449 }
13450
13451 run_result = e2fsck_run(ctx);
13452 e2fsck_clear_progbar(ctx);
13453 if (run_result == E2F_FLAG_RESTART) {
13454 printf(_("Restarting e2fsck from the beginning...\n"));
13455 retval = e2fsck_reset_context(ctx);
13456 if (retval) {
13457 bb_error_msg(_("while resetting context"));
13458 bb_error_msg_and_die(0);
13459 }
13460 ext2fs_close(fs);
13461 goto restart;
13462 }
13463 if (run_result & E2F_FLAG_CANCEL) {
13464 printf(_("%s: e2fsck canceled.\n"), ctx->device_name ?
13465 ctx->device_name : ctx->filesystem_name);
13466 exit_value |= FSCK_CANCELED;
13467 }
13468 if (run_result & E2F_FLAG_ABORT)
13469 bb_error_msg_and_die(_("aborted"));
13470
13471
13472 if (ext2fs_test_changed(fs)) {
13473 exit_value |= EXIT_NONDESTRUCT;
13474 if (!(ctx->options & E2F_OPT_PREEN))
13475 printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
13476 ctx->device_name);
13477 if (ctx->mount_flags & EXT2_MF_ISROOT) {
13478 printf(_("%s: ***** REBOOT LINUX *****\n"),
13479 ctx->device_name);
13480 exit_value |= EXIT_DESTRUCT;
13481 }
13482 }
13483 if (!ext2fs_test_valid(fs)) {
13484 printf(_("\n%s: ********** WARNING: Filesystem still has "
13485 "errors **********\n\n"), ctx->device_name);
13486 exit_value |= EXIT_UNCORRECTED;
13487 exit_value &= ~EXIT_NONDESTRUCT;
13488 }
13489 if (exit_value & FSCK_CANCELED)
13490 exit_value &= ~EXIT_NONDESTRUCT;
13491 else {
13492 show_stats(ctx);
13493 if (!(ctx->options & E2F_OPT_READONLY)) {
13494 if (ext2fs_test_valid(fs)) {
13495 if (!(sb->s_state & EXT2_VALID_FS))
13496 exit_value |= EXIT_NONDESTRUCT;
13497 sb->s_state = EXT2_VALID_FS;
13498 } else
13499 sb->s_state &= ~EXT2_VALID_FS;
13500 sb->s_mnt_count = 0;
13501 sb->s_lastcheck = time(NULL);
13502 ext2fs_mark_super_dirty(fs);
13503 }
13504 }
13505
13506 e2fsck_write_bitmaps(ctx);
13507
13508 ext2fs_close(fs);
13509 ctx->fs = NULL;
13510 free(ctx->filesystem_name);
13511 free(ctx->journal_name);
13512 e2fsck_free_context(ctx);
13513
13514 return exit_value;
13515}
13516