blob: b31b194145081e49820ba78d7d325c45304c88cf [file] [log] [blame]
Mike Frysinger51a43b42005-09-24 07:11:16 +00001/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002 * e2fsck
3 *
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 * This file may be
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006 * redistributed under the terms of the GNU Public License.
7 *
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008 *
9 * Dictionary Abstract Data Type
10 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
11 * Free Software License:
12 * All rights are reserved by the author, with the following exceptions:
13 * Permission is granted to freely reproduce and distribute this software,
14 * possibly in exchange for a fee, provided that this copyright notice appears
15 * intact. Permission is also granted to adapt this software to produce
16 * derivative works, as long as the modified versions carry this copyright
17 * notice and additional notices stating that the work has been modified.
18 * This source code may be translated into executable form and incorporated
19 * into proprietary software; there is no requirement for such software to
20 * contain a copyright notice related to this source.
21 *
22 * linux/fs/recovery and linux/fs/revoke
23 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
24 *
25 * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
26 *
27 * This file is part of the Linux kernel and is made available under
28 * the terms of the GNU General Public License, version 2, or at your
29 * option, any later version, incorporated herein by reference.
30 *
31 * Journal recovery routines for the generic filesystem journaling code;
32 * part of the ext2fs journaling system.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000033 */
34
35#ifndef _GNU_SOURCE
36#define _GNU_SOURCE 1 /* get strnlen() */
37#endif
38#include <sys/types.h>
39#include <inttypes.h>
40#include <stdio.h>
41#include <string.h>
42#include <unistd.h>
43#include <stdlib.h>
44#include <time.h>
45#include <fcntl.h>
46#include <ctype.h>
47#include <setjmp.h>
48#include <errno.h>
49#include <getopt.h>
50#include <limits.h>
51#include <stddef.h>
52#include <assert.h>
53#include <signal.h>
54#include <sys/time.h>
55#include <sys/stat.h>
56#include <sys/resource.h>
57#include <sys/param.h>
58#include <sys/mount.h>
59#include <sys/ioctl.h>
60#include <malloc.h>
61#include <termios.h>
62#include <mntent.h>
63#include <dirent.h>
64
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000065#include "fsck.h"
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000066
67#include "ext2fs/ext2_fs.h"
68#include "ext2fs/ext2fs.h"
69#include "blkid/blkid.h"
70#include "ext2fs/ext2_ext_attr.h"
71#include "uuid/uuid.h"
72
73#ifdef __GNUC__
74#define _INLINE_ __inline__
75#define EXT2FS_ATTR(x) __attribute__(x)
76#else
77#define _INLINE_
78#define EXT2FS_ATTR(x)
79#endif
80
81/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000082 * The last ext2fs revision level that this version of e2fsck is able to
83 * support
84 */
85#define E2FSCK_CURRENT_REV 1
86
87/*
88 * The directory information structure; stores directory information
89 * collected in earlier passes, to avoid disk i/o in fetching the
90 * directory information.
91 */
92struct dir_info {
93 ext2_ino_t ino; /* Inode number */
94 ext2_ino_t dotdot; /* Parent according to '..' */
95 ext2_ino_t parent; /* Parent according to treewalk */
96};
97
98
99/*
100 * The indexed directory information structure; stores information for
101 * directories which contain a hash tree index.
102 */
103struct dx_dir_info {
104 ext2_ino_t ino; /* Inode number */
105 int numblocks; /* number of blocks */
106 int hashversion;
107 short depth; /* depth of tree */
108 struct dx_dirblock_info *dx_block; /* Array of size numblocks */
109};
110
111#define DX_DIRBLOCK_ROOT 1
112#define DX_DIRBLOCK_LEAF 2
113#define DX_DIRBLOCK_NODE 3
114#define DX_DIRBLOCK_CORRUPT 4
115#define DX_DIRBLOCK_CLEARED 8
116
117struct dx_dirblock_info {
118 int type;
119 blk_t phys;
120 int flags;
121 blk_t parent;
122 ext2_dirhash_t min_hash;
123 ext2_dirhash_t max_hash;
124 ext2_dirhash_t node_min_hash;
125 ext2_dirhash_t node_max_hash;
126};
127
128#define DX_FLAG_REFERENCED 1
129#define DX_FLAG_DUP_REF 2
130#define DX_FLAG_FIRST 4
131#define DX_FLAG_LAST 8
132
133#ifdef RESOURCE_TRACK
134/*
135 * This structure is used for keeping track of how much resources have
136 * been used for a particular pass of e2fsck.
137 */
138struct resource_track {
139 struct timeval time_start;
140 struct timeval user_start;
141 struct timeval system_start;
142 void *brk_start;
143};
144#endif
145
146/*
147 * E2fsck options
148 */
149#define E2F_OPT_READONLY 0x0001
150#define E2F_OPT_PREEN 0x0002
151#define E2F_OPT_YES 0x0004
152#define E2F_OPT_NO 0x0008
153#define E2F_OPT_TIME 0x0010
154#define E2F_OPT_TIME2 0x0020
155#define E2F_OPT_CHECKBLOCKS 0x0040
156#define E2F_OPT_DEBUG 0x0080
157#define E2F_OPT_FORCE 0x0100
158#define E2F_OPT_WRITECHECK 0x0200
159#define E2F_OPT_COMPRESS_DIRS 0x0400
160
161/*
162 * E2fsck flags
163 */
164#define E2F_FLAG_ABORT 0x0001 /* Abort signaled */
165#define E2F_FLAG_CANCEL 0x0002 /* Cancel signaled */
166#define E2F_FLAG_SIGNAL_MASK 0x0003
167#define E2F_FLAG_RESTART 0x0004 /* Restart signaled */
168
169#define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */
170
171#define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */
172#define E2F_FLAG_PROG_SUPPRESS 0x0040 /* Progress suspended */
173#define E2F_FLAG_JOURNAL_INODE 0x0080 /* Create a new ext3 journal inode */
174#define E2F_FLAG_SB_SPECIFIED 0x0100 /* The superblock was explicitly
175 * specified by the user */
176#define E2F_FLAG_RESTARTED 0x0200 /* E2fsck has been restarted */
177#define E2F_FLAG_RESIZE_INODE 0x0400 /* Request to recreate resize inode */
178
179/*
180 * Defines for indicating the e2fsck pass number
181 */
182#define E2F_PASS_1 1
183#define E2F_PASS_2 2
184#define E2F_PASS_3 3
185#define E2F_PASS_4 4
186#define E2F_PASS_5 5
187#define E2F_PASS_1B 6
188
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000189
190/*
191 * This is the global e2fsck structure.
192 */
193typedef struct e2fsck_struct *e2fsck_t;
194
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000195/*
196 * Define the extended attribute refcount structure
197 */
198typedef struct ea_refcount *ext2_refcount_t;
199
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000200struct e2fsck_struct {
201 ext2_filsys fs;
202 const char *program_name;
203 char *filesystem_name;
204 char *device_name;
205 char *io_options;
206 int flags; /* E2fsck internal flags */
207 int options;
208 blk_t use_superblock; /* sb requested by user */
209 blk_t superblock; /* sb used to open fs */
210 int blocksize; /* blocksize */
211 blk_t num_blocks; /* Total number of blocks */
212 int mount_flags;
213 blkid_cache blkid; /* blkid cache */
214
215 jmp_buf abort_loc;
216
217 unsigned long abort_code;
218
219 int (*progress)(e2fsck_t ctx, int pass, unsigned long cur,
220 unsigned long max);
221
222 ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */
223 ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
224 ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
225 ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */
226 ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
227 ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
228
229 ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
230 ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */
231 ext2fs_block_bitmap block_ea_map; /* Blocks which are used by EA's */
232
233 /*
234 * Inode count arrays
235 */
236 ext2_icount_t inode_count;
237 ext2_icount_t inode_link_info;
238
239 ext2_refcount_t refcount;
240 ext2_refcount_t refcount_extra;
241
242 /*
243 * Array of flags indicating whether an inode bitmap, block
244 * bitmap, or inode table is invalid
245 */
246 int *invalid_inode_bitmap_flag;
247 int *invalid_block_bitmap_flag;
248 int *invalid_inode_table_flag;
249 int invalid_bitmaps; /* There are invalid bitmaps/itable */
250
251 /*
252 * Block buffer
253 */
254 char *block_buf;
255
256 /*
257 * For pass1_check_directory and pass1_get_blocks
258 */
259 ext2_ino_t stashed_ino;
260 struct ext2_inode *stashed_inode;
261
262 /*
263 * Location of the lost and found directory
264 */
265 ext2_ino_t lost_and_found;
266 int bad_lost_and_found;
267
268 /*
269 * Directory information
270 */
271 int dir_info_count;
272 int dir_info_size;
273 struct dir_info *dir_info;
274
275 /*
276 * Indexed directory information
277 */
278 int dx_dir_info_count;
279 int dx_dir_info_size;
280 struct dx_dir_info *dx_dir_info;
281
282 /*
283 * Directories to hash
284 */
285 ext2_u32_list dirs_to_hash;
286
287 /*
288 * Tuning parameters
289 */
290 int process_inode_size;
291 int inode_buffer_blocks;
292
293 /*
294 * ext3 journal support
295 */
296 io_channel journal_io;
297 char *journal_name;
298
299#ifdef RESOURCE_TRACK
300 /*
301 * For timing purposes
302 */
303 struct resource_track global_rtrack;
304#endif
305
306 /*
307 * How we display the progress update (for unix)
308 */
309 int progress_fd;
310 int progress_pos;
311 int progress_last_percent;
312 unsigned int progress_last_time;
313 int interactive; /* Are we connected directly to a tty? */
314 char start_meta[2], stop_meta[2];
315
316 /* File counts */
317 int fs_directory_count;
318 int fs_regular_count;
319 int fs_blockdev_count;
320 int fs_chardev_count;
321 int fs_links_count;
322 int fs_symlinks_count;
323 int fs_fast_symlinks_count;
324 int fs_fifo_count;
325 int fs_total_count;
326 int fs_badblocks_count;
327 int fs_sockets_count;
328 int fs_ind_count;
329 int fs_dind_count;
330 int fs_tind_count;
331 int fs_fragmented;
332 int large_files;
333 int fs_ext_attr_inodes;
334 int fs_ext_attr_blocks;
335
336 int ext_attr_ver;
337
338 /*
339 * For the use of callers of the e2fsck functions; not used by
340 * e2fsck functions themselves.
341 */
342 void *priv_data;
343};
344
345/* Used by the region allocation code */
346typedef __u32 region_addr_t;
347typedef struct region_struct *region_t;
348
349/*
350 * Procedure declarations
351 */
352
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000353static void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000354
355/* pass1.c */
356static void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000357
358/* pass2.c */
359static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
360 ext2_ino_t ino, char *buf);
361
362/* pass3.c */
363static int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
364static errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
365 int num, int gauranteed_size);
366static ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix);
367static errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino,
368 int adj);
369
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000370/* rehash.c */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000371static void e2fsck_rehash_directories(e2fsck_t ctx);
372
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000373/* util.c */
374static void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
375 const char *description);
376static int ask(e2fsck_t ctx, const char * string, int def);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000377static void e2fsck_read_bitmaps(e2fsck_t ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000378static void preenhalt(e2fsck_t ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000379#ifdef RESOURCE_TRACK
380static void print_resource_track(const char *desc,
381 struct resource_track *track);
382static void init_resource_track(struct resource_track *track);
383#endif
384static void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
385 struct ext2_inode * inode, const char * proc);
386static void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
387 struct ext2_inode * inode, const char * proc);
388#ifdef MTRACE
389static void mtrace_print(char *mesg);
390#endif
391static blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs,
392 const char *name, io_manager manager);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000393
394/* unix.c */
395static void e2fsck_clear_progbar(e2fsck_t ctx);
396static int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
397 float percent, unsigned int dpynum);
398/*
399 * problem.h --- e2fsck problem error codes
400 */
401
402typedef __u32 problem_t;
403
404struct problem_context {
405 errcode_t errcode;
406 ext2_ino_t ino, ino2, dir;
407 struct ext2_inode *inode;
408 struct ext2_dir_entry *dirent;
409 blk_t blk, blk2;
410 e2_blkcnt_t blkcount;
411 int group;
412 __u64 num;
413 const char *str;
414};
415
416/*
417 * We define a set of "latch groups"; these are problems which are
418 * handled as a set. The user answers once for a particular latch
419 * group.
420 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000421#define PR_LATCH_MASK 0x0ff0 /* Latch mask */
422#define PR_LATCH_BLOCK 0x0010 /* Latch for illegal blocks (pass 1) */
423#define PR_LATCH_BBLOCK 0x0020 /* Latch for bad block inode blocks (pass 1) */
424#define PR_LATCH_IBITMAP 0x0030 /* Latch for pass 5 inode bitmap proc. */
425#define PR_LATCH_BBITMAP 0x0040 /* Latch for pass 5 inode bitmap proc. */
426#define PR_LATCH_RELOC 0x0050 /* Latch for superblock relocate hint */
427#define PR_LATCH_DBLOCK 0x0060 /* Latch for pass 1b dup block headers */
428#define PR_LATCH_LOW_DTIME 0x0070 /* Latch for pass1 orphaned list refugees */
429#define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000430#define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */
431
432#define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1)
433
434/*
435 * Latch group descriptor flags
436 */
437#define PRL_YES 0x0001 /* Answer yes */
438#define PRL_NO 0x0002 /* Answer no */
439#define PRL_LATCHED 0x0004 /* The latch group is latched */
440#define PRL_SUPPRESS 0x0008 /* Suppress all latch group questions */
441
442#define PRL_VARIABLE 0x000f /* All the flags that need to be reset */
443
444/*
445 * Pre-Pass 1 errors
446 */
447
448/* Block bitmap not in group */
449#define PR_0_BB_NOT_GROUP 0x000001
450
451/* Inode bitmap not in group */
452#define PR_0_IB_NOT_GROUP 0x000002
453
454/* Inode table not in group */
455#define PR_0_ITABLE_NOT_GROUP 0x000003
456
457/* Superblock corrupt */
458#define PR_0_SB_CORRUPT 0x000004
459
460/* Filesystem size is wrong */
461#define PR_0_FS_SIZE_WRONG 0x000005
462
463/* Fragments not supported */
464#define PR_0_NO_FRAGMENTS 0x000006
465
466/* Bad blocks_per_group */
467#define PR_0_BLOCKS_PER_GROUP 0x000007
468
469/* Bad first_data_block */
470#define PR_0_FIRST_DATA_BLOCK 0x000008
471
472/* Adding UUID to filesystem */
473#define PR_0_ADD_UUID 0x000009
474
475/* Relocate hint */
476#define PR_0_RELOCATE_HINT 0x00000A
477
478/* Miscellaneous superblock corruption */
479#define PR_0_MISC_CORRUPT_SUPER 0x00000B
480
481/* Error determing physical device size of filesystem */
482#define PR_0_GETSIZE_ERROR 0x00000C
483
484/* Inode count in the superblock incorrect */
485#define PR_0_INODE_COUNT_WRONG 0x00000D
486
487/* The Hurd does not support the filetype feature */
488#define PR_0_HURD_CLEAR_FILETYPE 0x00000E
489
490/* Journal inode is invalid */
491#define PR_0_JOURNAL_BAD_INODE 0x00000F
492
493/* The external journal has multiple filesystems (which we can't handle yet) */
494#define PR_0_JOURNAL_UNSUPP_MULTIFS 0x000010
495
496/* Can't find external journal */
497#define PR_0_CANT_FIND_JOURNAL 0x000011
498
499/* External journal has bad superblock */
500#define PR_0_EXT_JOURNAL_BAD_SUPER 0x000012
501
502/* Superblock has a bad journal UUID */
503#define PR_0_JOURNAL_BAD_UUID 0x000013
504
505/* Journal has an unknown superblock type */
506#define PR_0_JOURNAL_UNSUPP_SUPER 0x000014
507
508/* Journal superblock is corrupt */
509#define PR_0_JOURNAL_BAD_SUPER 0x000015
510
511/* Journal superblock is corrupt */
512#define PR_0_JOURNAL_HAS_JOURNAL 0x000016
513
514/* Superblock has recovery flag set but no journal */
515#define PR_0_JOURNAL_RECOVER_SET 0x000017
516
517/* Journal has data, but recovery flag is clear */
518#define PR_0_JOURNAL_RECOVERY_CLEAR 0x000018
519
520/* Ask if we should clear the journal */
521#define PR_0_JOURNAL_RESET_JOURNAL 0x000019
522
523/* Filesystem revision is 0, but feature flags are set */
524#define PR_0_FS_REV_LEVEL 0x00001A
525
526/* Clearing orphan inode */
527#define PR_0_ORPHAN_CLEAR_INODE 0x000020
528
529/* Illegal block found in orphaned inode */
530#define PR_0_ORPHAN_ILLEGAL_BLOCK_NUM 0x000021
531
532/* Already cleared block found in orphaned inode */
533#define PR_0_ORPHAN_ALREADY_CLEARED_BLOCK 0x000022
534
535/* Illegal orphan inode in superblock */
536#define PR_0_ORPHAN_ILLEGAL_HEAD_INODE 0x000023
537
538/* Illegal inode in orphaned inode list */
539#define PR_0_ORPHAN_ILLEGAL_INODE 0x000024
540
541/* Journal has unsupported read-only feature - abort */
542#define PR_0_JOURNAL_UNSUPP_ROCOMPAT 0x000025
543
544/* Journal has unsupported incompatible feature - abort */
545#define PR_0_JOURNAL_UNSUPP_INCOMPAT 0x000026
546
547/* Journal has unsupported version number */
548#define PR_0_JOURNAL_UNSUPP_VERSION 0x000027
549
550/* Moving journal to hidden file */
551#define PR_0_MOVE_JOURNAL 0x000028
552
553/* Error moving journal */
554#define PR_0_ERR_MOVE_JOURNAL 0x000029
555
556/* Clearing V2 journal superblock */
557#define PR_0_CLEAR_V2_JOURNAL 0x00002A
558
559/* Run journal anyway */
560#define PR_0_JOURNAL_RUN 0x00002B
561
562/* Run journal anyway by default */
563#define PR_0_JOURNAL_RUN_DEFAULT 0x00002C
564
565/* Backup journal inode blocks */
566#define PR_0_BACKUP_JNL 0x00002D
567
568/* Reserved blocks w/o resize_inode */
569#define PR_0_NONZERO_RESERVED_GDT_BLOCKS 0x00002E
570
571/* Resize_inode not enabled, but resize inode is non-zero */
572#define PR_0_CLEAR_RESIZE_INODE 0x00002F
573
574/* Resize inode invalid */
575#define PR_0_RESIZE_INODE_INVALID 0x000030
576
577/*
578 * Pass 1 errors
579 */
580
581/* Pass 1: Checking inodes, blocks, and sizes */
582#define PR_1_PASS_HEADER 0x010000
583
584/* Root directory is not an inode */
585#define PR_1_ROOT_NO_DIR 0x010001
586
587/* Root directory has dtime set */
588#define PR_1_ROOT_DTIME 0x010002
589
590/* Reserved inode has bad mode */
591#define PR_1_RESERVED_BAD_MODE 0x010003
592
593/* Deleted inode has zero dtime */
594#define PR_1_ZERO_DTIME 0x010004
595
596/* Inode in use, but dtime set */
597#define PR_1_SET_DTIME 0x010005
598
599/* Zero-length directory */
600#define PR_1_ZERO_LENGTH_DIR 0x010006
601
602/* Block bitmap conflicts with some other fs block */
603#define PR_1_BB_CONFLICT 0x010007
604
605/* Inode bitmap conflicts with some other fs block */
606#define PR_1_IB_CONFLICT 0x010008
607
608/* Inode table conflicts with some other fs block */
609#define PR_1_ITABLE_CONFLICT 0x010009
610
611/* Block bitmap is on a bad block */
612#define PR_1_BB_BAD_BLOCK 0x01000A
613
614/* Inode bitmap is on a bad block */
615#define PR_1_IB_BAD_BLOCK 0x01000B
616
617/* Inode has incorrect i_size */
618#define PR_1_BAD_I_SIZE 0x01000C
619
620/* Inode has incorrect i_blocks */
621#define PR_1_BAD_I_BLOCKS 0x01000D
622
623/* Illegal block number in inode */
624#define PR_1_ILLEGAL_BLOCK_NUM 0x01000E
625
626/* Block number overlaps fs metadata */
627#define PR_1_BLOCK_OVERLAPS_METADATA 0x01000F
628
629/* Inode has illegal blocks (latch question) */
630#define PR_1_INODE_BLOCK_LATCH 0x010010
631
632/* Too many bad blocks in inode */
633#define PR_1_TOO_MANY_BAD_BLOCKS 0x010011
634
635/* Illegal block number in bad block inode */
636#define PR_1_BB_ILLEGAL_BLOCK_NUM 0x010012
637
638/* Bad block inode has illegal blocks (latch question) */
639#define PR_1_INODE_BBLOCK_LATCH 0x010013
640
641/* Duplicate or bad blocks in use! */
642#define PR_1_DUP_BLOCKS_PREENSTOP 0x010014
643
644/* Bad block used as bad block indirect block */
645#define PR_1_BBINODE_BAD_METABLOCK 0x010015
646
647/* Inconsistency can't be fixed prompt */
648#define PR_1_BBINODE_BAD_METABLOCK_PROMPT 0x010016
649
650/* Bad primary block */
651#define PR_1_BAD_PRIMARY_BLOCK 0x010017
652
653/* Bad primary block prompt */
654#define PR_1_BAD_PRIMARY_BLOCK_PROMPT 0x010018
655
656/* Bad primary superblock */
657#define PR_1_BAD_PRIMARY_SUPERBLOCK 0x010019
658
659/* Bad primary block group descriptors */
660#define PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR 0x01001A
661
662/* Bad superblock in group */
663#define PR_1_BAD_SUPERBLOCK 0x01001B
664
665/* Bad block group descriptors in group */
666#define PR_1_BAD_GROUP_DESCRIPTORS 0x01001C
667
668/* Block claimed for no reason */
669#define PR_1_PROGERR_CLAIMED_BLOCK 0x01001D
670
671/* Error allocating blocks for relocating metadata */
672#define PR_1_RELOC_BLOCK_ALLOCATE 0x01001E
673
674/* Error allocating block buffer during relocation process */
675#define PR_1_RELOC_MEMORY_ALLOCATE 0x01001F
676
677/* Relocating metadata group information from X to Y */
678#define PR_1_RELOC_FROM_TO 0x010020
679
680/* Relocating metatdata group information to X */
681#define PR_1_RELOC_TO 0x010021
682
683/* Block read error during relocation process */
684#define PR_1_RELOC_READ_ERR 0x010022
685
686/* Block write error during relocation process */
687#define PR_1_RELOC_WRITE_ERR 0x010023
688
689/* Error allocating inode bitmap */
690#define PR_1_ALLOCATE_IBITMAP_ERROR 0x010024
691
692/* Error allocating block bitmap */
693#define PR_1_ALLOCATE_BBITMAP_ERROR 0x010025
694
695/* Error allocating icount structure */
696#define PR_1_ALLOCATE_ICOUNT 0x010026
697
698/* Error allocating dbcount */
699#define PR_1_ALLOCATE_DBCOUNT 0x010027
700
701/* Error while scanning inodes */
702#define PR_1_ISCAN_ERROR 0x010028
703
704/* Error while iterating over blocks */
705#define PR_1_BLOCK_ITERATE 0x010029
706
707/* Error while storing inode count information */
708#define PR_1_ICOUNT_STORE 0x01002A
709
710/* Error while storing directory block information */
711#define PR_1_ADD_DBLOCK 0x01002B
712
713/* Error while reading inode (for clearing) */
714#define PR_1_READ_INODE 0x01002C
715
716/* Suppress messages prompt */
717#define PR_1_SUPPRESS_MESSAGES 0x01002D
718
719/* Imagic flag set on an inode when filesystem doesn't support it */
720#define PR_1_SET_IMAGIC 0x01002F
721
722/* Immutable flag set on a device or socket inode */
723#define PR_1_SET_IMMUTABLE 0x010030
724
725/* Compression flag set on a non-compressed filesystem */
726#define PR_1_COMPR_SET 0x010031
727
728/* Non-zero size on on device, fifo or socket inode */
729#define PR_1_SET_NONZSIZE 0x010032
730
731/* Filesystem revision is 0, but feature flags are set */
732#define PR_1_FS_REV_LEVEL 0x010033
733
734/* Journal inode not in use, needs clearing */
735#define PR_1_JOURNAL_INODE_NOT_CLEAR 0x010034
736
737/* Journal inode has wrong mode */
738#define PR_1_JOURNAL_BAD_MODE 0x010035
739
740/* Inode that was part of orphan linked list */
741#define PR_1_LOW_DTIME 0x010036
742
743/* Latch question which asks how to deal with low dtime inodes */
744#define PR_1_ORPHAN_LIST_REFUGEES 0x010037
745
746/* Error allocating refcount structure */
747#define PR_1_ALLOCATE_REFCOUNT 0x010038
748
749/* Error reading Extended Attribute block */
750#define PR_1_READ_EA_BLOCK 0x010039
751
752/* Invalid Extended Attribute block */
753#define PR_1_BAD_EA_BLOCK 0x01003A
754
755/* Error reading Extended Attribute block while fixing refcount -- abort */
756#define PR_1_EXTATTR_READ_ABORT 0x01003B
757
758/* Extended attribute reference count incorrect */
759#define PR_1_EXTATTR_REFCOUNT 0x01003C
760
761/* Error writing Extended Attribute block while fixing refcount */
762#define PR_1_EXTATTR_WRITE 0x01003D
763
764/* Multiple EA blocks not supported */
765#define PR_1_EA_MULTI_BLOCK 0x01003E
766
767/* Error allocating EA region allocation structure */
768#define PR_1_EA_ALLOC_REGION 0x01003F
769
770/* Error EA allocation collision */
771#define PR_1_EA_ALLOC_COLLISION 0x010040
772
773/* Bad extended attribute name */
774#define PR_1_EA_BAD_NAME 0x010041
775
776/* Bad extended attribute value */
777#define PR_1_EA_BAD_VALUE 0x010042
778
779/* Inode too big (latch question) */
780#define PR_1_INODE_TOOBIG 0x010043
781
782/* Directory too big */
783#define PR_1_TOOBIG_DIR 0x010044
784
785/* Regular file too big */
786#define PR_1_TOOBIG_REG 0x010045
787
788/* Symlink too big */
789#define PR_1_TOOBIG_SYMLINK 0x010046
790
791/* INDEX_FL flag set on a non-HTREE filesystem */
792#define PR_1_HTREE_SET 0x010047
793
794/* INDEX_FL flag set on a non-directory */
795#define PR_1_HTREE_NODIR 0x010048
796
797/* Invalid root node in HTREE directory */
798#define PR_1_HTREE_BADROOT 0x010049
799
800/* Unsupported hash version in HTREE directory */
801#define PR_1_HTREE_HASHV 0x01004A
802
803/* Incompatible flag in HTREE root node */
804#define PR_1_HTREE_INCOMPAT 0x01004B
805
806/* HTREE too deep */
807#define PR_1_HTREE_DEPTH 0x01004C
808
809/* Bad block has indirect block that conflicts with filesystem block */
810#define PR_1_BB_FS_BLOCK 0x01004D
811
812/* Resize inode failed */
813#define PR_1_RESIZE_INODE_CREATE 0x01004E
814
815/* inode->i_size is too long */
816#define PR_1_EXTRA_ISIZE 0x01004F
817
818/* attribute name is too long */
819#define PR_1_ATTR_NAME_LEN 0x010050
820
821/* wrong EA value offset */
822#define PR_1_ATTR_VALUE_OFFSET 0x010051
823
824/* wrong EA blocknumber */
825#define PR_1_ATTR_VALUE_BLOCK 0x010052
826
827/* wrong EA value size */
828#define PR_1_ATTR_VALUE_SIZE 0x010053
829
830/* wrong EA hash value */
831#define PR_1_ATTR_HASH 0x010054
832
833/*
834 * Pass 1b errors
835 */
836
837/* Pass 1B: Rescan for duplicate/bad blocks */
838#define PR_1B_PASS_HEADER 0x011000
839
840/* Duplicate/bad block(s) header */
841#define PR_1B_DUP_BLOCK_HEADER 0x011001
842
843/* Duplicate/bad block(s) in inode */
844#define PR_1B_DUP_BLOCK 0x011002
845
846/* Duplicate/bad block(s) end */
847#define PR_1B_DUP_BLOCK_END 0x011003
848
849/* Error while scanning inodes */
850#define PR_1B_ISCAN_ERROR 0x011004
851
852/* Error allocating inode bitmap */
853#define PR_1B_ALLOCATE_IBITMAP_ERROR 0x011005
854
855/* Error while iterating over blocks */
856#define PR_1B_BLOCK_ITERATE 0x0110006
857
858/* Error adjusting EA refcount */
859#define PR_1B_ADJ_EA_REFCOUNT 0x0110007
860
861
862/* Pass 1C: Scan directories for inodes with dup blocks. */
863#define PR_1C_PASS_HEADER 0x012000
864
865
866/* Pass 1D: Reconciling duplicate blocks */
867#define PR_1D_PASS_HEADER 0x013000
868
869/* File has duplicate blocks */
870#define PR_1D_DUP_FILE 0x013001
871
872/* List of files sharing duplicate blocks */
873#define PR_1D_DUP_FILE_LIST 0x013002
874
875/* File sharing blocks with filesystem metadata */
876#define PR_1D_SHARE_METADATA 0x013003
877
878/* Report of how many duplicate/bad inodes */
879#define PR_1D_NUM_DUP_INODES 0x013004
880
881/* Duplicated blocks already reassigned or cloned. */
882#define PR_1D_DUP_BLOCKS_DEALT 0x013005
883
884/* Clone duplicate/bad blocks? */
885#define PR_1D_CLONE_QUESTION 0x013006
886
887/* Delete file? */
888#define PR_1D_DELETE_QUESTION 0x013007
889
890/* Couldn't clone file (error) */
891#define PR_1D_CLONE_ERROR 0x013008
892
893/*
894 * Pass 2 errors
895 */
896
897/* Pass 2: Checking directory structure */
898#define PR_2_PASS_HEADER 0x020000
899
900/* Bad inode number for '.' */
901#define PR_2_BAD_INODE_DOT 0x020001
902
903/* Directory entry has bad inode number */
904#define PR_2_BAD_INO 0x020002
905
906/* Directory entry has deleted or unused inode */
907#define PR_2_UNUSED_INODE 0x020003
908
909/* Directry entry is link to '.' */
910#define PR_2_LINK_DOT 0x020004
911
912/* Directory entry points to inode now located in a bad block */
913#define PR_2_BB_INODE 0x020005
914
915/* Directory entry contains a link to a directory */
916#define PR_2_LINK_DIR 0x020006
917
918/* Directory entry contains a link to the root directry */
919#define PR_2_LINK_ROOT 0x020007
920
921/* Directory entry has illegal characters in its name */
922#define PR_2_BAD_NAME 0x020008
923
924/* Missing '.' in directory inode */
925#define PR_2_MISSING_DOT 0x020009
926
927/* Missing '..' in directory inode */
928#define PR_2_MISSING_DOT_DOT 0x02000A
929
930/* First entry in directory inode doesn't contain '.' */
931#define PR_2_1ST_NOT_DOT 0x02000B
932
933/* Second entry in directory inode doesn't contain '..' */
934#define PR_2_2ND_NOT_DOT_DOT 0x02000C
935
936/* i_faddr should be zero */
937#define PR_2_FADDR_ZERO 0x02000D
938
939/* i_file_acl should be zero */
940#define PR_2_FILE_ACL_ZERO 0x02000E
941
942/* i_dir_acl should be zero */
943#define PR_2_DIR_ACL_ZERO 0x02000F
944
945/* i_frag should be zero */
946#define PR_2_FRAG_ZERO 0x020010
947
948/* i_fsize should be zero */
949#define PR_2_FSIZE_ZERO 0x020011
950
951/* inode has bad mode */
952#define PR_2_BAD_MODE 0x020012
953
954/* directory corrupted */
955#define PR_2_DIR_CORRUPTED 0x020013
956
957/* filename too long */
958#define PR_2_FILENAME_LONG 0x020014
959
960/* Directory inode has a missing block (hole) */
961#define PR_2_DIRECTORY_HOLE 0x020015
962
963/* '.' is not NULL terminated */
964#define PR_2_DOT_NULL_TERM 0x020016
965
966/* '..' is not NULL terminated */
967#define PR_2_DOT_DOT_NULL_TERM 0x020017
968
969/* Illegal character device in inode */
970#define PR_2_BAD_CHAR_DEV 0x020018
971
972/* Illegal block device in inode */
973#define PR_2_BAD_BLOCK_DEV 0x020019
974
975/* Duplicate '.' entry */
976#define PR_2_DUP_DOT 0x02001A
977
978/* Duplicate '..' entry */
979#define PR_2_DUP_DOT_DOT 0x02001B
980
981/* Internal error: couldn't find dir_info */
982#define PR_2_NO_DIRINFO 0x02001C
983
984/* Final rec_len is wrong */
985#define PR_2_FINAL_RECLEN 0x02001D
986
987/* Error allocating icount structure */
988#define PR_2_ALLOCATE_ICOUNT 0x02001E
989
990/* Error iterating over directory blocks */
991#define PR_2_DBLIST_ITERATE 0x02001F
992
993/* Error reading directory block */
994#define PR_2_READ_DIRBLOCK 0x020020
995
996/* Error writing directory block */
997#define PR_2_WRITE_DIRBLOCK 0x020021
998
999/* Error allocating new directory block */
1000#define PR_2_ALLOC_DIRBOCK 0x020022
1001
1002/* Error deallocating inode */
1003#define PR_2_DEALLOC_INODE 0x020023
1004
1005/* Directory entry for '.' is big. Split? */
1006#define PR_2_SPLIT_DOT 0x020024
1007
1008/* Illegal FIFO */
1009#define PR_2_BAD_FIFO 0x020025
1010
1011/* Illegal socket */
1012#define PR_2_BAD_SOCKET 0x020026
1013
1014/* Directory filetype not set */
1015#define PR_2_SET_FILETYPE 0x020027
1016
1017/* Directory filetype incorrect */
1018#define PR_2_BAD_FILETYPE 0x020028
1019
1020/* Directory filetype set when it shouldn't be */
1021#define PR_2_CLEAR_FILETYPE 0x020029
1022
1023/* Directory filename can't be zero-length */
1024#define PR_2_NULL_NAME 0x020030
1025
1026/* Invalid symlink */
1027#define PR_2_INVALID_SYMLINK 0x020031
1028
1029/* i_file_acl (extended attribute) is bad */
1030#define PR_2_FILE_ACL_BAD 0x020032
1031
1032/* Filesystem contains large files, but has no such flag in sb */
1033#define PR_2_FEATURE_LARGE_FILES 0x020033
1034
1035/* Node in HTREE directory not referenced */
1036#define PR_2_HTREE_NOTREF 0x020034
1037
1038/* Node in HTREE directory referenced twice */
1039#define PR_2_HTREE_DUPREF 0x020035
1040
1041/* Node in HTREE directory has bad min hash */
1042#define PR_2_HTREE_MIN_HASH 0x020036
1043
1044/* Node in HTREE directory has bad max hash */
1045#define PR_2_HTREE_MAX_HASH 0x020037
1046
1047/* Clear invalid HTREE directory */
1048#define PR_2_HTREE_CLEAR 0x020038
1049
1050/* Clear the htree flag forcibly */
1051/* #define PR_2_HTREE_FCLR 0x020039 */
1052
1053/* Bad block in htree interior node */
1054#define PR_2_HTREE_BADBLK 0x02003A
1055
1056/* Error adjusting EA refcount */
1057#define PR_2_ADJ_EA_REFCOUNT 0x02003B
1058
1059/* Invalid HTREE root node */
1060#define PR_2_HTREE_BAD_ROOT 0x02003C
1061
1062/* Invalid HTREE limit */
1063#define PR_2_HTREE_BAD_LIMIT 0x02003D
1064
1065/* Invalid HTREE count */
1066#define PR_2_HTREE_BAD_COUNT 0x02003E
1067
1068/* HTREE interior node has out-of-order hashes in table */
1069#define PR_2_HTREE_HASH_ORDER 0x02003F
1070
1071/* Node in HTREE directory has bad depth */
1072#define PR_2_HTREE_BAD_DEPTH 0x020040
1073
1074/* Duplicate directory entry found */
1075#define PR_2_DUPLICATE_DIRENT 0x020041
1076
1077/* Non-unique filename found */
1078#define PR_2_NON_UNIQUE_FILE 0x020042
1079
1080/* Duplicate directory entry found */
1081#define PR_2_REPORT_DUP_DIRENT 0x020043
1082
1083/*
1084 * Pass 3 errors
1085 */
1086
1087/* Pass 3: Checking directory connectivity */
1088#define PR_3_PASS_HEADER 0x030000
1089
1090/* Root inode not allocated */
1091#define PR_3_NO_ROOT_INODE 0x030001
1092
1093/* No room in lost+found */
1094#define PR_3_EXPAND_LF_DIR 0x030002
1095
1096/* Unconnected directory inode */
1097#define PR_3_UNCONNECTED_DIR 0x030003
1098
1099/* /lost+found not found */
1100#define PR_3_NO_LF_DIR 0x030004
1101
1102/* .. entry is incorrect */
1103#define PR_3_BAD_DOT_DOT 0x030005
1104
1105/* Bad or non-existent /lost+found. Cannot reconnect */
1106#define PR_3_NO_LPF 0x030006
1107
1108/* Could not expand /lost+found */
1109#define PR_3_CANT_EXPAND_LPF 0x030007
1110
1111/* Could not reconnect inode */
1112#define PR_3_CANT_RECONNECT 0x030008
1113
1114/* Error while trying to find /lost+found */
1115#define PR_3_ERR_FIND_LPF 0x030009
1116
1117/* Error in ext2fs_new_block while creating /lost+found */
1118#define PR_3_ERR_LPF_NEW_BLOCK 0x03000A
1119
1120/* Error in ext2fs_new_inode while creating /lost+found */
1121#define PR_3_ERR_LPF_NEW_INODE 0x03000B
1122
1123/* Error in ext2fs_new_dir_block while creating /lost+found */
1124#define PR_3_ERR_LPF_NEW_DIR_BLOCK 0x03000C
1125
1126/* Error while writing directory block for /lost+found */
1127#define PR_3_ERR_LPF_WRITE_BLOCK 0x03000D
1128
1129/* Error while adjusting inode count */
1130#define PR_3_ADJUST_INODE 0x03000E
1131
1132/* Couldn't fix parent directory -- error */
1133#define PR_3_FIX_PARENT_ERR 0x03000F
1134
1135/* Couldn't fix parent directory -- couldn't find it */
1136#define PR_3_FIX_PARENT_NOFIND 0x030010
1137
1138/* Error allocating inode bitmap */
1139#define PR_3_ALLOCATE_IBITMAP_ERROR 0x030011
1140
1141/* Error creating root directory */
1142#define PR_3_CREATE_ROOT_ERROR 0x030012
1143
1144/* Error creating lost and found directory */
1145#define PR_3_CREATE_LPF_ERROR 0x030013
1146
1147/* Root inode is not directory; aborting */
1148#define PR_3_ROOT_NOT_DIR_ABORT 0x030014
1149
1150/* Cannot proceed without a root inode. */
1151#define PR_3_NO_ROOT_INODE_ABORT 0x030015
1152
1153/* Internal error: couldn't find dir_info */
1154#define PR_3_NO_DIRINFO 0x030016
1155
1156/* Lost+found is not a directory */
1157#define PR_3_LPF_NOTDIR 0x030017
1158
1159/*
1160 * Pass 3a --- rehashing diretories
1161 */
1162/* Pass 3a: Reindexing directories */
1163#define PR_3A_PASS_HEADER 0x031000
1164
1165/* Error iterating over directories */
1166#define PR_3A_OPTIMIZE_ITER 0x031001
1167
1168/* Error rehash directory */
1169#define PR_3A_OPTIMIZE_DIR_ERR 0x031002
1170
1171/* Rehashing dir header */
1172#define PR_3A_OPTIMIZE_DIR_HEADER 0x031003
1173
1174/* Rehashing directory %d */
1175#define PR_3A_OPTIMIZE_DIR 0x031004
1176
1177/* Rehashing dir end */
1178#define PR_3A_OPTIMIZE_DIR_END 0x031005
1179
1180/*
1181 * Pass 4 errors
1182 */
1183
1184/* Pass 4: Checking reference counts */
1185#define PR_4_PASS_HEADER 0x040000
1186
1187/* Unattached zero-length inode */
1188#define PR_4_ZERO_LEN_INODE 0x040001
1189
1190/* Unattached inode */
1191#define PR_4_UNATTACHED_INODE 0x040002
1192
1193/* Inode ref count wrong */
1194#define PR_4_BAD_REF_COUNT 0x040003
1195
1196/* Inconsistent inode count information cached */
1197#define PR_4_INCONSISTENT_COUNT 0x040004
1198
1199/*
1200 * Pass 5 errors
1201 */
1202
1203/* Pass 5: Checking group summary information */
1204#define PR_5_PASS_HEADER 0x050000
1205
1206/* Padding at end of inode bitmap is not set. */
1207#define PR_5_INODE_BMAP_PADDING 0x050001
1208
1209/* Padding at end of block bitmap is not set. */
1210#define PR_5_BLOCK_BMAP_PADDING 0x050002
1211
1212/* Block bitmap differences header */
1213#define PR_5_BLOCK_BITMAP_HEADER 0x050003
1214
1215/* Block not used, but marked in bitmap */
1216#define PR_5_BLOCK_UNUSED 0x050004
1217
1218/* Block used, but not marked used in bitmap */
1219#define PR_5_BLOCK_USED 0x050005
1220
1221/* Block bitmap differences end */
1222#define PR_5_BLOCK_BITMAP_END 0x050006
1223
1224/* Inode bitmap differences header */
1225#define PR_5_INODE_BITMAP_HEADER 0x050007
1226
1227/* Inode not used, but marked in bitmap */
1228#define PR_5_INODE_UNUSED 0x050008
1229
1230/* Inode used, but not marked used in bitmap */
1231#define PR_5_INODE_USED 0x050009
1232
1233/* Inode bitmap differences end */
1234#define PR_5_INODE_BITMAP_END 0x05000A
1235
1236/* Free inodes count for group wrong */
1237#define PR_5_FREE_INODE_COUNT_GROUP 0x05000B
1238
1239/* Directories count for group wrong */
1240#define PR_5_FREE_DIR_COUNT_GROUP 0x05000C
1241
1242/* Free inodes count wrong */
1243#define PR_5_FREE_INODE_COUNT 0x05000D
1244
1245/* Free blocks count for group wrong */
1246#define PR_5_FREE_BLOCK_COUNT_GROUP 0x05000E
1247
1248/* Free blocks count wrong */
1249#define PR_5_FREE_BLOCK_COUNT 0x05000F
1250
1251/* Programming error: bitmap endpoints don't match */
1252#define PR_5_BMAP_ENDPOINTS 0x050010
1253
1254/* Internal error: fudging end of bitmap */
1255#define PR_5_FUDGE_BITMAP_ERROR 0x050011
1256
1257/* Error copying in replacement inode bitmap */
1258#define PR_5_COPY_IBITMAP_ERROR 0x050012
1259
1260/* Error copying in replacement block bitmap */
1261#define PR_5_COPY_BBITMAP_ERROR 0x050013
1262
1263/* Block range not used, but marked in bitmap */
1264#define PR_5_BLOCK_RANGE_UNUSED 0x050014
1265
1266/* Block range used, but not marked used in bitmap */
1267#define PR_5_BLOCK_RANGE_USED 0x050015
1268
1269/* Inode range not used, but marked in bitmap */
1270#define PR_5_INODE_RANGE_UNUSED 0x050016
1271
1272/* Inode rangeused, but not marked used in bitmap */
1273#define PR_5_INODE_RANGE_USED 0x050017
1274
1275/*
1276 * Function declarations
1277 */
1278static int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx);
1279static int end_problem_latch(e2fsck_t ctx, int mask);
1280static int set_latch_flags(int mask, int setflags, int clearflags);
1281static void clear_problem_context(struct problem_context *ctx);
1282
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001283/*
1284 * Dictionary Abstract Data Type
1285 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
1286 *
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001287 * dict.h v 1.22.2.6 2000/11/13 01:36:44 kaz
1288 * kazlib_1_20
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001289 */
1290
1291#ifndef DICT_H
1292#define DICT_H
1293
1294/*
1295 * Blurb for inclusion into C++ translation units
1296 */
1297
1298typedef unsigned long dictcount_t;
1299#define DICTCOUNT_T_MAX ULONG_MAX
1300
1301/*
1302 * The dictionary is implemented as a red-black tree
1303 */
1304
1305typedef enum { dnode_red, dnode_black } dnode_color_t;
1306
1307typedef struct dnode_t {
1308 struct dnode_t *dict_left;
1309 struct dnode_t *dict_right;
1310 struct dnode_t *dict_parent;
1311 dnode_color_t dict_color;
1312 const void *dict_key;
1313 void *dict_data;
1314} dnode_t;
1315
1316typedef int (*dict_comp_t)(const void *, const void *);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001317typedef void (*dnode_free_t)(dnode_t *);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001318
1319typedef struct dict_t {
1320 dnode_t dict_nilnode;
1321 dictcount_t dict_nodecount;
1322 dictcount_t dict_maxcount;
1323 dict_comp_t dict_compare;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001324 dnode_free_t dict_freenode;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001325 int dict_dupes;
1326} dict_t;
1327
1328typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
1329
1330typedef struct dict_load_t {
1331 dict_t *dict_dictptr;
1332 dnode_t dict_nilnode;
1333} dict_load_t;
1334
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001335#define dict_count(D) ((D)->dict_nodecount)
1336#define dnode_get(N) ((N)->dict_data)
1337#define dnode_getkey(N) ((N)->dict_key)
1338
1339#endif
1340
1341/*
1342 * Compatibility header file for e2fsck which should be included
1343 * instead of linux/jfs.h
1344 *
1345 * Copyright (C) 2000 Stephen C. Tweedie
1346 */
1347
1348/*
1349 * Pull in the definition of the e2fsck context structure
1350 */
1351
1352
1353struct buffer_head {
1354 char b_data[8192];
1355 e2fsck_t b_ctx;
1356 io_channel b_io;
1357 int b_size;
1358 blk_t b_blocknr;
1359 int b_dirty;
1360 int b_uptodate;
1361 int b_err;
1362};
1363
1364struct inode {
1365 e2fsck_t i_ctx;
1366 ext2_ino_t i_ino;
1367 struct ext2_inode i_ext2;
1368};
1369
1370struct kdev_s {
1371 e2fsck_t k_ctx;
1372 int k_dev;
1373};
1374
1375#define K_DEV_FS 1
1376#define K_DEV_JOURNAL 2
1377
1378typedef struct kdev_s *kdev_t;
1379
1380#define lock_buffer(bh) do {} while(0)
1381#define unlock_buffer(bh) do {} while(0)
1382#define buffer_req(bh) 1
1383#define do_readahead(journal, start) do {} while(0)
1384
1385static e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
1386
1387typedef struct {
1388 int object_length;
1389} kmem_cache_t;
1390
1391#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001392
1393/*
1394 * We use the standard libext2fs portability tricks for inline
1395 * functions.
1396 */
1397
1398static _INLINE_ kmem_cache_t * do_cache_create(int len)
1399{
1400 kmem_cache_t *new_cache;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001401
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001402 new_cache = malloc(sizeof(*new_cache));
1403 if (new_cache)
1404 new_cache->object_length = len;
1405 return new_cache;
1406}
1407
1408static _INLINE_ void do_cache_destroy(kmem_cache_t *cache)
1409{
1410 free(cache);
1411}
1412
1413/*
1414 * Now pull in the real linux/jfs.h definitions.
1415 */
1416#include "ext2fs/kernel-jbd.h"
1417
1418/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001419 * badblocks.c --- replace/append bad blocks to the bad block inode
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001420 */
1421
1422static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt,
1423 void *priv_data);
1424
1425
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00001426static void invalid_block(ext2_filsys fs FSCK_ATTR((unused)), blk_t blk)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001427{
1428 printf(_("Bad block %u out of range; ignored.\n"), blk);
1429 return;
1430}
1431
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001432static void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001433 int replace_bad_blocks)
1434{
1435 ext2_filsys fs = ctx->fs;
1436 errcode_t retval;
1437 badblocks_list bb_list = 0;
1438 FILE *f;
1439 char buf[1024];
1440
1441 e2fsck_read_bitmaps(ctx);
1442
1443 /*
1444 * Make sure the bad block inode is sane. If there are any
1445 * illegal blocks, clear them.
1446 */
1447 retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0,
1448 check_bb_inode_blocks, 0);
1449 if (retval) {
1450 com_err("ext2fs_block_iterate", retval,
1451 _("while sanity checking the bad blocks inode"));
1452 goto fatal;
1453 }
1454
1455 /*
1456 * If we're appending to the bad blocks inode, read in the
1457 * current bad blocks.
1458 */
1459 if (!replace_bad_blocks) {
1460 retval = ext2fs_read_bb_inode(fs, &bb_list);
1461 if (retval) {
1462 com_err("ext2fs_read_bb_inode", retval,
1463 _("while reading the bad blocks inode"));
1464 goto fatal;
1465 }
1466 }
1467
1468 /*
1469 * Now read in the bad blocks from the file; if
1470 * bad_blocks_file is null, then try to run the badblocks
1471 * command.
1472 */
1473 if (bad_blocks_file) {
1474 f = fopen(bad_blocks_file, "r");
1475 if (!f) {
1476 com_err("read_bad_blocks_file", errno,
1477 _("while trying to open %s"), bad_blocks_file);
1478 goto fatal;
1479 }
1480 } else {
1481 sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize,
1482 (ctx->options & E2F_OPT_PREEN) ? "" : "-s ",
1483 (ctx->options & E2F_OPT_WRITECHECK) ? "-n " : "",
1484 fs->device_name, fs->super->s_blocks_count);
1485 f = popen(buf, "r");
1486 if (!f) {
1487 com_err("read_bad_blocks_file", errno,
1488 _("while trying popen '%s'"), buf);
1489 goto fatal;
1490 }
1491 }
1492 retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
1493 if (bad_blocks_file)
1494 fclose(f);
1495 else
1496 pclose(f);
1497 if (retval) {
1498 com_err("ext2fs_read_bb_FILE", retval,
1499 _("while reading in list of bad blocks from file"));
1500 goto fatal;
1501 }
1502
1503 /*
1504 * Finally, update the bad blocks from the bad_block_map
1505 */
1506 retval = ext2fs_update_bb_inode(fs, bb_list);
1507 if (retval) {
1508 com_err("ext2fs_update_bb_inode", retval,
1509 _("while updating bad block inode"));
1510 goto fatal;
1511 }
1512
1513 ext2fs_badblocks_list_free(bb_list);
1514 return;
1515
1516fatal:
1517 ctx->flags |= E2F_FLAG_ABORT;
1518 return;
1519
1520}
1521
1522static int check_bb_inode_blocks(ext2_filsys fs,
1523 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00001524 int blockcnt FSCK_ATTR((unused)),
1525 void *priv_data FSCK_ATTR((unused)))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001526{
1527 if (!*block_nr)
1528 return 0;
1529
1530 /*
1531 * If the block number is outrageous, clear it and ignore it.
1532 */
1533 if (*block_nr >= fs->super->s_blocks_count ||
1534 *block_nr < fs->super->s_first_data_block) {
1535 printf(_("Warning illegal block %u found in bad block inode. Cleared.\n"), *block_nr);
1536 *block_nr = 0;
1537 return BLOCK_CHANGED;
1538 }
1539
1540 return 0;
1541}
1542
1543/*
1544 * Dictionary Abstract Data Type
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001545 */
1546
1547
1548/*
1549 * These macros provide short convenient names for structure members,
1550 * which are embellished with dict_ prefixes so that they are
1551 * properly confined to the documented namespace. It's legal for a
1552 * program which uses dict to define, for instance, a macro called ``parent''.
1553 * Such a macro would interfere with the dnode_t struct definition.
1554 * In general, highly portable and reusable C modules which expose their
1555 * structures need to confine structure member names to well-defined spaces.
1556 * The resulting identifiers aren't necessarily convenient to use, nor
1557 * readable, in the implementation, however!
1558 */
1559
1560#define left dict_left
1561#define right dict_right
1562#define parent dict_parent
1563#define color dict_color
1564#define key dict_key
1565#define data dict_data
1566
1567#define nilnode dict_nilnode
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001568#define maxcount dict_maxcount
1569#define compare dict_compare
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001570#define dupes dict_dupes
1571
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001572#define dict_root(D) ((D)->nilnode.left)
1573#define dict_nil(D) (&(D)->nilnode)
1574#define DICT_DEPTH_MAX 64
1575
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001576static void dnode_free(dnode_t *node);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001577
1578/*
1579 * Perform a ``left rotation'' adjustment on the tree. The given node P and
1580 * its right child C are rearranged so that the P instead becomes the left
1581 * child of C. The left subtree of C is inherited as the new right subtree
1582 * for P. The ordering of the keys within the tree is thus preserved.
1583 */
1584
1585static void rotate_left(dnode_t *upper)
1586{
1587 dnode_t *lower, *lowleft, *upparent;
1588
1589 lower = upper->right;
1590 upper->right = lowleft = lower->left;
1591 lowleft->parent = upper;
1592
1593 lower->parent = upparent = upper->parent;
1594
1595 /* don't need to check for root node here because root->parent is
1596 the sentinel nil node, and root->parent->left points back to root */
1597
1598 if (upper == upparent->left) {
1599 upparent->left = lower;
1600 } else {
1601 assert (upper == upparent->right);
1602 upparent->right = lower;
1603 }
1604
1605 lower->left = upper;
1606 upper->parent = lower;
1607}
1608
1609/*
1610 * This operation is the ``mirror'' image of rotate_left. It is
1611 * the same procedure, but with left and right interchanged.
1612 */
1613
1614static void rotate_right(dnode_t *upper)
1615{
1616 dnode_t *lower, *lowright, *upparent;
1617
1618 lower = upper->left;
1619 upper->left = lowright = lower->right;
1620 lowright->parent = upper;
1621
1622 lower->parent = upparent = upper->parent;
1623
1624 if (upper == upparent->right) {
1625 upparent->right = lower;
1626 } else {
1627 assert (upper == upparent->left);
1628 upparent->left = lower;
1629 }
1630
1631 lower->right = upper;
1632 upper->parent = lower;
1633}
1634
1635/*
1636 * Do a postorder traversal of the tree rooted at the specified
1637 * node and free everything under it. Used by dict_free().
1638 */
1639
1640static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
1641{
1642 if (node == nil)
1643 return;
1644 free_nodes(dict, node->left, nil);
1645 free_nodes(dict, node->right, nil);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001646 dict->dict_freenode(node);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001647}
1648
1649/*
1650 * Verify that the tree contains the given node. This is done by
1651 * traversing all of the nodes and comparing their pointers to the
1652 * given pointer. Returns 1 if the node is found, otherwise
1653 * returns zero. It is intended for debugging purposes.
1654 */
1655
1656static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
1657{
1658 if (root != nil) {
1659 return root == node
1660 || verify_dict_has_node(nil, root->left, node)
1661 || verify_dict_has_node(nil, root->right, node);
1662 }
1663 return 0;
1664}
1665
1666
1667/*
1668 * Select a different set of node allocator routines.
1669 */
1670
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001671static void dict_set_allocator(dict_t *dict, dnode_free_t fr)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001672{
1673 assert (dict_count(dict) == 0);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001674 dict->dict_freenode = fr;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001675}
1676
1677/*
1678 * Free all the nodes in the dictionary by using the dictionary's
1679 * installed free routine. The dictionary is emptied.
1680 */
1681
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001682static void dict_free_nodes(dict_t *dict)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001683{
1684 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
1685 free_nodes(dict, root, nil);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001686 dict->dict_nodecount = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001687 dict->nilnode.left = &dict->nilnode;
1688 dict->nilnode.right = &dict->nilnode;
1689}
1690
1691/*
1692 * Initialize a user-supplied dictionary object.
1693 */
1694
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001695static dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001696{
1697 dict->compare = comp;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001698 dict->dict_freenode = dnode_free;
1699 dict->dict_nodecount = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001700 dict->maxcount = maxcount;
1701 dict->nilnode.left = &dict->nilnode;
1702 dict->nilnode.right = &dict->nilnode;
1703 dict->nilnode.parent = &dict->nilnode;
1704 dict->nilnode.color = dnode_black;
1705 dict->dupes = 0;
1706 return dict;
1707}
1708
1709/*
1710 * Locate a node in the dictionary having the given key.
1711 * If the node is not found, a null a pointer is returned (rather than
1712 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
1713 * located node is returned.
1714 */
1715
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001716static dnode_t *dict_lookup(dict_t *dict, const void *key)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001717{
1718 dnode_t *root = dict_root(dict);
1719 dnode_t *nil = dict_nil(dict);
1720 dnode_t *saved;
1721 int result;
1722
1723 /* simple binary search adapted for trees that contain duplicate keys */
1724
1725 while (root != nil) {
1726 result = dict->compare(key, root->key);
1727 if (result < 0)
1728 root = root->left;
1729 else if (result > 0)
1730 root = root->right;
1731 else {
1732 if (!dict->dupes) { /* no duplicates, return match */
1733 return root;
1734 } else { /* could be dupes, find leftmost one */
1735 do {
1736 saved = root;
1737 root = root->left;
1738 while (root != nil && dict->compare(key, root->key))
1739 root = root->right;
1740 } while (root != nil);
1741 return saved;
1742 }
1743 }
1744 }
1745
1746 return NULL;
1747}
1748
1749/*
1750 * Insert a node into the dictionary. The node should have been
1751 * initialized with a data field. All other fields are ignored.
1752 * The behavior is undefined if the user attempts to insert into
1753 * a dictionary that is already full (for which the dict_isfull()
1754 * function returns true).
1755 */
1756
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001757static void dict_insert(dict_t *dict, dnode_t *node, const void *key)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001758{
1759 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
1760 dnode_t *parent = nil, *uncle, *grandpa;
1761 int result = -1;
1762
1763 node->key = key;
1764
1765 /* basic binary tree insert */
1766
1767 while (where != nil) {
1768 parent = where;
1769 result = dict->compare(key, where->key);
1770 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
1771 assert (dict->dupes || result != 0);
1772 if (result < 0)
1773 where = where->left;
1774 else
1775 where = where->right;
1776 }
1777
1778 assert (where == nil);
1779
1780 if (result < 0)
1781 parent->left = node;
1782 else
1783 parent->right = node;
1784
1785 node->parent = parent;
1786 node->left = nil;
1787 node->right = nil;
1788
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001789 dict->dict_nodecount++;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001790
1791 /* red black adjustments */
1792
1793 node->color = dnode_red;
1794
1795 while (parent->color == dnode_red) {
1796 grandpa = parent->parent;
1797 if (parent == grandpa->left) {
1798 uncle = grandpa->right;
1799 if (uncle->color == dnode_red) { /* red parent, red uncle */
1800 parent->color = dnode_black;
1801 uncle->color = dnode_black;
1802 grandpa->color = dnode_red;
1803 node = grandpa;
1804 parent = grandpa->parent;
1805 } else { /* red parent, black uncle */
1806 if (node == parent->right) {
1807 rotate_left(parent);
1808 parent = node;
1809 assert (grandpa == parent->parent);
1810 /* rotation between parent and child preserves grandpa */
1811 }
1812 parent->color = dnode_black;
1813 grandpa->color = dnode_red;
1814 rotate_right(grandpa);
1815 break;
1816 }
1817 } else { /* symmetric cases: parent == parent->parent->right */
1818 uncle = grandpa->left;
1819 if (uncle->color == dnode_red) {
1820 parent->color = dnode_black;
1821 uncle->color = dnode_black;
1822 grandpa->color = dnode_red;
1823 node = grandpa;
1824 parent = grandpa->parent;
1825 } else {
1826 if (node == parent->left) {
1827 rotate_right(parent);
1828 parent = node;
1829 assert (grandpa == parent->parent);
1830 }
1831 parent->color = dnode_black;
1832 grandpa->color = dnode_red;
1833 rotate_left(grandpa);
1834 break;
1835 }
1836 }
1837 }
1838
1839 dict_root(dict)->color = dnode_black;
1840
1841}
1842
1843/*
1844 * Allocate a node using the dictionary's allocator routine, give it
1845 * the data item.
1846 */
1847
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001848static dnode_t *dnode_init(dnode_t *dnode, void *data)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001849{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001850 dnode->data = data;
1851 dnode->parent = NULL;
1852 dnode->left = NULL;
1853 dnode->right = NULL;
1854 return dnode;
1855}
1856
1857static int dict_alloc_insert(dict_t *dict, const void *key, void *data)
1858{
1859 dnode_t *node = malloc(sizeof(dnode_t));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001860
1861 if (node) {
1862 dnode_init(node, data);
1863 dict_insert(dict, node, key);
1864 return 1;
1865 }
1866 return 0;
1867}
1868
1869/*
1870 * Return the node with the lowest (leftmost) key. If the dictionary is empty
1871 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
1872 */
1873
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001874static dnode_t *dict_first(dict_t *dict)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001875{
1876 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
1877
1878 if (root != nil)
1879 while ((left = root->left) != nil)
1880 root = left;
1881
1882 return (root == nil) ? NULL : root;
1883}
1884
1885/*
1886 * Return the given node's successor node---the node which has the
1887 * next key in the the left to right ordering. If the node has
1888 * no successor, a null pointer is returned rather than a pointer to
1889 * the nil node.
1890 */
1891
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001892static dnode_t *dict_next(dict_t *dict, dnode_t *curr)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001893{
1894 dnode_t *nil = dict_nil(dict), *parent, *left;
1895
1896 if (curr->right != nil) {
1897 curr = curr->right;
1898 while ((left = curr->left) != nil)
1899 curr = left;
1900 return curr;
1901 }
1902
1903 parent = curr->parent;
1904
1905 while (parent != nil && curr == parent->right) {
1906 curr = parent;
1907 parent = curr->parent;
1908 }
1909
1910 return (parent == nil) ? NULL : parent;
1911}
1912
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001913
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001914static void dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001915{
1916 free(node);
1917}
1918
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001919
1920#undef left
1921#undef right
1922#undef parent
1923#undef color
1924#undef key
1925#undef data
1926
1927#undef nilnode
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001928#undef maxcount
1929#undef compare
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001930#undef dupes
1931
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001932
1933/*
1934 * dirinfo.c --- maintains the directory information table for e2fsck.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001935 */
1936
1937/*
1938 * This subroutine is called during pass1 to create a directory info
1939 * entry. During pass1, the passed-in parent is 0; it will get filled
1940 * in during pass2.
1941 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001942static void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001943{
1944 struct dir_info *dir;
1945 int i, j;
1946 ext2_ino_t num_dirs;
1947 errcode_t retval;
1948 unsigned long old_size;
1949
1950#if 0
1951 printf("add_dir_info for inode %lu...\n", ino);
1952#endif
1953 if (!ctx->dir_info) {
1954 ctx->dir_info_count = 0;
1955 retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
1956 if (retval)
1957 num_dirs = 1024; /* Guess */
1958 ctx->dir_info_size = num_dirs + 10;
1959 ctx->dir_info = (struct dir_info *)
1960 e2fsck_allocate_memory(ctx, ctx->dir_info_size
1961 * sizeof (struct dir_info),
1962 "directory map");
1963 }
1964
1965 if (ctx->dir_info_count >= ctx->dir_info_size) {
1966 old_size = ctx->dir_info_size * sizeof(struct dir_info);
1967 ctx->dir_info_size += 10;
1968 retval = ext2fs_resize_mem(old_size, ctx->dir_info_size *
1969 sizeof(struct dir_info),
1970 &ctx->dir_info);
1971 if (retval) {
1972 ctx->dir_info_size -= 10;
1973 return;
1974 }
1975 }
1976
1977 /*
1978 * Normally, add_dir_info is called with each inode in
1979 * sequential order; but once in a while (like when pass 3
1980 * needs to recreate the root directory or lost+found
1981 * directory) it is called out of order. In those cases, we
1982 * need to move the dir_info entries down to make room, since
1983 * the dir_info array needs to be sorted by inode number for
1984 * get_dir_info()'s sake.
1985 */
1986 if (ctx->dir_info_count &&
1987 ctx->dir_info[ctx->dir_info_count-1].ino >= ino) {
1988 for (i = ctx->dir_info_count-1; i > 0; i--)
1989 if (ctx->dir_info[i-1].ino < ino)
1990 break;
1991 dir = &ctx->dir_info[i];
1992 if (dir->ino != ino)
1993 for (j = ctx->dir_info_count++; j > i; j--)
1994 ctx->dir_info[j] = ctx->dir_info[j-1];
1995 } else
1996 dir = &ctx->dir_info[ctx->dir_info_count++];
1997
1998 dir->ino = ino;
1999 dir->dotdot = parent;
2000 dir->parent = parent;
2001}
2002
2003/*
2004 * get_dir_info() --- given an inode number, try to find the directory
2005 * information entry for it.
2006 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002007static struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002008{
2009 int low, high, mid;
2010
2011 low = 0;
2012 high = ctx->dir_info_count-1;
2013 if (!ctx->dir_info)
2014 return 0;
2015 if (ino == ctx->dir_info[low].ino)
2016 return &ctx->dir_info[low];
2017 if (ino == ctx->dir_info[high].ino)
2018 return &ctx->dir_info[high];
2019
2020 while (low < high) {
2021 mid = (low+high)/2;
2022 if (mid == low || mid == high)
2023 break;
2024 if (ino == ctx->dir_info[mid].ino)
2025 return &ctx->dir_info[mid];
2026 if (ino < ctx->dir_info[mid].ino)
2027 high = mid;
2028 else
2029 low = mid;
2030 }
2031 return 0;
2032}
2033
2034/*
2035 * Free the dir_info structure when it isn't needed any more.
2036 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002037static void e2fsck_free_dir_info(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002038{
2039 if (ctx->dir_info) {
2040 ext2fs_free_mem(&ctx->dir_info);
2041 ctx->dir_info = 0;
2042 }
2043 ctx->dir_info_size = 0;
2044 ctx->dir_info_count = 0;
2045}
2046
2047/*
2048 * Return the count of number of directories in the dir_info structure
2049 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002050static inline int e2fsck_get_num_dirinfo(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002051{
2052 return ctx->dir_info_count;
2053}
2054
2055/*
2056 * A simple interator function
2057 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002058static struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002059{
2060 if (*control >= ctx->dir_info_count)
2061 return 0;
2062
2063 return(ctx->dir_info + (*control)++);
2064}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002065
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002066/*
2067 * dirinfo.c --- maintains the directory information table for e2fsck.
2068 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002069 */
2070
2071#ifdef ENABLE_HTREE
2072
2073/*
2074 * This subroutine is called during pass1 to create a directory info
2075 * entry. During pass1, the passed-in parent is 0; it will get filled
2076 * in during pass2.
2077 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002078static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002079{
2080 struct dx_dir_info *dir;
2081 int i, j;
2082 errcode_t retval;
2083 unsigned long old_size;
2084
2085#if 0
2086 printf("add_dx_dir_info for inode %lu...\n", ino);
2087#endif
2088 if (!ctx->dx_dir_info) {
2089 ctx->dx_dir_info_count = 0;
2090 ctx->dx_dir_info_size = 100; /* Guess */
2091 ctx->dx_dir_info = (struct dx_dir_info *)
2092 e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
2093 * sizeof (struct dx_dir_info),
2094 "directory map");
2095 }
2096
2097 if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
2098 old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
2099 ctx->dx_dir_info_size += 10;
2100 retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
2101 sizeof(struct dx_dir_info),
2102 &ctx->dx_dir_info);
2103 if (retval) {
2104 ctx->dx_dir_info_size -= 10;
2105 return;
2106 }
2107 }
2108
2109 /*
2110 * Normally, add_dx_dir_info is called with each inode in
2111 * sequential order; but once in a while (like when pass 3
2112 * needs to recreate the root directory or lost+found
2113 * directory) it is called out of order. In those cases, we
2114 * need to move the dx_dir_info entries down to make room, since
2115 * the dx_dir_info array needs to be sorted by inode number for
2116 * get_dx_dir_info()'s sake.
2117 */
2118 if (ctx->dx_dir_info_count &&
2119 ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
2120 for (i = ctx->dx_dir_info_count-1; i > 0; i--)
2121 if (ctx->dx_dir_info[i-1].ino < ino)
2122 break;
2123 dir = &ctx->dx_dir_info[i];
2124 if (dir->ino != ino)
2125 for (j = ctx->dx_dir_info_count++; j > i; j--)
2126 ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
2127 } else
2128 dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
2129
2130 dir->ino = ino;
2131 dir->numblocks = num_blocks;
2132 dir->hashversion = 0;
2133 dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
2134 * sizeof (struct dx_dirblock_info),
2135 "dx_block info array");
2136
2137}
2138
2139/*
2140 * get_dx_dir_info() --- given an inode number, try to find the directory
2141 * information entry for it.
2142 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002143static struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002144{
2145 int low, high, mid;
2146
2147 low = 0;
2148 high = ctx->dx_dir_info_count-1;
2149 if (!ctx->dx_dir_info)
2150 return 0;
2151 if (ino == ctx->dx_dir_info[low].ino)
2152 return &ctx->dx_dir_info[low];
2153 if (ino == ctx->dx_dir_info[high].ino)
2154 return &ctx->dx_dir_info[high];
2155
2156 while (low < high) {
2157 mid = (low+high)/2;
2158 if (mid == low || mid == high)
2159 break;
2160 if (ino == ctx->dx_dir_info[mid].ino)
2161 return &ctx->dx_dir_info[mid];
2162 if (ino < ctx->dx_dir_info[mid].ino)
2163 high = mid;
2164 else
2165 low = mid;
2166 }
2167 return 0;
2168}
2169
2170/*
2171 * Free the dx_dir_info structure when it isn't needed any more.
2172 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002173static void e2fsck_free_dx_dir_info(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002174{
2175 int i;
2176 struct dx_dir_info *dir;
2177
2178 if (ctx->dx_dir_info) {
2179 dir = ctx->dx_dir_info;
2180 for (i=0; i < ctx->dx_dir_info_count; i++) {
2181 if (dir->dx_block) {
2182 ext2fs_free_mem(&dir->dx_block);
2183 dir->dx_block = 0;
2184 }
2185 }
2186 ext2fs_free_mem(&ctx->dx_dir_info);
2187 ctx->dx_dir_info = 0;
2188 }
2189 ctx->dx_dir_info_size = 0;
2190 ctx->dx_dir_info_count = 0;
2191}
2192
2193/*
2194 * A simple interator function
2195 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002196static struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002197{
2198 if (*control >= ctx->dx_dir_info_count)
2199 return 0;
2200
2201 return(ctx->dx_dir_info + (*control)++);
2202}
2203
2204#endif /* ENABLE_HTREE */
2205/*
2206 * e2fsck.c - a consistency checker for the new extended file system.
2207 *
Mike Frysinger51a43b42005-09-24 07:11:16 +00002208 */
2209
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002210/*
2211 * This function allocates an e2fsck context
2212 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002213static errcode_t e2fsck_allocate_context(e2fsck_t *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002214{
2215 e2fsck_t context;
2216 errcode_t retval;
2217
2218 retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
2219 if (retval)
2220 return retval;
2221
2222 memset(context, 0, sizeof(struct e2fsck_struct));
2223
2224 context->process_inode_size = 256;
2225 context->ext_attr_ver = 2;
2226
2227 *ret = context;
2228 return 0;
2229}
2230
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002231struct ea_refcount_el {
2232 blk_t ea_blk;
2233 int ea_count;
2234};
2235
2236struct ea_refcount {
2237 blk_t count;
2238 blk_t size;
2239 blk_t cursor;
2240 struct ea_refcount_el *list;
2241};
2242
2243static void ea_refcount_free(ext2_refcount_t refcount)
2244{
2245 if (!refcount)
2246 return;
2247
2248 if (refcount->list)
2249 ext2fs_free_mem(&refcount->list);
2250 ext2fs_free_mem(&refcount);
2251}
2252
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002253/*
2254 * This function resets an e2fsck context; it is called when e2fsck
2255 * needs to be restarted.
2256 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002257static errcode_t e2fsck_reset_context(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002258{
2259 ctx->flags = 0;
2260 ctx->lost_and_found = 0;
2261 ctx->bad_lost_and_found = 0;
2262 if (ctx->inode_used_map) {
2263 ext2fs_free_inode_bitmap(ctx->inode_used_map);
2264 ctx->inode_used_map = 0;
2265 }
2266 if (ctx->inode_dir_map) {
2267 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
2268 ctx->inode_dir_map = 0;
2269 }
2270 if (ctx->inode_reg_map) {
2271 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
2272 ctx->inode_reg_map = 0;
2273 }
2274 if (ctx->block_found_map) {
2275 ext2fs_free_block_bitmap(ctx->block_found_map);
2276 ctx->block_found_map = 0;
2277 }
2278 if (ctx->inode_link_info) {
2279 ext2fs_free_icount(ctx->inode_link_info);
2280 ctx->inode_link_info = 0;
2281 }
2282 if (ctx->journal_io) {
2283 if (ctx->fs && ctx->fs->io != ctx->journal_io)
2284 io_channel_close(ctx->journal_io);
2285 ctx->journal_io = 0;
2286 }
2287 if (ctx->fs && ctx->fs->dblist) {
2288 ext2fs_free_dblist(ctx->fs->dblist);
2289 ctx->fs->dblist = 0;
2290 }
2291 e2fsck_free_dir_info(ctx);
2292#ifdef ENABLE_HTREE
2293 e2fsck_free_dx_dir_info(ctx);
Mike Frysinger51a43b42005-09-24 07:11:16 +00002294#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002295 if (ctx->refcount) {
2296 ea_refcount_free(ctx->refcount);
2297 ctx->refcount = 0;
2298 }
2299 if (ctx->refcount_extra) {
2300 ea_refcount_free(ctx->refcount_extra);
2301 ctx->refcount_extra = 0;
2302 }
2303 if (ctx->block_dup_map) {
2304 ext2fs_free_block_bitmap(ctx->block_dup_map);
2305 ctx->block_dup_map = 0;
2306 }
2307 if (ctx->block_ea_map) {
2308 ext2fs_free_block_bitmap(ctx->block_ea_map);
2309 ctx->block_ea_map = 0;
2310 }
2311 if (ctx->inode_bb_map) {
2312 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
2313 ctx->inode_bb_map = 0;
2314 }
2315 if (ctx->inode_bad_map) {
2316 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
2317 ctx->inode_bad_map = 0;
2318 }
2319 if (ctx->inode_imagic_map) {
2320 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
2321 ctx->inode_imagic_map = 0;
2322 }
2323 if (ctx->dirs_to_hash) {
2324 ext2fs_u32_list_free(ctx->dirs_to_hash);
2325 ctx->dirs_to_hash = 0;
2326 }
2327
2328 /*
2329 * Clear the array of invalid meta-data flags
2330 */
2331 if (ctx->invalid_inode_bitmap_flag) {
2332 ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
2333 ctx->invalid_inode_bitmap_flag = 0;
2334 }
2335 if (ctx->invalid_block_bitmap_flag) {
2336 ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
2337 ctx->invalid_block_bitmap_flag = 0;
2338 }
2339 if (ctx->invalid_inode_table_flag) {
2340 ext2fs_free_mem(&ctx->invalid_inode_table_flag);
2341 ctx->invalid_inode_table_flag = 0;
2342 }
2343
2344 /* Clear statistic counters */
2345 ctx->fs_directory_count = 0;
2346 ctx->fs_regular_count = 0;
2347 ctx->fs_blockdev_count = 0;
2348 ctx->fs_chardev_count = 0;
2349 ctx->fs_links_count = 0;
2350 ctx->fs_symlinks_count = 0;
2351 ctx->fs_fast_symlinks_count = 0;
2352 ctx->fs_fifo_count = 0;
2353 ctx->fs_total_count = 0;
2354 ctx->fs_badblocks_count = 0;
2355 ctx->fs_sockets_count = 0;
2356 ctx->fs_ind_count = 0;
2357 ctx->fs_dind_count = 0;
2358 ctx->fs_tind_count = 0;
2359 ctx->fs_fragmented = 0;
2360 ctx->large_files = 0;
2361
2362 /* Reset the superblock to the user's requested value */
2363 ctx->superblock = ctx->use_superblock;
2364
2365 return 0;
2366}
2367
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002368static void e2fsck_free_context(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002369{
2370 if (!ctx)
2371 return;
2372
2373 e2fsck_reset_context(ctx);
2374 if (ctx->blkid)
2375 blkid_put_cache(ctx->blkid);
2376
2377 ext2fs_free_mem(&ctx);
2378}
2379
2380/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002381 * ea_refcount.c
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002382 */
2383
2384/*
2385 * The strategy we use for keeping track of EA refcounts is as
2386 * follows. We keep a sorted array of first EA blocks and its
2387 * reference counts. Once the refcount has dropped to zero, it is
2388 * removed from the array to save memory space. Once the EA block is
2389 * checked, its bit is set in the block_ea_map bitmap.
2390 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002391
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002392
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002393static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002394{
2395 ext2_refcount_t refcount;
2396 errcode_t retval;
2397 size_t bytes;
2398
2399 retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount);
2400 if (retval)
2401 return retval;
2402 memset(refcount, 0, sizeof(struct ea_refcount));
2403
2404 if (!size)
2405 size = 500;
2406 refcount->size = size;
2407 bytes = (size_t) (size * sizeof(struct ea_refcount_el));
2408#ifdef DEBUG
2409 printf("Refcount allocated %d entries, %d bytes.\n",
2410 refcount->size, bytes);
2411#endif
2412 retval = ext2fs_get_mem(bytes, &refcount->list);
2413 if (retval)
2414 goto errout;
2415 memset(refcount->list, 0, bytes);
2416
2417 refcount->count = 0;
2418 refcount->cursor = 0;
2419
2420 *ret = refcount;
2421 return 0;
2422
2423errout:
2424 ea_refcount_free(refcount);
2425 return(retval);
2426}
2427
2428/*
2429 * collapse_refcount() --- go through the refcount array, and get rid
2430 * of any count == zero entries
2431 */
2432static void refcount_collapse(ext2_refcount_t refcount)
2433{
2434 unsigned int i, j;
2435 struct ea_refcount_el *list;
2436
2437 list = refcount->list;
2438 for (i = 0, j = 0; i < refcount->count; i++) {
2439 if (list[i].ea_count) {
2440 if (i != j)
2441 list[j] = list[i];
2442 j++;
2443 }
2444 }
2445#if defined(DEBUG) || defined(TEST_PROGRAM)
2446 printf("Refcount_collapse: size was %d, now %d\n",
2447 refcount->count, j);
2448#endif
2449 refcount->count = j;
2450}
2451
2452
2453/*
2454 * insert_refcount_el() --- Insert a new entry into the sorted list at a
2455 * specified position.
2456 */
2457static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
2458 blk_t blk, int pos)
2459{
2460 struct ea_refcount_el *el;
2461 errcode_t retval;
2462 blk_t new_size = 0;
2463 int num;
2464
2465 if (refcount->count >= refcount->size) {
2466 new_size = refcount->size + 100;
2467#ifdef DEBUG
2468 printf("Reallocating refcount %d entries...\n", new_size);
2469#endif
2470 retval = ext2fs_resize_mem((size_t) refcount->size *
2471 sizeof(struct ea_refcount_el),
2472 (size_t) new_size *
2473 sizeof(struct ea_refcount_el),
2474 &refcount->list);
2475 if (retval)
2476 return 0;
2477 refcount->size = new_size;
2478 }
2479 num = (int) refcount->count - pos;
2480 if (num < 0)
2481 return 0; /* should never happen */
2482 if (num) {
2483 memmove(&refcount->list[pos+1], &refcount->list[pos],
2484 sizeof(struct ea_refcount_el) * num);
2485 }
2486 refcount->count++;
2487 el = &refcount->list[pos];
2488 el->ea_count = 0;
2489 el->ea_blk = blk;
2490 return el;
2491}
2492
2493
2494/*
2495 * get_refcount_el() --- given an block number, try to find refcount
2496 * information in the sorted list. If the create flag is set,
2497 * and we can't find an entry, create one in the sorted list.
2498 */
2499static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
2500 blk_t blk, int create)
2501{
2502 float range;
2503 int low, high, mid;
2504 blk_t lowval, highval;
2505
2506 if (!refcount || !refcount->list)
2507 return 0;
2508retry:
2509 low = 0;
2510 high = (int) refcount->count-1;
2511 if (create && ((refcount->count == 0) ||
2512 (blk > refcount->list[high].ea_blk))) {
2513 if (refcount->count >= refcount->size)
2514 refcount_collapse(refcount);
2515
2516 return insert_refcount_el(refcount, blk,
2517 (unsigned) refcount->count);
2518 }
2519 if (refcount->count == 0)
2520 return 0;
2521
2522 if (refcount->cursor >= refcount->count)
2523 refcount->cursor = 0;
2524 if (blk == refcount->list[refcount->cursor].ea_blk)
2525 return &refcount->list[refcount->cursor++];
2526#ifdef DEBUG
2527 printf("Non-cursor get_refcount_el: %u\n", blk);
2528#endif
2529 while (low <= high) {
2530#if 0
2531 mid = (low+high)/2;
Mike Frysinger51a43b42005-09-24 07:11:16 +00002532#else
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002533 if (low == high)
2534 mid = low;
2535 else {
2536 /* Interpolate for efficiency */
2537 lowval = refcount->list[low].ea_blk;
2538 highval = refcount->list[high].ea_blk;
2539
2540 if (blk < lowval)
2541 range = 0;
2542 else if (blk > highval)
2543 range = 1;
2544 else
2545 range = ((float) (blk - lowval)) /
2546 (highval - lowval);
2547 mid = low + ((int) (range * (high-low)));
2548 }
Mike Frysinger51a43b42005-09-24 07:11:16 +00002549#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002550 if (blk == refcount->list[mid].ea_blk) {
2551 refcount->cursor = mid+1;
2552 return &refcount->list[mid];
2553 }
2554 if (blk < refcount->list[mid].ea_blk)
2555 high = mid-1;
2556 else
2557 low = mid+1;
2558 }
2559 /*
2560 * If we need to create a new entry, it should be right at
2561 * low (where high will be left at low-1).
2562 */
2563 if (create) {
2564 if (refcount->count >= refcount->size) {
2565 refcount_collapse(refcount);
2566 if (refcount->count < refcount->size)
2567 goto retry;
2568 }
2569 return insert_refcount_el(refcount, blk, low);
2570 }
2571 return 0;
2572}
2573
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002574static errcode_t
2575ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002576{
2577 struct ea_refcount_el *el;
2578
2579 el = get_refcount_el(refcount, blk, 1);
2580 if (!el)
2581 return EXT2_ET_NO_MEMORY;
2582 el->ea_count++;
2583
2584 if (ret)
2585 *ret = el->ea_count;
2586 return 0;
2587}
2588
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002589static errcode_t
2590ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002591{
2592 struct ea_refcount_el *el;
2593
2594 el = get_refcount_el(refcount, blk, 0);
2595 if (!el || el->ea_count == 0)
2596 return EXT2_ET_INVALID_ARGUMENT;
2597
2598 el->ea_count--;
2599
2600 if (ret)
2601 *ret = el->ea_count;
2602 return 0;
2603}
2604
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002605static errcode_t
2606ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002607{
2608 struct ea_refcount_el *el;
2609
2610 /*
2611 * Get the refcount element
2612 */
2613 el = get_refcount_el(refcount, blk, count ? 1 : 0);
2614 if (!el)
2615 return count ? EXT2_ET_NO_MEMORY : 0;
2616 el->ea_count = count;
2617 return 0;
2618}
2619
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002620static inline void ea_refcount_intr_begin(ext2_refcount_t refcount)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002621{
2622 refcount->cursor = 0;
2623}
2624
2625
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002626static blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002627{
2628 struct ea_refcount_el *list;
2629
2630 while (1) {
2631 if (refcount->cursor >= refcount->count)
2632 return 0;
2633 list = refcount->list;
2634 if (list[refcount->cursor].ea_count) {
2635 if (ret)
2636 *ret = list[refcount->cursor].ea_count;
2637 return list[refcount->cursor++].ea_blk;
2638 }
2639 refcount->cursor++;
2640 }
2641}
2642
2643
2644/*
2645 * ehandler.c --- handle bad block errors which come up during the
2646 * course of an e2fsck session.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002647 */
2648
2649
2650static const char *operation;
2651
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002652static errcode_t
2653e2fsck_handle_read_error(io_channel channel, unsigned long block, int count,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00002654 void *data, size_t size FSCK_ATTR((unused)),
2655 int actual FSCK_ATTR((unused)), errcode_t error)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002656{
2657 int i;
2658 char *p;
2659 ext2_filsys fs = (ext2_filsys) channel->app_data;
2660 e2fsck_t ctx;
2661
2662 ctx = (e2fsck_t) fs->priv_data;
2663
2664 /*
2665 * If more than one block was read, try reading each block
2666 * separately. We could use the actual bytes read to figure
2667 * out where to start, but we don't bother.
2668 */
2669 if (count > 1) {
2670 p = (char *) data;
2671 for (i=0; i < count; i++, p += channel->block_size, block++) {
2672 error = io_channel_read_blk(channel, block,
2673 1, p);
2674 if (error)
2675 return error;
2676 }
2677 return 0;
2678 }
2679 if (operation)
2680 printf(_("Error reading block %lu (%s) while %s. "), block,
2681 error_message(error), operation);
2682 else
2683 printf(_("Error reading block %lu (%s). "), block,
2684 error_message(error));
2685 preenhalt(ctx);
2686 if (ask(ctx, _("Ignore error"), 1)) {
2687 if (ask(ctx, _("Force rewrite"), 1))
2688 io_channel_write_blk(channel, block, 1, data);
2689 return 0;
2690 }
2691
2692 return error;
2693}
2694
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002695static errcode_t
2696e2fsck_handle_write_error(io_channel channel, unsigned long block, int count,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00002697 const void *data, size_t size FSCK_ATTR((unused)),
2698 int actual FSCK_ATTR((unused)), errcode_t error)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002699{
2700 int i;
2701 const char *p;
2702 ext2_filsys fs = (ext2_filsys) channel->app_data;
2703 e2fsck_t ctx;
2704
2705 ctx = (e2fsck_t) fs->priv_data;
2706
2707 /*
2708 * If more than one block was written, try writing each block
2709 * separately. We could use the actual bytes read to figure
2710 * out where to start, but we don't bother.
2711 */
2712 if (count > 1) {
2713 p = (const char *) data;
2714 for (i=0; i < count; i++, p += channel->block_size, block++) {
2715 error = io_channel_write_blk(channel, block,
2716 1, p);
2717 if (error)
2718 return error;
2719 }
2720 return 0;
2721 }
2722
2723 if (operation)
2724 printf(_("Error writing block %lu (%s) while %s. "), block,
2725 error_message(error), operation);
2726 else
2727 printf(_("Error writing block %lu (%s). "), block,
2728 error_message(error));
2729 preenhalt(ctx);
2730 if (ask(ctx, _("Ignore error"), 1))
2731 return 0;
2732
2733 return error;
2734}
2735
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002736static inline const char *ehandler_operation(const char *op)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002737{
2738 const char *ret = operation;
2739
2740 operation = op;
2741 return ret;
2742}
2743
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002744static void ehandler_init(io_channel channel)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002745{
2746 channel->read_error = e2fsck_handle_read_error;
2747 channel->write_error = e2fsck_handle_write_error;
2748}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002749
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002750/*
2751 * journal.c --- code for handling the "ext3" journal
2752 *
2753 * Copyright (C) 2000 Andreas Dilger
2754 * Copyright (C) 2000 Theodore Ts'o
2755 *
2756 * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie
2757 * Copyright (C) 1999 Red Hat Software
2758 *
2759 * This file may be redistributed under the terms of the
2760 * GNU General Public License version 2 or at your discretion
2761 * any later version.
2762 */
2763
2764#define MNT_FL (MS_MGC_VAL | MS_RDONLY)
2765
2766
2767#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
2768static int bh_count = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +00002769#endif
2770
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002771/*
2772 * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
2773 * This creates a larger static binary, and a smaller binary using
2774 * shared libraries. It's also probably slightly less CPU-efficient,
2775 * which is why it's not on by default. But, it's a good way of
2776 * testing the functions in inode_io.c and fileio.c.
2777 */
2778#undef USE_INODE_IO
2779
2780/* Kernel compatibility functions for handling the journal. These allow us
2781 * to use the recovery.c file virtually unchanged from the kernel, so we
2782 * don't have to do much to keep kernel and user recovery in sync.
2783 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002784static int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002785{
2786#ifdef USE_INODE_IO
2787 *phys = block;
2788 return 0;
2789#else
2790 struct inode *inode = journal->j_inode;
2791 errcode_t retval;
2792 blk_t pblk;
2793
2794 if (!inode) {
2795 *phys = block;
2796 return 0;
2797 }
2798
2799 retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino,
2800 &inode->i_ext2, NULL, 0, block, &pblk);
2801 *phys = pblk;
2802 return (retval);
2803#endif
2804}
2805
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002806static struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002807{
2808 struct buffer_head *bh;
2809
2810 bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer");
2811 if (!bh)
2812 return NULL;
2813
2814 jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n",
2815 (unsigned long) blocknr, blocksize, ++bh_count);
2816
2817 bh->b_ctx = kdev->k_ctx;
2818 if (kdev->k_dev == K_DEV_FS)
2819 bh->b_io = kdev->k_ctx->fs->io;
2820 else
2821 bh->b_io = kdev->k_ctx->journal_io;
2822 bh->b_size = blocksize;
2823 bh->b_blocknr = blocknr;
2824
2825 return bh;
2826}
2827
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002828static void sync_blockdev(kdev_t kdev)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002829{
2830 io_channel io;
2831
2832 if (kdev->k_dev == K_DEV_FS)
2833 io = kdev->k_ctx->fs->io;
2834 else
2835 io = kdev->k_ctx->journal_io;
2836
2837 io_channel_flush(io);
2838}
2839
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002840static void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002841{
2842 int retval;
2843 struct buffer_head *bh;
2844
2845 for (; nr > 0; --nr) {
2846 bh = *bhp++;
2847 if (rw == READ && !bh->b_uptodate) {
2848 jfs_debug(3, "reading block %lu/%p\n",
2849 (unsigned long) bh->b_blocknr, (void *) bh);
2850 retval = io_channel_read_blk(bh->b_io,
2851 bh->b_blocknr,
2852 1, bh->b_data);
2853 if (retval) {
2854 com_err(bh->b_ctx->device_name, retval,
2855 "while reading block %lu\n",
2856 (unsigned long) bh->b_blocknr);
2857 bh->b_err = retval;
2858 continue;
2859 }
2860 bh->b_uptodate = 1;
2861 } else if (rw == WRITE && bh->b_dirty) {
2862 jfs_debug(3, "writing block %lu/%p\n",
2863 (unsigned long) bh->b_blocknr, (void *) bh);
2864 retval = io_channel_write_blk(bh->b_io,
2865 bh->b_blocknr,
2866 1, bh->b_data);
2867 if (retval) {
2868 com_err(bh->b_ctx->device_name, retval,
2869 "while writing block %lu\n",
2870 (unsigned long) bh->b_blocknr);
2871 bh->b_err = retval;
2872 continue;
2873 }
2874 bh->b_dirty = 0;
2875 bh->b_uptodate = 1;
2876 } else {
2877 jfs_debug(3, "no-op %s for block %lu\n",
2878 rw == READ ? "read" : "write",
2879 (unsigned long) bh->b_blocknr);
2880 }
2881 }
2882}
2883
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002884static inline void mark_buffer_dirty(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002885{
2886 bh->b_dirty = 1;
2887}
2888
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002889static inline void mark_buffer_clean(struct buffer_head * bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002890{
2891 bh->b_dirty = 0;
2892}
2893
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002894static void brelse(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002895{
2896 if (bh->b_dirty)
2897 ll_rw_block(WRITE, 1, &bh);
2898 jfs_debug(3, "freeing block %lu/%p (total %d)\n",
2899 (unsigned long) bh->b_blocknr, (void *) bh, --bh_count);
2900 ext2fs_free_mem(&bh);
2901}
2902
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002903static inline int buffer_uptodate(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002904{
2905 return bh->b_uptodate;
2906}
2907
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002908static inline void mark_buffer_uptodate(struct buffer_head *bh, int val)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002909{
2910 bh->b_uptodate = val;
2911}
2912
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002913static void wait_on_buffer(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002914{
2915 if (!bh->b_uptodate)
2916 ll_rw_block(READ, 1, &bh);
2917}
2918
2919
2920static void e2fsck_clear_recover(e2fsck_t ctx, int error)
2921{
2922 ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
2923
2924 /* if we had an error doing journal recovery, we need a full fsck */
2925 if (error)
2926 ctx->fs->super->s_state &= ~EXT2_VALID_FS;
2927 ext2fs_mark_super_dirty(ctx->fs);
2928}
2929
2930static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
2931{
2932 struct ext2_super_block *sb = ctx->fs->super;
2933 struct ext2_super_block jsuper;
2934 struct problem_context pctx;
2935 struct buffer_head *bh;
2936 struct inode *j_inode = NULL;
2937 struct kdev_s *dev_fs = NULL, *dev_journal;
2938 const char *journal_name = 0;
2939 journal_t *journal = NULL;
2940 errcode_t retval = 0;
2941 io_manager io_ptr = 0;
2942 unsigned long start = 0;
2943 blk_t blk;
2944 int ext_journal = 0;
2945 int tried_backup_jnl = 0;
2946 int i;
2947
2948 clear_problem_context(&pctx);
2949
2950 journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
2951 if (!journal) {
2952 return EXT2_ET_NO_MEMORY;
2953 }
2954
2955 dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
2956 if (!dev_fs) {
2957 retval = EXT2_ET_NO_MEMORY;
2958 goto errout;
2959 }
2960 dev_journal = dev_fs+1;
2961
2962 dev_fs->k_ctx = dev_journal->k_ctx = ctx;
2963 dev_fs->k_dev = K_DEV_FS;
2964 dev_journal->k_dev = K_DEV_JOURNAL;
2965
2966 journal->j_dev = dev_journal;
2967 journal->j_fs_dev = dev_fs;
2968 journal->j_inode = NULL;
2969 journal->j_blocksize = ctx->fs->blocksize;
2970
2971 if (uuid_is_null(sb->s_journal_uuid)) {
2972 if (!sb->s_journal_inum)
2973 return EXT2_ET_BAD_INODE_NUM;
2974 j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
2975 "journal inode");
2976 if (!j_inode) {
2977 retval = EXT2_ET_NO_MEMORY;
2978 goto errout;
2979 }
2980
2981 j_inode->i_ctx = ctx;
2982 j_inode->i_ino = sb->s_journal_inum;
2983
2984 if ((retval = ext2fs_read_inode(ctx->fs,
2985 sb->s_journal_inum,
2986 &j_inode->i_ext2))) {
2987 try_backup_journal:
2988 if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
2989 tried_backup_jnl)
2990 goto errout;
2991 memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
2992 memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
2993 EXT2_N_BLOCKS*4);
2994 j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
2995 j_inode->i_ext2.i_links_count = 1;
2996 j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
2997 tried_backup_jnl++;
2998 }
2999 if (!j_inode->i_ext2.i_links_count ||
3000 !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
3001 retval = EXT2_ET_NO_JOURNAL;
3002 goto try_backup_journal;
3003 }
3004 if (j_inode->i_ext2.i_size / journal->j_blocksize <
3005 JFS_MIN_JOURNAL_BLOCKS) {
3006 retval = EXT2_ET_JOURNAL_TOO_SMALL;
3007 goto try_backup_journal;
3008 }
3009 for (i=0; i < EXT2_N_BLOCKS; i++) {
3010 blk = j_inode->i_ext2.i_block[i];
3011 if (!blk) {
3012 if (i < EXT2_NDIR_BLOCKS) {
3013 retval = EXT2_ET_JOURNAL_TOO_SMALL;
3014 goto try_backup_journal;
3015 }
3016 continue;
3017 }
3018 if (blk < sb->s_first_data_block ||
3019 blk >= sb->s_blocks_count) {
3020 retval = EXT2_ET_BAD_BLOCK_NUM;
3021 goto try_backup_journal;
3022 }
3023 }
3024 journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;
3025
3026#ifdef USE_INODE_IO
3027 retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
3028 &j_inode->i_ext2,
3029 &journal_name);
3030 if (retval)
3031 goto errout;
3032
3033 io_ptr = inode_io_manager;
3034#else
3035 journal->j_inode = j_inode;
3036 ctx->journal_io = ctx->fs->io;
3037 if ((retval = journal_bmap(journal, 0, &start)) != 0)
3038 goto errout;
3039#endif
3040 } else {
3041 ext_journal = 1;
3042 if (!ctx->journal_name) {
3043 char uuid[37];
3044
3045 uuid_unparse(sb->s_journal_uuid, uuid);
3046 ctx->journal_name = blkid_get_devname(ctx->blkid,
3047 "UUID", uuid);
3048 if (!ctx->journal_name)
3049 ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
3050 }
3051 journal_name = ctx->journal_name;
3052
3053 if (!journal_name) {
3054 fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
3055 return EXT2_ET_LOAD_EXT_JOURNAL;
3056 }
3057
3058 jfs_debug(1, "Using journal file %s\n", journal_name);
3059 io_ptr = unix_io_manager;
3060 }
3061
3062#if 0
3063 test_io_backing_manager = io_ptr;
3064 io_ptr = test_io_manager;
3065#endif
3066#ifndef USE_INODE_IO
3067 if (ext_journal)
3068#endif
3069 retval = io_ptr->open(journal_name, IO_FLAG_RW,
3070 &ctx->journal_io);
3071 if (retval)
3072 goto errout;
3073
3074 io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
3075
3076 if (ext_journal) {
3077 if (ctx->fs->blocksize == 1024)
3078 start = 1;
3079 bh = getblk(dev_journal, start, ctx->fs->blocksize);
3080 if (!bh) {
3081 retval = EXT2_ET_NO_MEMORY;
3082 goto errout;
3083 }
3084 ll_rw_block(READ, 1, &bh);
3085 if ((retval = bh->b_err) != 0)
3086 goto errout;
3087 memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
3088 sizeof(jsuper));
3089 brelse(bh);
3090#ifdef EXT2FS_ENABLE_SWAPFS
3091 if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
3092 ext2fs_swap_super(&jsuper);
3093#endif
3094 if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
3095 !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
3096 fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
3097 retval = EXT2_ET_LOAD_EXT_JOURNAL;
3098 goto errout;
3099 }
3100 /* Make sure the journal UUID is correct */
3101 if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
3102 sizeof(jsuper.s_uuid))) {
3103 fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
3104 retval = EXT2_ET_LOAD_EXT_JOURNAL;
3105 goto errout;
3106 }
3107
3108 journal->j_maxlen = jsuper.s_blocks_count;
3109 start++;
3110 }
3111
3112 if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
3113 retval = EXT2_ET_NO_MEMORY;
3114 goto errout;
3115 }
3116
3117 journal->j_sb_buffer = bh;
3118 journal->j_superblock = (journal_superblock_t *)bh->b_data;
3119
3120#ifdef USE_INODE_IO
3121 if (j_inode)
3122 ext2fs_free_mem(&j_inode);
3123#endif
3124
3125 *ret_journal = journal;
3126 return 0;
3127
3128errout:
3129 if (dev_fs)
3130 ext2fs_free_mem(&dev_fs);
3131 if (j_inode)
3132 ext2fs_free_mem(&j_inode);
3133 if (journal)
3134 ext2fs_free_mem(&journal);
3135 return retval;
3136
3137}
3138
3139static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
3140 struct problem_context *pctx)
3141{
3142 struct ext2_super_block *sb = ctx->fs->super;
3143 int recover = ctx->fs->super->s_feature_incompat &
3144 EXT3_FEATURE_INCOMPAT_RECOVER;
3145 int has_journal = ctx->fs->super->s_feature_compat &
3146 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3147
3148 if (has_journal || sb->s_journal_inum) {
3149 /* The journal inode is bogus, remove and force full fsck */
3150 pctx->ino = sb->s_journal_inum;
3151 if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
3152 if (has_journal && sb->s_journal_inum)
3153 printf("*** ext3 journal has been deleted - "
3154 "filesystem is now ext2 only ***\n\n");
3155 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3156 sb->s_journal_inum = 0;
3157 ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */
3158 e2fsck_clear_recover(ctx, 1);
3159 return 0;
3160 }
3161 return EXT2_ET_BAD_INODE_NUM;
3162 } else if (recover) {
3163 if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
3164 e2fsck_clear_recover(ctx, 1);
3165 return 0;
3166 }
3167 return EXT2_ET_UNSUPP_FEATURE;
3168 }
3169 return 0;
3170}
3171
3172#define V1_SB_SIZE 0x0024
3173static void clear_v2_journal_fields(journal_t *journal)
3174{
3175 e2fsck_t ctx = journal->j_dev->k_ctx;
3176 struct problem_context pctx;
3177
3178 clear_problem_context(&pctx);
3179
3180 if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
3181 return;
3182
3183 memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
3184 ctx->fs->blocksize-V1_SB_SIZE);
3185 mark_buffer_dirty(journal->j_sb_buffer);
3186}
3187
3188
3189static errcode_t e2fsck_journal_load(journal_t *journal)
3190{
3191 e2fsck_t ctx = journal->j_dev->k_ctx;
3192 journal_superblock_t *jsb;
3193 struct buffer_head *jbh = journal->j_sb_buffer;
3194 struct problem_context pctx;
3195
3196 clear_problem_context(&pctx);
3197
3198 ll_rw_block(READ, 1, &jbh);
3199 if (jbh->b_err) {
3200 com_err(ctx->device_name, jbh->b_err,
3201 _("reading journal superblock\n"));
3202 return jbh->b_err;
3203 }
3204
3205 jsb = journal->j_superblock;
3206 /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
3207 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
3208 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
3209
3210 switch (ntohl(jsb->s_header.h_blocktype)) {
3211 case JFS_SUPERBLOCK_V1:
3212 journal->j_format_version = 1;
3213 if (jsb->s_feature_compat ||
3214 jsb->s_feature_incompat ||
3215 jsb->s_feature_ro_compat ||
3216 jsb->s_nr_users)
3217 clear_v2_journal_fields(journal);
3218 break;
3219
3220 case JFS_SUPERBLOCK_V2:
3221 journal->j_format_version = 2;
3222 if (ntohl(jsb->s_nr_users) > 1 &&
3223 uuid_is_null(ctx->fs->super->s_journal_uuid))
3224 clear_v2_journal_fields(journal);
3225 if (ntohl(jsb->s_nr_users) > 1) {
3226 fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
3227 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
3228 }
3229 break;
3230
3231 /*
3232 * These should never appear in a journal super block, so if
3233 * they do, the journal is badly corrupted.
3234 */
3235 case JFS_DESCRIPTOR_BLOCK:
3236 case JFS_COMMIT_BLOCK:
3237 case JFS_REVOKE_BLOCK:
3238 return EXT2_ET_CORRUPT_SUPERBLOCK;
3239
3240 /* If we don't understand the superblock major type, but there
3241 * is a magic number, then it is likely to be a new format we
3242 * just don't understand, so leave it alone. */
3243 default:
3244 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
3245 }
3246
3247 if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
3248 return EXT2_ET_UNSUPP_FEATURE;
3249
3250 if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
3251 return EXT2_ET_RO_UNSUPP_FEATURE;
3252
3253 /* We have now checked whether we know enough about the journal
3254 * format to be able to proceed safely, so any other checks that
3255 * fail we should attempt to recover from. */
3256 if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
3257 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
3258 _("%s: no valid journal superblock found\n"),
3259 ctx->device_name);
3260 return EXT2_ET_CORRUPT_SUPERBLOCK;
3261 }
3262
3263 if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
3264 journal->j_maxlen = ntohl(jsb->s_maxlen);
3265 else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
3266 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
3267 _("%s: journal too short\n"),
3268 ctx->device_name);
3269 return EXT2_ET_CORRUPT_SUPERBLOCK;
3270 }
3271
3272 journal->j_tail_sequence = ntohl(jsb->s_sequence);
3273 journal->j_transaction_sequence = journal->j_tail_sequence;
3274 journal->j_tail = ntohl(jsb->s_start);
3275 journal->j_first = ntohl(jsb->s_first);
3276 journal->j_last = ntohl(jsb->s_maxlen);
3277
3278 return 0;
3279}
3280
3281static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
3282 journal_t *journal)
3283{
3284 char *p;
3285 union {
3286 uuid_t uuid;
3287 __u32 val[4];
3288 } u;
3289 __u32 new_seq = 0;
3290 int i;
3291
3292 /* Leave a valid existing V1 superblock signature alone.
3293 * Anything unrecognisable we overwrite with a new V2
3294 * signature. */
3295
3296 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
3297 jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
3298 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
3299 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
3300 }
3301
3302 /* Zero out everything else beyond the superblock header */
3303
3304 p = ((char *) jsb) + sizeof(journal_header_t);
3305 memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
3306
3307 jsb->s_blocksize = htonl(ctx->fs->blocksize);
3308 jsb->s_maxlen = htonl(journal->j_maxlen);
3309 jsb->s_first = htonl(1);
3310
3311 /* Initialize the journal sequence number so that there is "no"
3312 * chance we will find old "valid" transactions in the journal.
3313 * This avoids the need to zero the whole journal (slow to do,
3314 * and risky when we are just recovering the filesystem).
3315 */
3316 uuid_generate(u.uuid);
3317 for (i = 0; i < 4; i ++)
3318 new_seq ^= u.val[i];
3319 jsb->s_sequence = htonl(new_seq);
3320
3321 mark_buffer_dirty(journal->j_sb_buffer);
3322 ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
3323}
3324
3325static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
3326 journal_t *journal,
3327 struct problem_context *pctx)
3328{
3329 struct ext2_super_block *sb = ctx->fs->super;
3330 int recover = ctx->fs->super->s_feature_incompat &
3331 EXT3_FEATURE_INCOMPAT_RECOVER;
3332
3333 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
3334 if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
3335 e2fsck_journal_reset_super(ctx, journal->j_superblock,
3336 journal);
3337 journal->j_transaction_sequence = 1;
3338 e2fsck_clear_recover(ctx, recover);
3339 return 0;
3340 }
3341 return EXT2_ET_CORRUPT_SUPERBLOCK;
3342 } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
3343 return EXT2_ET_CORRUPT_SUPERBLOCK;
3344
3345 return 0;
3346}
3347
3348static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
3349 int reset, int drop)
3350{
3351 journal_superblock_t *jsb;
3352
3353 if (drop)
3354 mark_buffer_clean(journal->j_sb_buffer);
3355 else if (!(ctx->options & E2F_OPT_READONLY)) {
3356 jsb = journal->j_superblock;
3357 jsb->s_sequence = htonl(journal->j_transaction_sequence);
3358 if (reset)
3359 jsb->s_start = 0; /* this marks the journal as empty */
3360 mark_buffer_dirty(journal->j_sb_buffer);
3361 }
3362 brelse(journal->j_sb_buffer);
3363
3364 if (ctx->journal_io) {
3365 if (ctx->fs && ctx->fs->io != ctx->journal_io)
3366 io_channel_close(ctx->journal_io);
3367 ctx->journal_io = 0;
3368 }
3369
3370#ifndef USE_INODE_IO
3371 if (journal->j_inode)
3372 ext2fs_free_mem(&journal->j_inode);
3373#endif
3374 if (journal->j_fs_dev)
3375 ext2fs_free_mem(&journal->j_fs_dev);
3376 ext2fs_free_mem(&journal);
3377}
3378
3379/*
3380 * This function makes sure that the superblock fields regarding the
3381 * journal are consistent.
3382 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003383static int e2fsck_check_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003384{
3385 struct ext2_super_block *sb = ctx->fs->super;
3386 journal_t *journal;
3387 int recover = ctx->fs->super->s_feature_incompat &
3388 EXT3_FEATURE_INCOMPAT_RECOVER;
3389 struct problem_context pctx;
3390 problem_t problem;
3391 int reset = 0, force_fsck = 0;
3392 int retval;
3393
3394 /* If we don't have any journal features, don't do anything more */
3395 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
3396 !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
3397 uuid_is_null(sb->s_journal_uuid))
3398 return 0;
3399
3400 clear_problem_context(&pctx);
3401 pctx.num = sb->s_journal_inum;
3402
3403 retval = e2fsck_get_journal(ctx, &journal);
3404 if (retval) {
3405 if ((retval == EXT2_ET_BAD_INODE_NUM) ||
3406 (retval == EXT2_ET_BAD_BLOCK_NUM) ||
3407 (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
3408 (retval == EXT2_ET_NO_JOURNAL))
3409 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
3410 return retval;
3411 }
3412
3413 retval = e2fsck_journal_load(journal);
3414 if (retval) {
3415 if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
3416 ((retval == EXT2_ET_UNSUPP_FEATURE) &&
3417 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
3418 &pctx))) ||
3419 ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
3420 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
3421 &pctx))) ||
3422 ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
3423 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
3424 retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
3425 &pctx);
3426 e2fsck_journal_release(ctx, journal, 0, 1);
3427 return retval;
3428 }
3429
3430 /*
3431 * We want to make the flags consistent here. We will not leave with
3432 * needs_recovery set but has_journal clear. We can't get in a loop
3433 * with -y, -n, or -p, only if a user isn't making up their mind.
3434 */
3435no_has_journal:
3436 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
3437 recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
3438 pctx.str = "inode";
3439 if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
3440 if (recover &&
3441 !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
3442 goto no_has_journal;
3443 /*
3444 * Need a full fsck if we are releasing a
3445 * journal stored on a reserved inode.
3446 */
3447 force_fsck = recover ||
3448 (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
3449 /* Clear all of the journal fields */
3450 sb->s_journal_inum = 0;
3451 sb->s_journal_dev = 0;
3452 memset(sb->s_journal_uuid, 0,
3453 sizeof(sb->s_journal_uuid));
3454 e2fsck_clear_recover(ctx, force_fsck);
3455 } else if (!(ctx->options & E2F_OPT_READONLY)) {
3456 sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3457 ext2fs_mark_super_dirty(ctx->fs);
3458 }
3459 }
3460
3461 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
3462 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
3463 journal->j_superblock->s_start != 0) {
3464 /* Print status information */
3465 fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
3466 if (ctx->superblock)
3467 problem = PR_0_JOURNAL_RUN_DEFAULT;
3468 else
3469 problem = PR_0_JOURNAL_RUN;
3470 if (fix_problem(ctx, problem, &pctx)) {
3471 ctx->options |= E2F_OPT_FORCE;
3472 sb->s_feature_incompat |=
3473 EXT3_FEATURE_INCOMPAT_RECOVER;
3474 ext2fs_mark_super_dirty(ctx->fs);
3475 } else if (fix_problem(ctx,
3476 PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
3477 reset = 1;
3478 sb->s_state &= ~EXT2_VALID_FS;
3479 ext2fs_mark_super_dirty(ctx->fs);
3480 }
3481 /*
3482 * If the user answers no to the above question, we
3483 * ignore the fact that journal apparently has data;
3484 * accidentally replaying over valid data would be far
3485 * worse than skipping a questionable recovery.
3486 *
3487 * XXX should we abort with a fatal error here? What
3488 * will the ext3 kernel code do if a filesystem with
3489 * !NEEDS_RECOVERY but with a non-zero
3490 * journal->j_superblock->s_start is mounted?
3491 */
3492 }
3493
3494 e2fsck_journal_release(ctx, journal, reset, 0);
3495 return retval;
3496}
3497
3498static errcode_t recover_ext3_journal(e2fsck_t ctx)
3499{
3500 journal_t *journal;
3501 int retval;
3502
3503 journal_init_revoke_caches();
3504 retval = e2fsck_get_journal(ctx, &journal);
3505 if (retval)
3506 return retval;
3507
3508 retval = e2fsck_journal_load(journal);
3509 if (retval)
3510 goto errout;
3511
3512 retval = journal_init_revoke(journal, 1024);
3513 if (retval)
3514 goto errout;
3515
3516 retval = -journal_recover(journal);
3517 if (retval)
3518 goto errout;
3519
3520 if (journal->j_superblock->s_errno) {
3521 ctx->fs->super->s_state |= EXT2_ERROR_FS;
3522 ext2fs_mark_super_dirty(ctx->fs);
3523 journal->j_superblock->s_errno = 0;
3524 mark_buffer_dirty(journal->j_sb_buffer);
3525 }
3526
3527errout:
3528 journal_destroy_revoke(journal);
3529 journal_destroy_revoke_caches();
3530 e2fsck_journal_release(ctx, journal, 1, 0);
3531 return retval;
3532}
3533
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003534static int e2fsck_run_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003535{
3536 io_manager io_ptr = ctx->fs->io->manager;
3537 int blocksize = ctx->fs->blocksize;
3538 errcode_t retval, recover_retval;
3539
3540 printf(_("%s: recovering journal\n"), ctx->device_name);
3541 if (ctx->options & E2F_OPT_READONLY) {
3542 printf(_("%s: won't do journal recovery while read-only\n"),
3543 ctx->device_name);
3544 return EXT2_ET_FILE_RO;
3545 }
3546
3547 if (ctx->fs->flags & EXT2_FLAG_DIRTY)
3548 ext2fs_flush(ctx->fs); /* Force out any modifications */
3549
3550 recover_retval = recover_ext3_journal(ctx);
3551
3552 /*
3553 * Reload the filesystem context to get up-to-date data from disk
3554 * because journal recovery will change the filesystem under us.
3555 */
3556 ext2fs_close(ctx->fs);
3557 retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
3558 ctx->superblock, blocksize, io_ptr,
3559 &ctx->fs);
3560
3561 if (retval) {
3562 com_err(ctx->program_name, retval,
3563 _("while trying to re-open %s"),
3564 ctx->device_name);
3565 fatal_error(ctx, 0);
3566 }
3567 ctx->fs->priv_data = ctx;
3568
3569 /* Set the superblock flags */
3570 e2fsck_clear_recover(ctx, recover_retval);
3571 return recover_retval;
3572}
3573
3574/*
3575 * This function will move the journal inode from a visible file in
3576 * the filesystem directory hierarchy to the reserved inode if necessary.
3577 */
3578static const char * const journal_names[] = {
3579 ".journal", "journal", ".journal.dat", "journal.dat", 0 };
3580
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003581static void e2fsck_move_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003582{
3583 struct ext2_super_block *sb = ctx->fs->super;
3584 struct problem_context pctx;
3585 struct ext2_inode inode;
3586 ext2_filsys fs = ctx->fs;
3587 ext2_ino_t ino;
3588 errcode_t retval;
3589 const char * const * cpp;
3590 int group, mount_flags;
3591
3592 clear_problem_context(&pctx);
3593
3594 /*
3595 * If the filesystem is opened read-only, or there is no
3596 * journal, then do nothing.
3597 */
3598 if ((ctx->options & E2F_OPT_READONLY) ||
3599 (sb->s_journal_inum == 0) ||
3600 !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
3601 return;
3602
3603 /*
3604 * Read in the journal inode
3605 */
3606 if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
3607 return;
3608
3609 /*
3610 * If it's necessary to backup the journal inode, do so.
3611 */
3612 if ((sb->s_jnl_backup_type == 0) ||
3613 ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
3614 memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
3615 if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
3616 memcpy(sb->s_jnl_blocks, inode.i_block,
3617 EXT2_N_BLOCKS*4);
3618 sb->s_jnl_blocks[16] = inode.i_size;
3619 sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
3620 ext2fs_mark_super_dirty(fs);
3621 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3622 }
3623 }
3624
3625 /*
3626 * If the journal is already the hidden inode, then do nothing
3627 */
3628 if (sb->s_journal_inum == EXT2_JOURNAL_INO)
3629 return;
3630
3631 /*
3632 * The journal inode had better have only one link and not be readable.
3633 */
3634 if (inode.i_links_count != 1)
3635 return;
3636
3637 /*
3638 * If the filesystem is mounted, or we can't tell whether
3639 * or not it's mounted, do nothing.
3640 */
3641 retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
3642 if (retval || (mount_flags & EXT2_MF_MOUNTED))
3643 return;
3644
3645 /*
3646 * If we can't find the name of the journal inode, then do
3647 * nothing.
3648 */
3649 for (cpp = journal_names; *cpp; cpp++) {
3650 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
3651 strlen(*cpp), 0, &ino);
3652 if ((retval == 0) && (ino == sb->s_journal_inum))
3653 break;
3654 }
3655 if (*cpp == 0)
3656 return;
3657
3658 /* We need the inode bitmap to be loaded */
3659 retval = ext2fs_read_bitmaps(fs);
3660 if (retval)
3661 return;
3662
3663 pctx.str = *cpp;
3664 if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
3665 return;
3666
3667 /*
3668 * OK, we've done all the checks, let's actually move the
3669 * journal inode. Errors at this point mean we need to force
3670 * an ext2 filesystem check.
3671 */
3672 if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
3673 goto err_out;
3674 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
3675 goto err_out;
3676 sb->s_journal_inum = EXT2_JOURNAL_INO;
3677 ext2fs_mark_super_dirty(fs);
3678 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3679 inode.i_links_count = 0;
3680 inode.i_dtime = time(0);
3681 if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
3682 goto err_out;
3683
3684 group = ext2fs_group_of_ino(fs, ino);
3685 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
3686 ext2fs_mark_ib_dirty(fs);
3687 fs->group_desc[group].bg_free_inodes_count++;
3688 fs->super->s_free_inodes_count++;
3689 return;
3690
3691err_out:
3692 pctx.errcode = retval;
3693 fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
3694 fs->super->s_state &= ~EXT2_VALID_FS;
3695 ext2fs_mark_super_dirty(fs);
3696 return;
3697}
3698
3699/*
3700 * message.c --- print e2fsck messages (with compression)
3701 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003702 * print_e2fsck_message() prints a message to the user, using
3703 * compression techniques and expansions of abbreviations.
3704 *
3705 * The following % expansions are supported:
3706 *
3707 * %b <blk> block number
3708 * %B <blkcount> integer
3709 * %c <blk2> block number
3710 * %Di <dirent>->ino inode number
3711 * %Dn <dirent>->name string
3712 * %Dr <dirent>->rec_len
3713 * %Dl <dirent>->name_len
3714 * %Dt <dirent>->filetype
3715 * %d <dir> inode number
3716 * %g <group> integer
3717 * %i <ino> inode number
3718 * %Is <inode> -> i_size
3719 * %IS <inode> -> i_extra_isize
3720 * %Ib <inode> -> i_blocks
3721 * %Il <inode> -> i_links_count
3722 * %Im <inode> -> i_mode
3723 * %IM <inode> -> i_mtime
3724 * %IF <inode> -> i_faddr
3725 * %If <inode> -> i_file_acl
3726 * %Id <inode> -> i_dir_acl
3727 * %Iu <inode> -> i_uid
3728 * %Ig <inode> -> i_gid
3729 * %j <ino2> inode number
3730 * %m <com_err error message>
3731 * %N <num>
3732 * %p ext2fs_get_pathname of directory <ino>
3733 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
3734 * the containing directory. (If dirent is NULL
3735 * then return the pathname of directory <ino2>)
3736 * %q ext2fs_get_pathname of directory <dir>
3737 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
3738 * the containing directory.
3739 * %s <str> miscellaneous string
3740 * %S backup superblock
3741 * %X <num> hexadecimal format
3742 *
3743 * The following '@' expansions are supported:
3744 *
3745 * @a extended attribute
3746 * @A error allocating
3747 * @b block
3748 * @B bitmap
3749 * @c compress
3750 * @C conflicts with some other fs block
3751 * @D deleted
3752 * @d directory
3753 * @e entry
3754 * @E Entry '%Dn' in %p (%i)
3755 * @f filesystem
3756 * @F for @i %i (%Q) is
3757 * @g group
3758 * @h HTREE directory inode
3759 * @i inode
3760 * @I illegal
3761 * @j journal
3762 * @l lost+found
3763 * @L is a link
3764 * @o orphaned
3765 * @p problem in
3766 * @r root inode
3767 * @s should be
3768 * @S superblock
3769 * @u unattached
3770 * @v device
3771 * @z zero-length
3772 */
3773
3774
3775/*
3776 * This structure defines the abbreviations used by the text strings
3777 * below. The first character in the string is the index letter. An
3778 * abbreviation of the form '@<i>' is expanded by looking up the index
3779 * letter <i> in the table below.
3780 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003781static const char * const abbrevs[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003782 N_("aextended attribute"),
3783 N_("Aerror allocating"),
3784 N_("bblock"),
3785 N_("Bbitmap"),
3786 N_("ccompress"),
3787 N_("Cconflicts with some other fs @b"),
3788 N_("iinode"),
3789 N_("Iillegal"),
3790 N_("jjournal"),
3791 N_("Ddeleted"),
3792 N_("ddirectory"),
3793 N_("eentry"),
3794 N_("E@e '%Dn' in %p (%i)"),
3795 N_("ffilesystem"),
3796 N_("Ffor @i %i (%Q) is"),
3797 N_("ggroup"),
3798 N_("hHTREE @d @i"),
3799 N_("llost+found"),
3800 N_("Lis a link"),
3801 N_("oorphaned"),
3802 N_("pproblem in"),
3803 N_("rroot @i"),
3804 N_("sshould be"),
3805 N_("Ssuper@b"),
3806 N_("uunattached"),
3807 N_("vdevice"),
3808 N_("zzero-length"),
3809 "@@",
3810 0
3811 };
3812
3813/*
3814 * Give more user friendly names to the "special" inodes.
3815 */
3816#define num_special_inodes 11
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003817static const char * const special_inode_name[] =
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003818{
3819 N_("<The NULL inode>"), /* 0 */
3820 N_("<The bad blocks inode>"), /* 1 */
3821 "/", /* 2 */
3822 N_("<The ACL index inode>"), /* 3 */
3823 N_("<The ACL data inode>"), /* 4 */
3824 N_("<The boot loader inode>"), /* 5 */
3825 N_("<The undelete directory inode>"), /* 6 */
3826 N_("<The group descriptor inode>"), /* 7 */
3827 N_("<The journal inode>"), /* 8 */
3828 N_("<Reserved inode 9>"), /* 9 */
3829 N_("<Reserved inode 10>"), /* 10 */
3830};
3831
3832/*
3833 * This function does "safe" printing. It will convert non-printable
3834 * ASCII characters using '^' and M- notation.
3835 */
3836static void safe_print(const char *cp, int len)
3837{
3838 unsigned char ch;
3839
3840 if (len < 0)
3841 len = strlen(cp);
3842
3843 while (len--) {
3844 ch = *cp++;
3845 if (ch > 128) {
3846 fputs("M-", stdout);
3847 ch -= 128;
3848 }
3849 if ((ch < 32) || (ch == 0x7f)) {
3850 fputc('^', stdout);
3851 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
3852 }
3853 fputc(ch, stdout);
3854 }
3855}
3856
3857
3858/*
3859 * This function prints a pathname, using the ext2fs_get_pathname
3860 * function
3861 */
3862static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
3863{
3864 errcode_t retval;
3865 char *path;
3866
3867 if (!dir && (ino < num_special_inodes)) {
3868 fputs(_(special_inode_name[ino]), stdout);
3869 return;
3870 }
3871
3872 retval = ext2fs_get_pathname(fs, dir, ino, &path);
3873 if (retval)
3874 fputs("???", stdout);
3875 else {
3876 safe_print(path, -1);
3877 ext2fs_free_mem(&path);
3878 }
3879}
3880
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003881static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
3882 struct problem_context *pctx, int first);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003883/*
3884 * This function handles the '@' expansion. We allow recursive
3885 * expansion; an @ expression can contain further '@' and '%'
3886 * expressions.
3887 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003888static void expand_at_expression(e2fsck_t ctx, char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003889 struct problem_context *pctx,
3890 int *first)
3891{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003892 const char * const *cpp;
3893 const char *str;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003894
3895 /* Search for the abbreviation */
3896 for (cpp = abbrevs; *cpp; cpp++) {
3897 if (ch == *cpp[0])
3898 break;
3899 }
3900 if (*cpp) {
3901 str = _(*cpp) + 1;
3902 if (*first && islower(*str)) {
3903 *first = 0;
3904 fputc(toupper(*str++), stdout);
3905 }
3906 print_e2fsck_message(ctx, str, pctx, *first);
3907 } else
3908 printf("@%c", ch);
3909}
3910
3911/*
3912 * This function expands '%IX' expressions
3913 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003914static void expand_inode_expression(char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003915 struct problem_context *ctx)
3916{
3917 struct ext2_inode *inode;
3918 struct ext2_inode_large *large_inode;
3919 char * time_str;
3920 time_t t;
3921 int do_gmt = -1;
3922
3923 if (!ctx || !ctx->inode)
3924 goto no_inode;
3925
3926 inode = ctx->inode;
3927 large_inode = (struct ext2_inode_large *) inode;
3928
3929 switch (ch) {
3930 case 's':
3931 if (LINUX_S_ISDIR(inode->i_mode))
3932 printf("%u", inode->i_size);
3933 else {
3934#ifdef EXT2_NO_64_TYPE
3935 if (inode->i_size_high)
3936 printf("0x%x%08x", inode->i_size_high,
3937 inode->i_size);
3938 else
3939 printf("%u", inode->i_size);
3940#else
3941 printf("%llu", (inode->i_size |
3942 ((__u64) inode->i_size_high << 32)));
3943#endif
3944 }
3945 break;
3946 case 'S':
3947 printf("%u", large_inode->i_extra_isize);
3948 break;
3949 case 'b':
3950 printf("%u", inode->i_blocks);
3951 break;
3952 case 'l':
3953 printf("%d", inode->i_links_count);
3954 break;
3955 case 'm':
3956 printf("0%o", inode->i_mode);
3957 break;
3958 case 'M':
3959 /* The diet libc doesn't respect the TZ environemnt variable */
3960 if (do_gmt == -1) {
3961 time_str = getenv("TZ");
3962 if (!time_str)
3963 time_str = "";
3964 do_gmt = !strcmp(time_str, "GMT");
3965 }
3966 t = inode->i_mtime;
3967 time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
3968 printf("%.24s", time_str);
3969 break;
3970 case 'F':
3971 printf("%u", inode->i_faddr);
3972 break;
3973 case 'f':
3974 printf("%u", inode->i_file_acl);
3975 break;
3976 case 'd':
3977 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
3978 inode->i_dir_acl : 0));
3979 break;
3980 case 'u':
3981 printf("%d", (inode->i_uid |
3982 (inode->osd2.linux2.l_i_uid_high << 16)));
3983 break;
3984 case 'g':
3985 printf("%d", (inode->i_gid |
3986 (inode->osd2.linux2.l_i_gid_high << 16)));
3987 break;
3988 default:
3989 no_inode:
3990 printf("%%I%c", ch);
3991 break;
3992 }
3993}
3994
3995/*
3996 * This function expands '%dX' expressions
3997 */
3998static _INLINE_ void expand_dirent_expression(char ch,
3999 struct problem_context *ctx)
4000{
4001 struct ext2_dir_entry *dirent;
4002 int len;
4003
4004 if (!ctx || !ctx->dirent)
4005 goto no_dirent;
4006
4007 dirent = ctx->dirent;
4008
4009 switch (ch) {
4010 case 'i':
4011 printf("%u", dirent->inode);
4012 break;
4013 case 'n':
4014 len = dirent->name_len & 0xFF;
4015 if (len > EXT2_NAME_LEN)
4016 len = EXT2_NAME_LEN;
4017 if (len > dirent->rec_len)
4018 len = dirent->rec_len;
4019 safe_print(dirent->name, len);
4020 break;
4021 case 'r':
4022 printf("%u", dirent->rec_len);
4023 break;
4024 case 'l':
4025 printf("%u", dirent->name_len & 0xFF);
4026 break;
4027 case 't':
4028 printf("%u", dirent->name_len >> 8);
4029 break;
4030 default:
4031 no_dirent:
4032 printf("%%D%c", ch);
4033 break;
4034 }
4035}
4036
4037static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
4038 struct problem_context *ctx)
4039{
4040 if (!ctx)
4041 goto no_context;
4042
4043 switch (ch) {
4044 case '%':
4045 fputc('%', stdout);
4046 break;
4047 case 'b':
4048 printf("%u", ctx->blk);
4049 break;
4050 case 'B':
4051#ifdef EXT2_NO_64_TYPE
4052 printf("%d", ctx->blkcount);
4053#else
4054 printf("%lld", ctx->blkcount);
4055#endif
4056 break;
4057 case 'c':
4058 printf("%u", ctx->blk2);
4059 break;
4060 case 'd':
4061 printf("%u", ctx->dir);
4062 break;
4063 case 'g':
4064 printf("%d", ctx->group);
4065 break;
4066 case 'i':
4067 printf("%u", ctx->ino);
4068 break;
4069 case 'j':
4070 printf("%u", ctx->ino2);
4071 break;
4072 case 'm':
4073 printf("%s", error_message(ctx->errcode));
4074 break;
4075 case 'N':
4076#ifdef EXT2_NO_64_TYPE
4077 printf("%u", ctx->num);
4078#else
4079 printf("%llu", ctx->num);
4080#endif
4081 break;
4082 case 'p':
4083 print_pathname(fs, ctx->ino, 0);
4084 break;
4085 case 'P':
4086 print_pathname(fs, ctx->ino2,
4087 ctx->dirent ? ctx->dirent->inode : 0);
4088 break;
4089 case 'q':
4090 print_pathname(fs, ctx->dir, 0);
4091 break;
4092 case 'Q':
4093 print_pathname(fs, ctx->dir, ctx->ino);
4094 break;
4095 case 'S':
4096 printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
4097 break;
4098 case 's':
4099 printf("%s", ctx->str ? ctx->str : "NULL");
4100 break;
4101 case 'X':
4102#ifdef EXT2_NO_64_TYPE
4103 printf("0x%x", ctx->num);
4104#else
4105 printf("0x%llx", ctx->num);
4106#endif
4107 break;
4108 default:
4109 no_context:
4110 printf("%%%c", ch);
4111 break;
4112 }
4113}
4114
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004115
4116static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004117 struct problem_context *pctx, int first)
4118{
4119 ext2_filsys fs = ctx->fs;
4120 const char * cp;
4121 int i;
4122
4123 e2fsck_clear_progbar(ctx);
4124 for (cp = msg; *cp; cp++) {
4125 if (cp[0] == '@') {
4126 cp++;
4127 expand_at_expression(ctx, *cp, pctx, &first);
4128 } else if (cp[0] == '%' && cp[1] == 'I') {
4129 cp += 2;
4130 expand_inode_expression(*cp, pctx);
4131 } else if (cp[0] == '%' && cp[1] == 'D') {
4132 cp += 2;
4133 expand_dirent_expression(*cp, pctx);
4134 } else if ((cp[0] == '%')) {
4135 cp++;
4136 expand_percent_expression(fs, *cp, pctx);
4137 } else {
4138 for (i=0; cp[i]; i++)
4139 if ((cp[i] == '@') || cp[i] == '%')
4140 break;
4141 printf("%.*s", i, cp);
4142 cp += i-1;
4143 }
4144 first = 0;
4145 }
4146}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004147
4148
4149/*
4150 * region.c --- code which manages allocations within a region.
4151 */
4152
4153struct region_el {
4154 region_addr_t start;
4155 region_addr_t end;
4156 struct region_el *next;
4157};
4158
4159struct region_struct {
4160 region_addr_t min;
4161 region_addr_t max;
4162 struct region_el *allocated;
4163};
4164
4165static region_t region_create(region_addr_t min, region_addr_t max)
4166{
4167 region_t region;
4168
4169 region = malloc(sizeof(struct region_struct));
4170 if (!region)
4171 return NULL;
4172 memset(region, 0, sizeof(struct region_struct));
4173 region->min = min;
4174 region->max = max;
4175 return region;
4176}
4177
4178static void region_free(region_t region)
4179{
4180 struct region_el *r, *next;
4181
4182 for (r = region->allocated; r; r = next) {
4183 next = r->next;
4184 free(r);
4185 }
4186 memset(region, 0, sizeof(struct region_struct));
4187 free(region);
4188}
4189
4190static int region_allocate(region_t region, region_addr_t start, int n)
4191{
4192 struct region_el *r, *new_region, *prev, *next;
4193 region_addr_t end;
4194
4195 end = start+n;
4196 if ((start < region->min) || (end > region->max))
4197 return -1;
4198 if (n == 0)
4199 return 1;
4200
4201 /*
4202 * Search through the linked list. If we find that it
4203 * conflicts witih something that's already allocated, return
4204 * 1; if we can find an existing region which we can grow, do
4205 * so. Otherwise, stop when we find the appropriate place
4206 * insert a new region element into the linked list.
4207 */
4208 for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
4209 if (((start >= r->start) && (start < r->end)) ||
4210 ((end > r->start) && (end <= r->end)) ||
4211 ((start <= r->start) && (end >= r->end)))
4212 return 1;
4213 if (end == r->start) {
4214 r->start = start;
4215 return 0;
4216 }
4217 if (start == r->end) {
4218 if ((next = r->next)) {
4219 if (end > next->start)
4220 return 1;
4221 if (end == next->start) {
4222 r->end = next->end;
4223 r->next = next->next;
4224 free(next);
4225 return 0;
4226 }
4227 }
4228 r->end = end;
4229 return 0;
4230 }
4231 if (start < r->start)
4232 break;
4233 }
4234 /*
4235 * Insert a new region element structure into the linked list
4236 */
4237 new_region = malloc(sizeof(struct region_el));
4238 if (!new_region)
4239 return -1;
4240 new_region->start = start;
4241 new_region->end = start + n;
4242 new_region->next = r;
4243 if (prev)
4244 prev->next = new_region;
4245 else
4246 region->allocated = new_region;
4247 return 0;
4248}
4249
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004250/*
4251 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
4252 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004253 * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
4254 * and applies the following tests to each inode:
4255 *
4256 * - The mode field of the inode must be legal.
4257 * - The size and block count fields of the inode are correct.
4258 * - A data block must not be used by another inode
4259 *
4260 * Pass 1 also gathers the collects the following information:
4261 *
4262 * - A bitmap of which inodes are in use. (inode_used_map)
4263 * - A bitmap of which inodes are directories. (inode_dir_map)
4264 * - A bitmap of which inodes are regular files. (inode_reg_map)
4265 * - A bitmap of which inodes have bad fields. (inode_bad_map)
4266 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
4267 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
4268 * - A bitmap of which blocks are in use. (block_found_map)
4269 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
4270 * - The data blocks of the directory inodes. (dir_map)
4271 *
4272 * Pass 1 is designed to stash away enough information so that the
4273 * other passes should not need to read in the inode information
4274 * during the normal course of a filesystem check. (Althogh if an
4275 * inconsistency is detected, other passes may need to read in an
4276 * inode to fix it.)
4277 *
4278 * Note that pass 1B will be invoked if there are any duplicate blocks
4279 * found.
4280 */
4281
4282
4283static int process_block(ext2_filsys fs, blk_t *blocknr,
4284 e2_blkcnt_t blockcnt, blk_t ref_blk,
4285 int ref_offset, void *priv_data);
4286static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
4287 e2_blkcnt_t blockcnt, blk_t ref_blk,
4288 int ref_offset, void *priv_data);
4289static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
4290 char *block_buf);
4291static void mark_table_blocks(e2fsck_t ctx);
4292static void alloc_bb_map(e2fsck_t ctx);
4293static void alloc_imagic_map(e2fsck_t ctx);
4294static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
4295static void handle_fs_bad_blocks(e2fsck_t ctx);
4296static void process_inodes(e2fsck_t ctx, char *block_buf);
4297static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
4298static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
4299 dgrp_t group, void * priv_data);
4300static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
4301 char *block_buf, int adjust_sign);
4302/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
4303
4304static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
4305 struct ext2_inode * inode, int bufsize,
4306 const char *proc);
4307
4308struct process_block_struct_1 {
4309 ext2_ino_t ino;
4310 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
4311 fragmented:1, compressed:1, bbcheck:1;
4312 blk_t num_blocks;
4313 blk_t max_blocks;
4314 e2_blkcnt_t last_block;
4315 int num_illegal_blocks;
4316 blk_t previous_block;
4317 struct ext2_inode *inode;
4318 struct problem_context *pctx;
4319 ext2fs_block_bitmap fs_meta_blocks;
4320 e2fsck_t ctx;
4321};
4322
4323struct process_inode_block {
4324 ext2_ino_t ino;
4325 struct ext2_inode inode;
4326};
4327
4328struct scan_callback_struct {
4329 e2fsck_t ctx;
4330 char *block_buf;
4331};
4332
4333/*
4334 * For the inodes to process list.
4335 */
4336static struct process_inode_block *inodes_to_process;
4337static int process_inode_count;
4338
4339static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
4340 EXT2_MIN_BLOCK_LOG_SIZE + 1];
4341
4342/*
4343 * Free all memory allocated by pass1 in preparation for restarting
4344 * things.
4345 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004346static void unwind_pass1(void)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004347{
4348 ext2fs_free_mem(&inodes_to_process);
4349 inodes_to_process = 0;
4350}
4351
4352/*
4353 * Check to make sure a device inode is real. Returns 1 if the device
4354 * checks out, 0 if not.
4355 *
4356 * Note: this routine is now also used to check FIFO's and Sockets,
4357 * since they have the same requirement; the i_block fields should be
4358 * zero.
4359 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004360static int
4361e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004362{
4363 int i;
4364
4365 /*
4366 * If i_blocks is non-zero, or the index flag is set, then
4367 * this is a bogus device/fifo/socket
4368 */
4369 if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
4370 (inode->i_flags & EXT2_INDEX_FL))
4371 return 0;
4372
4373 /*
4374 * We should be able to do the test below all the time, but
4375 * because the kernel doesn't forcibly clear the device
4376 * inode's additional i_block fields, there are some rare
4377 * occasions when a legitimate device inode will have non-zero
4378 * additional i_block fields. So for now, we only complain
4379 * when the immutable flag is set, which should never happen
4380 * for devices. (And that's when the problem is caused, since
4381 * you can't set or clear immutable flags for devices.) Once
4382 * the kernel has been fixed we can change this...
4383 */
4384 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
4385 for (i=4; i < EXT2_N_BLOCKS; i++)
4386 if (inode->i_block[i])
4387 return 0;
4388 }
4389 return 1;
4390}
4391
4392/*
4393 * Check to make sure a symlink inode is real. Returns 1 if the symlink
4394 * checks out, 0 if not.
4395 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004396static int
4397e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, char *buf)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004398{
4399 unsigned int len;
4400 int i;
4401 blk_t blocks;
4402
4403 if ((inode->i_size_high || inode->i_size == 0) ||
4404 (inode->i_flags & EXT2_INDEX_FL))
4405 return 0;
4406
4407 blocks = ext2fs_inode_data_blocks(fs, inode);
4408 if (blocks) {
4409 if ((inode->i_size >= fs->blocksize) ||
4410 (blocks != fs->blocksize >> 9) ||
4411 (inode->i_block[0] < fs->super->s_first_data_block) ||
4412 (inode->i_block[0] >= fs->super->s_blocks_count))
4413 return 0;
4414
4415 for (i = 1; i < EXT2_N_BLOCKS; i++)
4416 if (inode->i_block[i])
4417 return 0;
4418
4419 if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
4420 return 0;
4421
4422 len = strnlen(buf, fs->blocksize);
4423 if (len == fs->blocksize)
4424 return 0;
4425 } else {
4426 if (inode->i_size >= sizeof(inode->i_block))
4427 return 0;
4428
4429 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
4430 if (len == sizeof(inode->i_block))
4431 return 0;
4432 }
4433 if (len != inode->i_size)
4434 return 0;
4435 return 1;
4436}
4437
4438/*
4439 * If the immutable (or append-only) flag is set on the inode, offer
4440 * to clear it.
4441 */
4442#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
4443static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
4444{
4445 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
4446 return;
4447
4448 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
4449 return;
4450
4451 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
4452 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4453}
4454
4455/*
4456 * If device, fifo or socket, check size is zero -- if not offer to
4457 * clear it
4458 */
4459static void check_size(e2fsck_t ctx, struct problem_context *pctx)
4460{
4461 struct ext2_inode *inode = pctx->inode;
4462
4463 if ((inode->i_size == 0) && (inode->i_size_high == 0))
4464 return;
4465
4466 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
4467 return;
4468
4469 inode->i_size = 0;
4470 inode->i_size_high = 0;
4471 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4472}
4473
4474static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
4475{
4476 struct ext2_super_block *sb = ctx->fs->super;
4477 struct ext2_inode_large *inode;
4478 struct ext2_ext_attr_entry *entry;
4479 char *start, *end;
4480 int storage_size, remain, offs;
4481 int problem = 0;
4482
4483 inode = (struct ext2_inode_large *) pctx->inode;
4484 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
4485 inode->i_extra_isize;
4486 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4487 inode->i_extra_isize + sizeof(__u32);
4488 end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
4489 entry = (struct ext2_ext_attr_entry *) start;
4490
4491 /* scan all entry's headers first */
4492
4493 /* take finish entry 0UL into account */
4494 remain = storage_size - sizeof(__u32);
4495 offs = end - start;
4496
4497 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
4498
4499 /* header eats this space */
4500 remain -= sizeof(struct ext2_ext_attr_entry);
4501
4502 /* is attribute name valid? */
4503 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
4504 pctx->num = entry->e_name_len;
4505 problem = PR_1_ATTR_NAME_LEN;
4506 goto fix;
4507 }
4508
4509 /* attribute len eats this space */
4510 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
4511
4512 /* check value size */
4513 if (entry->e_value_size == 0 || entry->e_value_size > remain) {
4514 pctx->num = entry->e_value_size;
4515 problem = PR_1_ATTR_VALUE_SIZE;
4516 goto fix;
4517 }
4518
4519 /* check value placement */
4520 if (entry->e_value_offs +
4521 EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
4522 printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
4523 pctx->num = entry->e_value_offs;
4524 problem = PR_1_ATTR_VALUE_OFFSET;
4525 goto fix;
4526 }
4527
4528 /* e_value_block must be 0 in inode's ea */
4529 if (entry->e_value_block != 0) {
4530 pctx->num = entry->e_value_block;
4531 problem = PR_1_ATTR_VALUE_BLOCK;
4532 goto fix;
4533 }
4534
4535 /* e_hash must be 0 in inode's ea */
4536 if (entry->e_hash != 0) {
4537 pctx->num = entry->e_hash;
4538 problem = PR_1_ATTR_HASH;
4539 goto fix;
4540 }
4541
4542 remain -= entry->e_value_size;
4543 offs -= EXT2_XATTR_SIZE(entry->e_value_size);
4544
4545 entry = EXT2_EXT_ATTR_NEXT(entry);
4546 }
4547fix:
4548 /*
4549 * it seems like a corruption. it's very unlikely we could repair
4550 * EA(s) in automatic fashion -bzzz
4551 */
4552#if 0
4553 problem = PR_1_ATTR_HASH;
4554#endif
4555 if (problem == 0 || !fix_problem(ctx, problem, pctx))
4556 return;
4557
4558 /* simple remove all possible EA(s) */
4559 *((__u32 *)start) = 0UL;
4560 e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
4561 EXT2_INODE_SIZE(sb), "pass1");
4562}
4563
4564static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
4565{
4566 struct ext2_super_block *sb = ctx->fs->super;
4567 struct ext2_inode_large *inode;
4568 __u32 *eamagic;
4569 int min, max;
4570
4571 inode = (struct ext2_inode_large *) pctx->inode;
4572 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
4573 /* this isn't large inode. so, nothing to check */
4574 return;
4575 }
4576
4577#if 0
4578 printf("inode #%u, i_extra_size %d\n", pctx->ino,
4579 inode->i_extra_isize);
4580#endif
4581 /* i_extra_isize must cover i_extra_isize + i_pad1 at least */
4582 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
4583 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
4584 /*
4585 * For now we will allow i_extra_isize to be 0, but really
4586 * implementations should never allow i_extra_isize to be 0
4587 */
4588 if (inode->i_extra_isize &&
4589 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
4590 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
4591 return;
4592 inode->i_extra_isize = min;
4593 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
4594 EXT2_INODE_SIZE(sb), "pass1");
4595 return;
4596 }
4597
4598 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4599 inode->i_extra_isize);
4600 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
4601 /* it seems inode has an extended attribute(s) in body */
4602 check_ea_in_inode(ctx, pctx);
4603 }
4604}
4605
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004606static void e2fsck_pass1(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004607{
4608 int i;
4609 __u64 max_sizes;
4610 ext2_filsys fs = ctx->fs;
4611 ext2_ino_t ino;
4612 struct ext2_inode *inode;
4613 ext2_inode_scan scan;
4614 char *block_buf;
4615#ifdef RESOURCE_TRACK
4616 struct resource_track rtrack;
4617#endif
4618 unsigned char frag, fsize;
4619 struct problem_context pctx;
4620 struct scan_callback_struct scan_struct;
4621 struct ext2_super_block *sb = ctx->fs->super;
4622 int imagic_fs;
4623 int busted_fs_time = 0;
4624 int inode_size;
4625
4626#ifdef RESOURCE_TRACK
4627 init_resource_track(&rtrack);
4628#endif
4629 clear_problem_context(&pctx);
4630
4631 if (!(ctx->options & E2F_OPT_PREEN))
4632 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
4633
4634 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
4635 !(ctx->options & E2F_OPT_NO)) {
4636 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
4637 ctx->dirs_to_hash = 0;
4638 }
4639
4640#ifdef MTRACE
4641 mtrace_print("Pass 1");
4642#endif
4643
4644#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
4645
4646 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
4647 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
4648 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
4649 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
4650 max_sizes = (max_sizes * (1UL << i)) - 1;
4651 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
4652 }
4653#undef EXT2_BPP
4654
4655 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
4656
4657 /*
4658 * Allocate bitmaps structures
4659 */
4660 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
4661 &ctx->inode_used_map);
4662 if (pctx.errcode) {
4663 pctx.num = 1;
4664 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4665 ctx->flags |= E2F_FLAG_ABORT;
4666 return;
4667 }
4668 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4669 _("directory inode map"), &ctx->inode_dir_map);
4670 if (pctx.errcode) {
4671 pctx.num = 2;
4672 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4673 ctx->flags |= E2F_FLAG_ABORT;
4674 return;
4675 }
4676 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4677 _("regular file inode map"), &ctx->inode_reg_map);
4678 if (pctx.errcode) {
4679 pctx.num = 6;
4680 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4681 ctx->flags |= E2F_FLAG_ABORT;
4682 return;
4683 }
4684 pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
4685 &ctx->block_found_map);
4686 if (pctx.errcode) {
4687 pctx.num = 1;
4688 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4689 ctx->flags |= E2F_FLAG_ABORT;
4690 return;
4691 }
4692 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
4693 &ctx->inode_link_info);
4694 if (pctx.errcode) {
4695 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
4696 ctx->flags |= E2F_FLAG_ABORT;
4697 return;
4698 }
4699 inode_size = EXT2_INODE_SIZE(fs->super);
4700 inode = (struct ext2_inode *)
4701 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
4702
4703 inodes_to_process = (struct process_inode_block *)
4704 e2fsck_allocate_memory(ctx,
4705 (ctx->process_inode_size *
4706 sizeof(struct process_inode_block)),
4707 "array of inodes to process");
4708 process_inode_count = 0;
4709
4710 pctx.errcode = ext2fs_init_dblist(fs, 0);
4711 if (pctx.errcode) {
4712 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
4713 ctx->flags |= E2F_FLAG_ABORT;
4714 return;
4715 }
4716
4717 /*
4718 * If the last orphan field is set, clear it, since the pass1
4719 * processing will automatically find and clear the orphans.
4720 * In the future, we may want to try using the last_orphan
4721 * linked list ourselves, but for now, we clear it so that the
4722 * ext3 mount code won't get confused.
4723 */
4724 if (!(ctx->options & E2F_OPT_READONLY)) {
4725 if (fs->super->s_last_orphan) {
4726 fs->super->s_last_orphan = 0;
4727 ext2fs_mark_super_dirty(fs);
4728 }
4729 }
4730
4731 mark_table_blocks(ctx);
4732 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
4733 "block interate buffer");
4734 e2fsck_use_inode_shortcuts(ctx, 1);
4735 ehandler_operation(_("doing inode scan"));
4736 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
4737 &scan);
4738 if (pctx.errcode) {
4739 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4740 ctx->flags |= E2F_FLAG_ABORT;
4741 return;
4742 }
4743 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
4744 ctx->stashed_inode = inode;
4745 scan_struct.ctx = ctx;
4746 scan_struct.block_buf = block_buf;
4747 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
4748 if (ctx->progress)
4749 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
4750 return;
4751 if (fs->super->s_wtime < fs->super->s_inodes_count)
4752 busted_fs_time = 1;
4753
4754 while (1) {
4755 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
4756 inode, inode_size);
4757 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4758 return;
4759 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
4760 if (!ctx->inode_bb_map)
4761 alloc_bb_map(ctx);
4762 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
4763 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4764 continue;
4765 }
4766 if (pctx.errcode) {
4767 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4768 ctx->flags |= E2F_FLAG_ABORT;
4769 return;
4770 }
4771 if (!ino)
4772 break;
4773 pctx.ino = ino;
4774 pctx.inode = inode;
4775 ctx->stashed_ino = ino;
4776 if (inode->i_links_count) {
4777 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
4778 ino, inode->i_links_count);
4779 if (pctx.errcode) {
4780 pctx.num = inode->i_links_count;
4781 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
4782 ctx->flags |= E2F_FLAG_ABORT;
4783 return;
4784 }
4785 }
4786 if (ino == EXT2_BAD_INO) {
4787 struct process_block_struct_1 pb;
4788
4789 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
4790 &pb.fs_meta_blocks);
4791 if (pctx.errcode) {
4792 pctx.num = 4;
4793 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4794 ctx->flags |= E2F_FLAG_ABORT;
4795 return;
4796 }
4797 pb.ino = EXT2_BAD_INO;
4798 pb.num_blocks = pb.last_block = 0;
4799 pb.num_illegal_blocks = 0;
4800 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
4801 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
4802 pb.inode = inode;
4803 pb.pctx = &pctx;
4804 pb.ctx = ctx;
4805 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
4806 block_buf, process_bad_block, &pb);
4807 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
4808 if (pctx.errcode) {
4809 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
4810 ctx->flags |= E2F_FLAG_ABORT;
4811 return;
4812 }
4813 if (pb.bbcheck)
4814 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
4815 ctx->flags |= E2F_FLAG_ABORT;
4816 return;
4817 }
4818 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4819 clear_problem_context(&pctx);
4820 continue;
4821 } else if (ino == EXT2_ROOT_INO) {
4822 /*
4823 * Make sure the root inode is a directory; if
4824 * not, offer to clear it. It will be
4825 * regnerated in pass #3.
4826 */
4827 if (!LINUX_S_ISDIR(inode->i_mode)) {
4828 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
4829 inode->i_dtime = time(0);
4830 inode->i_links_count = 0;
4831 ext2fs_icount_store(ctx->inode_link_info,
4832 ino, 0);
4833 e2fsck_write_inode(ctx, ino, inode,
4834 "pass1");
4835 }
4836
4837 }
4838 /*
4839 * If dtime is set, offer to clear it. mke2fs
4840 * version 0.2b created filesystems with the
4841 * dtime field set for the root and lost+found
4842 * directories. We won't worry about
4843 * /lost+found, since that can be regenerated
4844 * easily. But we will fix the root directory
4845 * as a special case.
4846 */
4847 if (inode->i_dtime && inode->i_links_count) {
4848 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
4849 inode->i_dtime = 0;
4850 e2fsck_write_inode(ctx, ino, inode,
4851 "pass1");
4852 }
4853 }
4854 } else if (ino == EXT2_JOURNAL_INO) {
4855 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4856 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
4857 if (!LINUX_S_ISREG(inode->i_mode) &&
4858 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
4859 &pctx)) {
4860 inode->i_mode = LINUX_S_IFREG;
4861 e2fsck_write_inode(ctx, ino, inode,
4862 "pass1");
4863 }
4864 check_blocks(ctx, &pctx, block_buf);
4865 continue;
4866 }
4867 if ((inode->i_links_count || inode->i_blocks ||
4868 inode->i_blocks || inode->i_block[0]) &&
4869 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
4870 &pctx)) {
4871 memset(inode, 0, inode_size);
4872 ext2fs_icount_store(ctx->inode_link_info,
4873 ino, 0);
4874 e2fsck_write_inode_full(ctx, ino, inode,
4875 inode_size, "pass1");
4876 }
4877 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
4878 int problem = 0;
4879
4880 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4881 if (ino == EXT2_BOOT_LOADER_INO) {
4882 if (LINUX_S_ISDIR(inode->i_mode))
4883 problem = PR_1_RESERVED_BAD_MODE;
4884 } else if (ino == EXT2_RESIZE_INO) {
4885 if (inode->i_mode &&
4886 !LINUX_S_ISREG(inode->i_mode))
4887 problem = PR_1_RESERVED_BAD_MODE;
4888 } else {
4889 if (inode->i_mode != 0)
4890 problem = PR_1_RESERVED_BAD_MODE;
4891 }
4892 if (problem) {
4893 if (fix_problem(ctx, problem, &pctx)) {
4894 inode->i_mode = 0;
4895 e2fsck_write_inode(ctx, ino, inode,
4896 "pass1");
4897 }
4898 }
4899 check_blocks(ctx, &pctx, block_buf);
4900 continue;
4901 }
4902 /*
4903 * Check for inodes who might have been part of the
4904 * orphaned list linked list. They should have gotten
4905 * dealt with by now, unless the list had somehow been
4906 * corrupted.
4907 *
4908 * FIXME: In the future, inodes which are still in use
4909 * (and which are therefore) pending truncation should
4910 * be handled specially. Right now we just clear the
4911 * dtime field, and the normal e2fsck handling of
4912 * inodes where i_size and the inode blocks are
4913 * inconsistent is to fix i_size, instead of releasing
4914 * the extra blocks. This won't catch the inodes that
4915 * was at the end of the orphan list, but it's better
4916 * than nothing. The right answer is that there
4917 * shouldn't be any bugs in the orphan list handling. :-)
4918 */
4919 if (inode->i_dtime && !busted_fs_time &&
4920 inode->i_dtime < ctx->fs->super->s_inodes_count) {
4921 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
4922 inode->i_dtime = inode->i_links_count ?
4923 0 : time(0);
4924 e2fsck_write_inode(ctx, ino, inode,
4925 "pass1");
4926 }
4927 }
4928
4929 /*
4930 * This code assumes that deleted inodes have
4931 * i_links_count set to 0.
4932 */
4933 if (!inode->i_links_count) {
4934 if (!inode->i_dtime && inode->i_mode) {
4935 if (fix_problem(ctx,
4936 PR_1_ZERO_DTIME, &pctx)) {
4937 inode->i_dtime = time(0);
4938 e2fsck_write_inode(ctx, ino, inode,
4939 "pass1");
4940 }
4941 }
4942 continue;
4943 }
4944 /*
4945 * n.b. 0.3c ext2fs code didn't clear i_links_count for
4946 * deleted files. Oops.
4947 *
4948 * Since all new ext2 implementations get this right,
4949 * we now assume that the case of non-zero
4950 * i_links_count and non-zero dtime means that we
4951 * should keep the file, not delete it.
4952 *
4953 */
4954 if (inode->i_dtime) {
4955 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
4956 inode->i_dtime = 0;
4957 e2fsck_write_inode(ctx, ino, inode, "pass1");
4958 }
4959 }
4960
4961 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4962 switch (fs->super->s_creator_os) {
4963 case EXT2_OS_LINUX:
4964 frag = inode->osd2.linux2.l_i_frag;
4965 fsize = inode->osd2.linux2.l_i_fsize;
4966 break;
4967 case EXT2_OS_HURD:
4968 frag = inode->osd2.hurd2.h_i_frag;
4969 fsize = inode->osd2.hurd2.h_i_fsize;
4970 break;
4971 case EXT2_OS_MASIX:
4972 frag = inode->osd2.masix2.m_i_frag;
4973 fsize = inode->osd2.masix2.m_i_fsize;
4974 break;
4975 default:
4976 frag = fsize = 0;
4977 }
4978
4979 if (inode->i_faddr || frag || fsize ||
4980 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
4981 mark_inode_bad(ctx, ino);
4982 if (inode->i_flags & EXT2_IMAGIC_FL) {
4983 if (imagic_fs) {
4984 if (!ctx->inode_imagic_map)
4985 alloc_imagic_map(ctx);
4986 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
4987 ino);
4988 } else {
4989 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
4990 inode->i_flags &= ~EXT2_IMAGIC_FL;
4991 e2fsck_write_inode(ctx, ino,
4992 inode, "pass1");
4993 }
4994 }
4995 }
4996
4997 check_inode_extra_space(ctx, &pctx);
4998
4999 if (LINUX_S_ISDIR(inode->i_mode)) {
5000 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
5001 e2fsck_add_dir_info(ctx, ino, 0);
5002 ctx->fs_directory_count++;
5003 } else if (LINUX_S_ISREG (inode->i_mode)) {
5004 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
5005 ctx->fs_regular_count++;
5006 } else if (LINUX_S_ISCHR (inode->i_mode) &&
5007 e2fsck_pass1_check_device_inode(fs, inode)) {
5008 check_immutable(ctx, &pctx);
5009 check_size(ctx, &pctx);
5010 ctx->fs_chardev_count++;
5011 } else if (LINUX_S_ISBLK (inode->i_mode) &&
5012 e2fsck_pass1_check_device_inode(fs, inode)) {
5013 check_immutable(ctx, &pctx);
5014 check_size(ctx, &pctx);
5015 ctx->fs_blockdev_count++;
5016 } else if (LINUX_S_ISLNK (inode->i_mode) &&
5017 e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
5018 check_immutable(ctx, &pctx);
5019 ctx->fs_symlinks_count++;
5020 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
5021 ctx->fs_fast_symlinks_count++;
5022 check_blocks(ctx, &pctx, block_buf);
5023 continue;
5024 }
5025 }
5026 else if (LINUX_S_ISFIFO (inode->i_mode) &&
5027 e2fsck_pass1_check_device_inode(fs, inode)) {
5028 check_immutable(ctx, &pctx);
5029 check_size(ctx, &pctx);
5030 ctx->fs_fifo_count++;
5031 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
5032 e2fsck_pass1_check_device_inode(fs, inode)) {
5033 check_immutable(ctx, &pctx);
5034 check_size(ctx, &pctx);
5035 ctx->fs_sockets_count++;
5036 } else
5037 mark_inode_bad(ctx, ino);
5038 if (inode->i_block[EXT2_IND_BLOCK])
5039 ctx->fs_ind_count++;
5040 if (inode->i_block[EXT2_DIND_BLOCK])
5041 ctx->fs_dind_count++;
5042 if (inode->i_block[EXT2_TIND_BLOCK])
5043 ctx->fs_tind_count++;
5044 if (inode->i_block[EXT2_IND_BLOCK] ||
5045 inode->i_block[EXT2_DIND_BLOCK] ||
5046 inode->i_block[EXT2_TIND_BLOCK] ||
5047 inode->i_file_acl) {
5048 inodes_to_process[process_inode_count].ino = ino;
5049 inodes_to_process[process_inode_count].inode = *inode;
5050 process_inode_count++;
5051 } else
5052 check_blocks(ctx, &pctx, block_buf);
5053
5054 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5055 return;
5056
5057 if (process_inode_count >= ctx->process_inode_size) {
5058 process_inodes(ctx, block_buf);
5059
5060 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5061 return;
5062 }
5063 }
5064 process_inodes(ctx, block_buf);
5065 ext2fs_close_inode_scan(scan);
5066 ehandler_operation(0);
5067
5068 /*
5069 * If any extended attribute blocks' reference counts need to
5070 * be adjusted, either up (ctx->refcount_extra), or down
5071 * (ctx->refcount), then fix them.
5072 */
5073 if (ctx->refcount) {
5074 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
5075 ea_refcount_free(ctx->refcount);
5076 ctx->refcount = 0;
5077 }
5078 if (ctx->refcount_extra) {
5079 adjust_extattr_refcount(ctx, ctx->refcount_extra,
5080 block_buf, +1);
5081 ea_refcount_free(ctx->refcount_extra);
5082 ctx->refcount_extra = 0;
5083 }
5084
5085 if (ctx->invalid_bitmaps)
5086 handle_fs_bad_blocks(ctx);
5087
5088 /* We don't need the block_ea_map any more */
5089 if (ctx->block_ea_map) {
5090 ext2fs_free_block_bitmap(ctx->block_ea_map);
5091 ctx->block_ea_map = 0;
5092 }
5093
5094 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
5095 ext2fs_block_bitmap save_bmap;
5096
5097 save_bmap = fs->block_map;
5098 fs->block_map = ctx->block_found_map;
5099 clear_problem_context(&pctx);
5100 pctx.errcode = ext2fs_create_resize_inode(fs);
5101 if (pctx.errcode) {
5102 fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
5103 /* Should never get here */
5104 ctx->flags |= E2F_FLAG_ABORT;
5105 return;
5106 }
5107 fs->block_map = save_bmap;
5108 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
5109 }
5110
5111 if (ctx->flags & E2F_FLAG_RESTART) {
5112 /*
5113 * Only the master copy of the superblock and block
5114 * group descriptors are going to be written during a
5115 * restart, so set the superblock to be used to be the
5116 * master superblock.
5117 */
5118 ctx->use_superblock = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00005119 unwind_pass1();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005120 goto endit;
5121 }
5122
5123 if (ctx->block_dup_map) {
5124 if (ctx->options & E2F_OPT_PREEN) {
5125 clear_problem_context(&pctx);
5126 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
5127 }
5128 e2fsck_pass1_dupblocks(ctx, block_buf);
5129 }
5130 ext2fs_free_mem(&inodes_to_process);
5131endit:
5132 e2fsck_use_inode_shortcuts(ctx, 0);
5133
5134 ext2fs_free_mem(&block_buf);
5135 ext2fs_free_mem(&inode);
5136
5137#ifdef RESOURCE_TRACK
5138 if (ctx->options & E2F_OPT_TIME2) {
5139 e2fsck_clear_progbar(ctx);
5140 print_resource_track(_("Pass 1"), &rtrack);
5141 }
5142#endif
5143}
5144
5145/*
5146 * When the inode_scan routines call this callback at the end of the
5147 * glock group, call process_inodes.
5148 */
5149static errcode_t scan_callback(ext2_filsys fs,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005150 ext2_inode_scan scan FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005151 dgrp_t group, void * priv_data)
5152{
5153 struct scan_callback_struct *scan_struct;
5154 e2fsck_t ctx;
5155
5156 scan_struct = (struct scan_callback_struct *) priv_data;
5157 ctx = scan_struct->ctx;
5158
5159 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
5160
5161 if (ctx->progress)
5162 if ((ctx->progress)(ctx, 1, group+1,
5163 ctx->fs->group_desc_count))
5164 return EXT2_ET_CANCEL_REQUESTED;
5165
5166 return 0;
5167}
5168
5169/*
5170 * Process the inodes in the "inodes to process" list.
5171 */
5172static void process_inodes(e2fsck_t ctx, char *block_buf)
5173{
5174 int i;
5175 struct ext2_inode *old_stashed_inode;
5176 ext2_ino_t old_stashed_ino;
5177 const char *old_operation;
5178 char buf[80];
5179 struct problem_context pctx;
5180
5181#if 0
5182 printf("begin process_inodes: ");
5183#endif
5184 if (process_inode_count == 0)
5185 return;
5186 old_operation = ehandler_operation(0);
5187 old_stashed_inode = ctx->stashed_inode;
5188 old_stashed_ino = ctx->stashed_ino;
5189 qsort(inodes_to_process, process_inode_count,
5190 sizeof(struct process_inode_block), process_inode_cmp);
5191 clear_problem_context(&pctx);
5192 for (i=0; i < process_inode_count; i++) {
5193 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
5194 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
5195
5196#if 0
5197 printf("%u ", pctx.ino);
5198#endif
5199 sprintf(buf, _("reading indirect blocks of inode %u"),
5200 pctx.ino);
5201 ehandler_operation(buf);
5202 check_blocks(ctx, &pctx, block_buf);
5203 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5204 break;
5205 }
5206 ctx->stashed_inode = old_stashed_inode;
5207 ctx->stashed_ino = old_stashed_ino;
5208 process_inode_count = 0;
5209#if 0
5210 printf("end process inodes\n");
5211#endif
5212 ehandler_operation(old_operation);
5213}
5214
5215static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
5216{
5217 const struct process_inode_block *ib_a =
5218 (const struct process_inode_block *) a;
5219 const struct process_inode_block *ib_b =
5220 (const struct process_inode_block *) b;
5221 int ret;
5222
5223 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
5224 ib_b->inode.i_block[EXT2_IND_BLOCK]);
5225 if (ret == 0)
5226 ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
5227 return ret;
5228}
5229
5230/*
5231 * Mark an inode as being bad in some what
5232 */
5233static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
5234{
5235 struct problem_context pctx;
5236
5237 if (!ctx->inode_bad_map) {
5238 clear_problem_context(&pctx);
5239
5240 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5241 _("bad inode map"), &ctx->inode_bad_map);
5242 if (pctx.errcode) {
5243 pctx.num = 3;
5244 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5245 /* Should never get here */
5246 ctx->flags |= E2F_FLAG_ABORT;
5247 return;
5248 }
5249 }
5250 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
5251}
5252
5253
5254/*
5255 * This procedure will allocate the inode "bb" (badblock) map table
5256 */
5257static void alloc_bb_map(e2fsck_t ctx)
5258{
5259 struct problem_context pctx;
5260
5261 clear_problem_context(&pctx);
5262 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5263 _("inode in bad block map"),
5264 &ctx->inode_bb_map);
5265 if (pctx.errcode) {
5266 pctx.num = 4;
5267 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5268 /* Should never get here */
5269 ctx->flags |= E2F_FLAG_ABORT;
5270 return;
5271 }
5272}
5273
5274/*
5275 * This procedure will allocate the inode imagic table
5276 */
5277static void alloc_imagic_map(e2fsck_t ctx)
5278{
5279 struct problem_context pctx;
5280
5281 clear_problem_context(&pctx);
5282 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5283 _("imagic inode map"),
5284 &ctx->inode_imagic_map);
5285 if (pctx.errcode) {
5286 pctx.num = 5;
5287 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5288 /* Should never get here */
5289 ctx->flags |= E2F_FLAG_ABORT;
5290 return;
5291 }
5292}
5293
5294/*
5295 * Marks a block as in use, setting the dup_map if it's been set
5296 * already. Called by process_block and process_bad_block.
5297 *
5298 * WARNING: Assumes checks have already been done to make sure block
5299 * is valid. This is true in both process_block and process_bad_block.
5300 */
5301static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
5302{
5303 struct problem_context pctx;
5304
5305 clear_problem_context(&pctx);
5306
5307 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
5308 if (!ctx->block_dup_map) {
5309 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
5310 _("multiply claimed block map"),
5311 &ctx->block_dup_map);
5312 if (pctx.errcode) {
5313 pctx.num = 3;
5314 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
5315 &pctx);
5316 /* Should never get here */
5317 ctx->flags |= E2F_FLAG_ABORT;
5318 return;
5319 }
5320 }
5321 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
5322 } else {
5323 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
5324 }
5325}
5326
5327/*
5328 * Adjust the extended attribute block's reference counts at the end
5329 * of pass 1, either by subtracting out references for EA blocks that
5330 * are still referenced in ctx->refcount, or by adding references for
5331 * EA blocks that had extra references as accounted for in
5332 * ctx->refcount_extra.
5333 */
5334static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
5335 char *block_buf, int adjust_sign)
5336{
5337 struct ext2_ext_attr_header *header;
5338 struct problem_context pctx;
5339 ext2_filsys fs = ctx->fs;
5340 blk_t blk;
5341 __u32 should_be;
5342 int count;
5343
5344 clear_problem_context(&pctx);
5345
5346 ea_refcount_intr_begin(refcount);
5347 while (1) {
5348 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
5349 break;
5350 pctx.blk = blk;
5351 pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5352 if (pctx.errcode) {
5353 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
5354 return;
5355 }
5356 header = (struct ext2_ext_attr_header *) block_buf;
5357 pctx.blkcount = header->h_refcount;
5358 should_be = header->h_refcount + adjust_sign * count;
5359 pctx.num = should_be;
5360 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
5361 header->h_refcount = should_be;
5362 pctx.errcode = ext2fs_write_ext_attr(fs, blk,
5363 block_buf);
5364 if (pctx.errcode) {
5365 fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
5366 continue;
5367 }
5368 }
5369 }
5370}
5371
5372/*
5373 * Handle processing the extended attribute blocks
5374 */
5375static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
5376 char *block_buf)
5377{
5378 ext2_filsys fs = ctx->fs;
5379 ext2_ino_t ino = pctx->ino;
5380 struct ext2_inode *inode = pctx->inode;
5381 blk_t blk;
5382 char * end;
5383 struct ext2_ext_attr_header *header;
5384 struct ext2_ext_attr_entry *entry;
5385 int count;
5386 region_t region;
5387
5388 blk = inode->i_file_acl;
5389 if (blk == 0)
5390 return 0;
5391
5392 /*
5393 * If the Extended attribute flag isn't set, then a non-zero
5394 * file acl means that the inode is corrupted.
5395 *
5396 * Or if the extended attribute block is an invalid block,
5397 * then the inode is also corrupted.
5398 */
5399 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
5400 (blk < fs->super->s_first_data_block) ||
5401 (blk >= fs->super->s_blocks_count)) {
5402 mark_inode_bad(ctx, ino);
5403 return 0;
5404 }
5405
5406 /* If ea bitmap hasn't been allocated, create it */
5407 if (!ctx->block_ea_map) {
5408 pctx->errcode = ext2fs_allocate_block_bitmap(fs,
5409 _("ext attr block map"),
5410 &ctx->block_ea_map);
5411 if (pctx->errcode) {
5412 pctx->num = 2;
5413 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
5414 ctx->flags |= E2F_FLAG_ABORT;
5415 return 0;
5416 }
5417 }
5418
5419 /* Create the EA refcount structure if necessary */
5420 if (!ctx->refcount) {
5421 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
5422 if (pctx->errcode) {
5423 pctx->num = 1;
5424 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5425 ctx->flags |= E2F_FLAG_ABORT;
5426 return 0;
5427 }
5428 }
5429
5430#if 0
5431 /* Debugging text */
5432 printf("Inode %u has EA block %u\n", ino, blk);
5433#endif
5434
5435 /* Have we seen this EA block before? */
5436 if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
5437 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
5438 return 1;
5439 /* Ooops, this EA was referenced more than it stated */
5440 if (!ctx->refcount_extra) {
5441 pctx->errcode = ea_refcount_create(0,
5442 &ctx->refcount_extra);
5443 if (pctx->errcode) {
5444 pctx->num = 2;
5445 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5446 ctx->flags |= E2F_FLAG_ABORT;
5447 return 0;
5448 }
5449 }
5450 ea_refcount_increment(ctx->refcount_extra, blk, 0);
5451 return 1;
5452 }
5453
5454 /*
5455 * OK, we haven't seen this EA block yet. So we need to
5456 * validate it
5457 */
5458 pctx->blk = blk;
5459 pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5460 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
5461 goto clear_extattr;
5462 header = (struct ext2_ext_attr_header *) block_buf;
5463 pctx->blk = inode->i_file_acl;
5464 if (((ctx->ext_attr_ver == 1) &&
5465 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
5466 ((ctx->ext_attr_ver == 2) &&
5467 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
5468 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
5469 goto clear_extattr;
5470 }
5471
5472 if (header->h_blocks != 1) {
5473 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
5474 goto clear_extattr;
5475 }
5476
5477 region = region_create(0, fs->blocksize);
5478 if (!region) {
5479 fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
5480 ctx->flags |= E2F_FLAG_ABORT;
5481 return 0;
5482 }
5483 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
5484 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5485 goto clear_extattr;
5486 }
5487
5488 entry = (struct ext2_ext_attr_entry *)(header+1);
5489 end = block_buf + fs->blocksize;
5490 while ((char *)entry < end && *(__u32 *)entry) {
5491 if (region_allocate(region, (char *)entry - (char *)header,
5492 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
5493 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5494 goto clear_extattr;
5495 }
5496 if ((ctx->ext_attr_ver == 1 &&
5497 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
5498 (ctx->ext_attr_ver == 2 &&
5499 entry->e_name_index == 0)) {
5500 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
5501 goto clear_extattr;
5502 }
5503 if (entry->e_value_block != 0) {
5504 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
5505 goto clear_extattr;
5506 }
5507 if (entry->e_value_size &&
5508 region_allocate(region, entry->e_value_offs,
5509 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
5510 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5511 goto clear_extattr;
5512 }
5513 entry = EXT2_EXT_ATTR_NEXT(entry);
5514 }
5515 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
5516 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5517 goto clear_extattr;
5518 }
5519 region_free(region);
5520
5521 count = header->h_refcount - 1;
5522 if (count)
5523 ea_refcount_store(ctx->refcount, blk, count);
5524 mark_block_used(ctx, blk);
5525 ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
5526
5527 return 1;
5528
5529clear_extattr:
5530 inode->i_file_acl = 0;
5531 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
5532 return 0;
5533}
5534
5535/* Returns 1 if bad htree, 0 if OK */
5536static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005537 ext2_ino_t ino FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005538 struct ext2_inode *inode,
5539 char *block_buf)
5540{
5541 struct ext2_dx_root_info *root;
5542 ext2_filsys fs = ctx->fs;
5543 errcode_t retval;
5544 blk_t blk;
5545
5546 if ((!LINUX_S_ISDIR(inode->i_mode) &&
5547 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
5548 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
5549 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
5550 return 1;
5551
5552 blk = inode->i_block[0];
5553 if (((blk == 0) ||
5554 (blk < fs->super->s_first_data_block) ||
5555 (blk >= fs->super->s_blocks_count)) &&
5556 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5557 return 1;
5558
5559 retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
5560 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5561 return 1;
5562
5563 /* XXX should check that beginning matches a directory */
5564 root = (struct ext2_dx_root_info *) (block_buf + 24);
5565
5566 if ((root->reserved_zero || root->info_length < 8) &&
5567 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5568 return 1;
5569
5570 pctx->num = root->hash_version;
5571 if ((root->hash_version != EXT2_HASH_LEGACY) &&
5572 (root->hash_version != EXT2_HASH_HALF_MD4) &&
5573 (root->hash_version != EXT2_HASH_TEA) &&
5574 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
5575 return 1;
5576
5577 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
5578 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
5579 return 1;
5580
5581 pctx->num = root->indirect_levels;
5582 if ((root->indirect_levels > 1) &&
5583 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
5584 return 1;
5585
5586 return 0;
5587}
5588
5589/*
5590 * This subroutine is called on each inode to account for all of the
5591 * blocks used by that inode.
5592 */
5593static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
5594 char *block_buf)
5595{
5596 ext2_filsys fs = ctx->fs;
5597 struct process_block_struct_1 pb;
5598 ext2_ino_t ino = pctx->ino;
5599 struct ext2_inode *inode = pctx->inode;
5600 int bad_size = 0;
5601 int dirty_inode = 0;
5602 __u64 size;
5603
5604 pb.ino = ino;
5605 pb.num_blocks = 0;
5606 pb.last_block = -1;
5607 pb.num_illegal_blocks = 0;
5608 pb.suppress = 0; pb.clear = 0;
5609 pb.fragmented = 0;
5610 pb.compressed = 0;
5611 pb.previous_block = 0;
5612 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
5613 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
5614 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
5615 pb.inode = inode;
5616 pb.pctx = pctx;
5617 pb.ctx = ctx;
5618 pctx->ino = ino;
5619 pctx->errcode = 0;
5620
5621 if (inode->i_flags & EXT2_COMPRBLK_FL) {
5622 if (fs->super->s_feature_incompat &
5623 EXT2_FEATURE_INCOMPAT_COMPRESSION)
5624 pb.compressed = 1;
5625 else {
5626 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
5627 inode->i_flags &= ~EXT2_COMPRBLK_FL;
5628 dirty_inode++;
5629 }
5630 }
5631 }
5632
5633 if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
5634 pb.num_blocks++;
5635
5636 if (ext2fs_inode_has_valid_blocks(inode))
5637 pctx->errcode = ext2fs_block_iterate2(fs, ino,
5638 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
5639 block_buf, process_block, &pb);
5640 end_problem_latch(ctx, PR_LATCH_BLOCK);
5641 end_problem_latch(ctx, PR_LATCH_TOOBIG);
5642 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5643 goto out;
5644 if (pctx->errcode)
5645 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
5646
5647 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
5648 ctx->fs_fragmented++;
5649
5650 if (pb.clear) {
5651 inode->i_links_count = 0;
5652 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5653 inode->i_dtime = time(0);
5654 dirty_inode++;
5655 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5656 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5657 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5658 /*
5659 * The inode was probably partially accounted for
5660 * before processing was aborted, so we need to
5661 * restart the pass 1 scan.
5662 */
5663 ctx->flags |= E2F_FLAG_RESTART;
5664 goto out;
5665 }
5666
5667 if (inode->i_flags & EXT2_INDEX_FL) {
5668 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
5669 inode->i_flags &= ~EXT2_INDEX_FL;
5670 dirty_inode++;
5671 } else {
5672#ifdef ENABLE_HTREE
5673 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
5674#endif
5675 }
5676 }
5677 if (ctx->dirs_to_hash && pb.is_dir &&
5678 !(inode->i_flags & EXT2_INDEX_FL) &&
5679 ((inode->i_size / fs->blocksize) >= 3))
5680 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
5681
5682 if (!pb.num_blocks && pb.is_dir) {
5683 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
5684 inode->i_links_count = 0;
5685 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5686 inode->i_dtime = time(0);
5687 dirty_inode++;
5688 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5689 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5690 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5691 ctx->fs_directory_count--;
5692 goto out;
5693 }
5694 }
5695
5696 pb.num_blocks *= (fs->blocksize / 512);
5697#if 0
5698 printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
5699 ino, inode->i_size, pb.last_block, inode->i_blocks,
5700 pb.num_blocks);
5701#endif
5702 if (pb.is_dir) {
5703 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
5704 if (nblock > (pb.last_block + 1))
5705 bad_size = 1;
5706 else if (nblock < (pb.last_block + 1)) {
5707 if (((pb.last_block + 1) - nblock) >
5708 fs->super->s_prealloc_dir_blocks)
5709 bad_size = 2;
5710 }
5711 } else {
5712 size = EXT2_I_SIZE(inode);
5713 if ((pb.last_block >= 0) &&
5714 (size < (__u64) pb.last_block * fs->blocksize))
5715 bad_size = 3;
5716 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
5717 bad_size = 4;
5718 }
5719 /* i_size for symlinks is checked elsewhere */
5720 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
5721 pctx->num = (pb.last_block+1) * fs->blocksize;
5722 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
5723 inode->i_size = pctx->num;
5724 if (!LINUX_S_ISDIR(inode->i_mode))
5725 inode->i_size_high = pctx->num >> 32;
5726 dirty_inode++;
5727 }
5728 pctx->num = 0;
5729 }
5730 if (LINUX_S_ISREG(inode->i_mode) &&
5731 (inode->i_size_high || inode->i_size & 0x80000000UL))
5732 ctx->large_files++;
5733 if (pb.num_blocks != inode->i_blocks) {
5734 pctx->num = pb.num_blocks;
5735 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
5736 inode->i_blocks = pb.num_blocks;
5737 dirty_inode++;
5738 }
5739 pctx->num = 0;
5740 }
5741out:
5742 if (dirty_inode)
5743 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
5744}
5745
5746#if 0
5747/*
5748 * Helper function called by process block when an illegal block is
5749 * found. It returns a description about why the block is illegal
5750 */
5751static char *describe_illegal_block(ext2_filsys fs, blk_t block)
5752{
5753 blk_t super;
5754 int i;
5755 static char problem[80];
5756
5757 super = fs->super->s_first_data_block;
5758 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
5759 if (block < super) {
5760 sprintf(problem, "< FIRSTBLOCK (%u)", super);
5761 return(problem);
5762 } else if (block >= fs->super->s_blocks_count) {
5763 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
5764 return(problem);
5765 }
5766 for (i = 0; i < fs->group_desc_count; i++) {
5767 if (block == super) {
5768 sprintf(problem, "is the superblock in group %d", i);
5769 break;
5770 }
5771 if (block > super &&
5772 block <= (super + fs->desc_blocks)) {
5773 sprintf(problem, "is in the group descriptors "
5774 "of group %d", i);
5775 break;
5776 }
5777 if (block == fs->group_desc[i].bg_block_bitmap) {
5778 sprintf(problem, "is the block bitmap of group %d", i);
5779 break;
5780 }
5781 if (block == fs->group_desc[i].bg_inode_bitmap) {
5782 sprintf(problem, "is the inode bitmap of group %d", i);
5783 break;
5784 }
5785 if (block >= fs->group_desc[i].bg_inode_table &&
5786 (block < fs->group_desc[i].bg_inode_table
5787 + fs->inode_blocks_per_group)) {
5788 sprintf(problem, "is in the inode table of group %d",
5789 i);
5790 break;
5791 }
5792 super += fs->super->s_blocks_per_group;
5793 }
5794 return(problem);
5795}
5796#endif
5797
5798/*
5799 * This is a helper function for check_blocks().
5800 */
5801static int process_block(ext2_filsys fs,
5802 blk_t *block_nr,
5803 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005804 blk_t ref_block FSCK_ATTR((unused)),
5805 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005806 void *priv_data)
5807{
5808 struct process_block_struct_1 *p;
5809 struct problem_context *pctx;
5810 blk_t blk = *block_nr;
5811 int ret_code = 0;
5812 int problem = 0;
5813 e2fsck_t ctx;
5814
5815 p = (struct process_block_struct_1 *) priv_data;
5816 pctx = p->pctx;
5817 ctx = p->ctx;
5818
5819 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
5820 /* todo: Check that the comprblk_fl is high, that the
5821 blkaddr pattern looks right (all non-holes up to
5822 first EXT2FS_COMPRESSED_BLKADDR, then all
5823 EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
5824 that the feature_incompat bit is high, and that the
5825 inode is a regular file. If we're doing a "full
5826 check" (a concept introduced to e2fsck by e2compr,
5827 meaning that we look at data blocks as well as
5828 metadata) then call some library routine that
5829 checks the compressed data. I'll have to think
5830 about this, because one particularly important
5831 problem to be able to fix is to recalculate the
5832 cluster size if necessary. I think that perhaps
5833 we'd better do most/all e2compr-specific checks
5834 separately, after the non-e2compr checks. If not
5835 doing a full check, it may be useful to test that
5836 the personality is linux; e.g. if it isn't then
5837 perhaps this really is just an illegal block. */
5838 return 0;
5839 }
5840
5841 if (blk == 0) {
5842 if (p->is_dir == 0) {
5843 /*
5844 * Should never happen, since only directories
5845 * get called with BLOCK_FLAG_HOLE
5846 */
5847#if DEBUG_E2FSCK
5848 printf("process_block() called with blk == 0, "
5849 "blockcnt=%d, inode %lu???\n",
5850 blockcnt, p->ino);
5851#endif
5852 return 0;
5853 }
5854 if (blockcnt < 0)
5855 return 0;
5856 if (blockcnt * fs->blocksize < p->inode->i_size) {
5857#if 0
5858 printf("Missing block (#%d) in directory inode %lu!\n",
5859 blockcnt, p->ino);
5860#endif
5861 goto mark_dir;
5862 }
5863 return 0;
5864 }
5865
5866#if 0
5867 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
5868 blockcnt);
5869#endif
5870
5871 /*
5872 * Simplistic fragmentation check. We merely require that the
5873 * file be contiguous. (Which can never be true for really
5874 * big files that are greater than a block group.)
5875 */
5876 if (!HOLE_BLKADDR(p->previous_block)) {
5877 if (p->previous_block+1 != blk)
5878 p->fragmented = 1;
5879 }
5880 p->previous_block = blk;
5881
5882 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
5883 problem = PR_1_TOOBIG_DIR;
5884 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
5885 problem = PR_1_TOOBIG_REG;
5886 if (!p->is_dir && !p->is_reg && blockcnt > 0)
5887 problem = PR_1_TOOBIG_SYMLINK;
5888
5889 if (blk < fs->super->s_first_data_block ||
5890 blk >= fs->super->s_blocks_count)
5891 problem = PR_1_ILLEGAL_BLOCK_NUM;
5892
5893 if (problem) {
5894 p->num_illegal_blocks++;
5895 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
5896 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
5897 p->clear = 1;
5898 return BLOCK_ABORT;
5899 }
5900 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
5901 p->suppress = 1;
5902 set_latch_flags(PR_LATCH_BLOCK,
5903 PRL_SUPPRESS, 0);
5904 }
5905 }
5906 pctx->blk = blk;
5907 pctx->blkcount = blockcnt;
5908 if (fix_problem(ctx, problem, pctx)) {
5909 blk = *block_nr = 0;
5910 ret_code = BLOCK_CHANGED;
5911 goto mark_dir;
5912 } else
5913 return 0;
5914 }
5915
5916 if (p->ino == EXT2_RESIZE_INO) {
5917 /*
5918 * The resize inode has already be sanity checked
5919 * during pass #0 (the superblock checks). All we
5920 * have to do is mark the double indirect block as
5921 * being in use; all of the other blocks are handled
5922 * by mark_table_blocks()).
5923 */
5924 if (blockcnt == BLOCK_COUNT_DIND)
5925 mark_block_used(ctx, blk);
5926 } else
5927 mark_block_used(ctx, blk);
5928 p->num_blocks++;
5929 if (blockcnt >= 0)
5930 p->last_block = blockcnt;
5931mark_dir:
5932 if (p->is_dir && (blockcnt >= 0)) {
5933 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
5934 blk, blockcnt);
5935 if (pctx->errcode) {
5936 pctx->blk = blk;
5937 pctx->num = blockcnt;
5938 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
5939 /* Should never get here */
5940 ctx->flags |= E2F_FLAG_ABORT;
5941 return BLOCK_ABORT;
5942 }
5943 }
5944 return ret_code;
5945}
5946
5947static int process_bad_block(ext2_filsys fs,
5948 blk_t *block_nr,
5949 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005950 blk_t ref_block FSCK_ATTR((unused)),
5951 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005952 void *priv_data)
5953{
5954 struct process_block_struct_1 *p;
5955 blk_t blk = *block_nr;
5956 blk_t first_block;
5957 dgrp_t i;
5958 struct problem_context *pctx;
5959 e2fsck_t ctx;
5960
5961 /*
5962 * Note: This function processes blocks for the bad blocks
5963 * inode, which is never compressed. So we don't use HOLE_BLKADDR().
5964 */
5965
5966 if (!blk)
5967 return 0;
5968
5969 p = (struct process_block_struct_1 *) priv_data;
5970 ctx = p->ctx;
5971 pctx = p->pctx;
5972
5973 pctx->ino = EXT2_BAD_INO;
5974 pctx->blk = blk;
5975 pctx->blkcount = blockcnt;
5976
5977 if ((blk < fs->super->s_first_data_block) ||
5978 (blk >= fs->super->s_blocks_count)) {
5979 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
5980 *block_nr = 0;
5981 return BLOCK_CHANGED;
5982 } else
5983 return 0;
5984 }
5985
5986 if (blockcnt < 0) {
5987 if (ext2fs_test_block_bitmap(p->fs_meta_blocks, blk)) {
5988 p->bbcheck = 1;
5989 if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) {
5990 *block_nr = 0;
5991 return BLOCK_CHANGED;
5992 }
5993 } else if (ext2fs_test_block_bitmap(ctx->block_found_map,
5994 blk)) {
5995 p->bbcheck = 1;
5996 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
5997 pctx)) {
5998 *block_nr = 0;
5999 return BLOCK_CHANGED;
6000 }
6001 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6002 return BLOCK_ABORT;
6003 } else
6004 mark_block_used(ctx, blk);
6005 return 0;
6006 }
6007#if 0
6008 printf ("DEBUG: Marking %u as bad.\n", blk);
6009#endif
6010 ctx->fs_badblocks_count++;
6011 /*
6012 * If the block is not used, then mark it as used and return.
6013 * If it is already marked as found, this must mean that
6014 * there's an overlap between the filesystem table blocks
6015 * (bitmaps and inode table) and the bad block list.
6016 */
6017 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
6018 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
6019 return 0;
6020 }
6021 /*
6022 * Try to find the where the filesystem block was used...
6023 */
6024 first_block = fs->super->s_first_data_block;
6025
6026 for (i = 0; i < fs->group_desc_count; i++ ) {
6027 pctx->group = i;
6028 pctx->blk = blk;
6029 if (!ext2fs_bg_has_super(fs, i))
6030 goto skip_super;
6031 if (blk == first_block) {
6032 if (i == 0) {
6033 if (fix_problem(ctx,
6034 PR_1_BAD_PRIMARY_SUPERBLOCK,
6035 pctx)) {
6036 *block_nr = 0;
6037 return BLOCK_CHANGED;
6038 }
6039 return 0;
6040 }
6041 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
6042 return 0;
6043 }
6044 if ((blk > first_block) &&
6045 (blk <= first_block + fs->desc_blocks)) {
6046 if (i == 0) {
6047 pctx->blk = *block_nr;
6048 if (fix_problem(ctx,
6049 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
6050 *block_nr = 0;
6051 return BLOCK_CHANGED;
6052 }
6053 return 0;
6054 }
6055 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
6056 return 0;
6057 }
6058 skip_super:
6059 if (blk == fs->group_desc[i].bg_block_bitmap) {
6060 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
6061 ctx->invalid_block_bitmap_flag[i]++;
6062 ctx->invalid_bitmaps++;
6063 }
6064 return 0;
6065 }
6066 if (blk == fs->group_desc[i].bg_inode_bitmap) {
6067 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
6068 ctx->invalid_inode_bitmap_flag[i]++;
6069 ctx->invalid_bitmaps++;
6070 }
6071 return 0;
6072 }
6073 if ((blk >= fs->group_desc[i].bg_inode_table) &&
6074 (blk < (fs->group_desc[i].bg_inode_table +
6075 fs->inode_blocks_per_group))) {
6076 /*
6077 * If there are bad blocks in the inode table,
6078 * the inode scan code will try to do
6079 * something reasonable automatically.
6080 */
6081 return 0;
6082 }
6083 first_block += fs->super->s_blocks_per_group;
6084 }
6085 /*
6086 * If we've gotten to this point, then the only
6087 * possibility is that the bad block inode meta data
6088 * is using a bad block.
6089 */
6090 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
6091 (blk == p->inode->i_block[EXT2_DIND_BLOCK]) ||
6092 (blk == p->inode->i_block[EXT2_TIND_BLOCK])) {
6093 p->bbcheck = 1;
6094 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) {
6095 *block_nr = 0;
6096 return BLOCK_CHANGED;
6097 }
6098 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6099 return BLOCK_ABORT;
6100 return 0;
6101 }
6102
6103 pctx->group = -1;
6104
6105 /* Warn user that the block wasn't claimed */
6106 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
6107
6108 return 0;
6109}
6110
6111static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
6112 const char *name, int num, blk_t *new_block)
6113{
6114 ext2_filsys fs = ctx->fs;
6115 blk_t old_block = *new_block;
6116 int i;
6117 char *buf;
6118 struct problem_context pctx;
6119
6120 clear_problem_context(&pctx);
6121
6122 pctx.group = group;
6123 pctx.blk = old_block;
6124 pctx.str = name;
6125
6126 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
6127 first_block + fs->super->s_blocks_per_group,
6128 num, ctx->block_found_map, new_block);
6129 if (pctx.errcode) {
6130 pctx.num = num;
6131 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
6132 ext2fs_unmark_valid(fs);
6133 return;
6134 }
6135 pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf);
6136 if (pctx.errcode) {
6137 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
6138 ext2fs_unmark_valid(fs);
6139 return;
6140 }
6141 ext2fs_mark_super_dirty(fs);
6142 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
6143 pctx.blk2 = *new_block;
6144 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
6145 PR_1_RELOC_TO), &pctx);
6146 pctx.blk2 = 0;
6147 for (i = 0; i < num; i++) {
6148 pctx.blk = i;
6149 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
6150 if (old_block) {
6151 pctx.errcode = io_channel_read_blk(fs->io,
6152 old_block + i, 1, buf);
6153 if (pctx.errcode)
6154 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
6155 } else
6156 memset(buf, 0, fs->blocksize);
6157
6158 pctx.blk = (*new_block) + i;
6159 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
6160 1, buf);
6161 if (pctx.errcode)
6162 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
6163 }
6164 ext2fs_free_mem(&buf);
6165}
6166
6167/*
6168 * This routine gets called at the end of pass 1 if bad blocks are
6169 * detected in the superblock, group descriptors, inode_bitmaps, or
6170 * block bitmaps. At this point, all of the blocks have been mapped
6171 * out, so we can try to allocate new block(s) to replace the bad
6172 * blocks.
6173 */
6174static void handle_fs_bad_blocks(e2fsck_t ctx)
6175{
6176 ext2_filsys fs = ctx->fs;
6177 dgrp_t i;
6178 int first_block = fs->super->s_first_data_block;
6179
6180 for (i = 0; i < fs->group_desc_count; i++) {
6181 if (ctx->invalid_block_bitmap_flag[i]) {
6182 new_table_block(ctx, first_block, i, _("block bitmap"),
6183 1, &fs->group_desc[i].bg_block_bitmap);
6184 }
6185 if (ctx->invalid_inode_bitmap_flag[i]) {
6186 new_table_block(ctx, first_block, i, _("inode bitmap"),
6187 1, &fs->group_desc[i].bg_inode_bitmap);
6188 }
6189 if (ctx->invalid_inode_table_flag[i]) {
6190 new_table_block(ctx, first_block, i, _("inode table"),
6191 fs->inode_blocks_per_group,
6192 &fs->group_desc[i].bg_inode_table);
6193 ctx->flags |= E2F_FLAG_RESTART;
6194 }
6195 first_block += fs->super->s_blocks_per_group;
6196 }
6197 ctx->invalid_bitmaps = 0;
6198}
6199
6200/*
6201 * This routine marks all blocks which are used by the superblock,
6202 * group descriptors, inode bitmaps, and block bitmaps.
6203 */
6204static void mark_table_blocks(e2fsck_t ctx)
6205{
6206 ext2_filsys fs = ctx->fs;
6207 blk_t block, b;
6208 dgrp_t i;
6209 int j;
6210 struct problem_context pctx;
6211
6212 clear_problem_context(&pctx);
6213
6214 block = fs->super->s_first_data_block;
6215 for (i = 0; i < fs->group_desc_count; i++) {
6216 pctx.group = i;
6217
6218 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
6219
6220 /*
6221 * Mark the blocks used for the inode table
6222 */
6223 if (fs->group_desc[i].bg_inode_table) {
6224 for (j = 0, b = fs->group_desc[i].bg_inode_table;
6225 j < fs->inode_blocks_per_group;
6226 j++, b++) {
6227 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6228 b)) {
6229 pctx.blk = b;
6230 if (fix_problem(ctx,
6231 PR_1_ITABLE_CONFLICT, &pctx)) {
6232 ctx->invalid_inode_table_flag[i]++;
6233 ctx->invalid_bitmaps++;
6234 }
6235 } else {
6236 ext2fs_mark_block_bitmap(ctx->block_found_map,
6237 b);
6238 }
6239 }
6240 }
6241
6242 /*
6243 * Mark block used for the block bitmap
6244 */
6245 if (fs->group_desc[i].bg_block_bitmap) {
6246 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6247 fs->group_desc[i].bg_block_bitmap)) {
6248 pctx.blk = fs->group_desc[i].bg_block_bitmap;
6249 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
6250 ctx->invalid_block_bitmap_flag[i]++;
6251 ctx->invalid_bitmaps++;
6252 }
6253 } else {
6254 ext2fs_mark_block_bitmap(ctx->block_found_map,
6255 fs->group_desc[i].bg_block_bitmap);
6256 }
6257
6258 }
6259 /*
6260 * Mark block used for the inode bitmap
6261 */
6262 if (fs->group_desc[i].bg_inode_bitmap) {
6263 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6264 fs->group_desc[i].bg_inode_bitmap)) {
6265 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
6266 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
6267 ctx->invalid_inode_bitmap_flag[i]++;
6268 ctx->invalid_bitmaps++;
6269 }
6270 } else {
6271 ext2fs_mark_block_bitmap(ctx->block_found_map,
6272 fs->group_desc[i].bg_inode_bitmap);
6273 }
6274 }
6275 block += fs->super->s_blocks_per_group;
6276 }
6277}
6278
6279/*
6280 * Thes subroutines short circuits ext2fs_get_blocks and
6281 * ext2fs_check_directory; we use them since we already have the inode
6282 * structure, so there's no point in letting the ext2fs library read
6283 * the inode again.
6284 */
6285static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
6286 blk_t *blocks)
6287{
6288 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6289 int i;
6290
6291 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6292 return EXT2_ET_CALLBACK_NOTHANDLED;
6293
6294 for (i=0; i < EXT2_N_BLOCKS; i++)
6295 blocks[i] = ctx->stashed_inode->i_block[i];
6296 return 0;
6297}
6298
6299static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
6300 struct ext2_inode *inode)
6301{
6302 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6303
6304 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6305 return EXT2_ET_CALLBACK_NOTHANDLED;
6306 *inode = *ctx->stashed_inode;
6307 return 0;
6308}
6309
6310static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
6311 struct ext2_inode *inode)
6312{
6313 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6314
6315 if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
6316 *ctx->stashed_inode = *inode;
6317 return EXT2_ET_CALLBACK_NOTHANDLED;
6318}
6319
6320static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
6321{
6322 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6323
6324 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6325 return EXT2_ET_CALLBACK_NOTHANDLED;
6326
6327 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
6328 return EXT2_ET_NO_DIRECTORY;
6329 return 0;
6330}
6331
6332void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
6333{
6334 ext2_filsys fs = ctx->fs;
6335
6336 if (bool) {
6337 fs->get_blocks = pass1_get_blocks;
6338 fs->check_directory = pass1_check_directory;
6339 fs->read_inode = pass1_read_inode;
6340 fs->write_inode = pass1_write_inode;
6341 ctx->stashed_ino = 0;
6342 } else {
6343 fs->get_blocks = 0;
6344 fs->check_directory = 0;
6345 fs->read_inode = 0;
6346 fs->write_inode = 0;
6347 }
6348}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006349
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006350/*
6351 * pass1b.c --- Pass #1b of e2fsck
6352 *
6353 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
6354 * only invoked if pass 1 discovered blocks which are in use by more
6355 * than one inode.
6356 *
6357 * Pass1B scans the data blocks of all the inodes again, generating a
6358 * complete list of duplicate blocks and which inodes have claimed
6359 * them.
6360 *
6361 * Pass1C does a tree-traversal of the filesystem, to determine the
6362 * parent directories of these inodes. This step is necessary so that
6363 * e2fsck can print out the pathnames of affected inodes.
6364 *
6365 * Pass1D is a reconciliation pass. For each inode with duplicate
6366 * blocks, the user is prompted if s/he would like to clone the file
6367 * (so that the file gets a fresh copy of the duplicated blocks) or
6368 * simply to delete the file.
6369 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006370 */
6371
6372
6373/* Needed for architectures where sizeof(int) != sizeof(void *) */
6374#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
6375#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
6376
6377/* Define an extension to the ext2 library's block count information */
6378#define BLOCK_COUNT_EXTATTR (-5)
6379
6380struct block_el {
6381 blk_t block;
6382 struct block_el *next;
6383};
6384
6385struct inode_el {
6386 ext2_ino_t inode;
6387 struct inode_el *next;
6388};
6389
6390struct dup_block {
6391 int num_bad;
6392 struct inode_el *inode_list;
6393};
6394
6395/*
6396 * This structure stores information about a particular inode which
6397 * is sharing blocks with other inodes. This information is collected
6398 * to display to the user, so that the user knows what files he or she
6399 * is dealing with, when trying to decide how to resolve the conflict
6400 * of multiply-claimed blocks.
6401 */
6402struct dup_inode {
6403 ext2_ino_t dir;
6404 int num_dupblocks;
6405 struct ext2_inode inode;
6406 struct block_el *block_list;
6407};
6408
6409static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
6410 e2_blkcnt_t blockcnt, blk_t ref_blk,
6411 int ref_offset, void *priv_data);
6412static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
6413 struct dup_inode *dp, char *block_buf);
6414static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
6415 struct dup_inode *dp, char* block_buf);
6416static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
6417
6418static void pass1b(e2fsck_t ctx, char *block_buf);
6419static void pass1c(e2fsck_t ctx, char *block_buf);
6420static void pass1d(e2fsck_t ctx, char *block_buf);
6421
6422static int dup_inode_count = 0;
6423
6424static dict_t blk_dict, ino_dict;
6425
6426static ext2fs_inode_bitmap inode_dup_map;
6427
6428static int dict_int_cmp(const void *a, const void *b)
6429{
6430 intptr_t ia, ib;
6431
6432 ia = (intptr_t)a;
6433 ib = (intptr_t)b;
6434
6435 return (ia-ib);
6436}
6437
6438/*
6439 * Add a duplicate block record
6440 */
6441static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
6442 struct ext2_inode *inode)
6443{
6444 dnode_t *n;
6445 struct dup_block *db;
6446 struct dup_inode *di;
6447 struct block_el *blk_el;
6448 struct inode_el *ino_el;
6449
6450 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
6451 if (n)
6452 db = (struct dup_block *) dnode_get(n);
6453 else {
6454 db = (struct dup_block *) e2fsck_allocate_memory(ctx,
6455 sizeof(struct dup_block), "duplicate block header");
6456 db->num_bad = 0;
6457 db->inode_list = 0;
6458 dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
6459 }
6460 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
6461 sizeof(struct inode_el), "inode element");
6462 ino_el->inode = ino;
6463 ino_el->next = db->inode_list;
6464 db->inode_list = ino_el;
6465 db->num_bad++;
6466
6467 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
6468 if (n)
6469 di = (struct dup_inode *) dnode_get(n);
6470 else {
6471 di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
6472 sizeof(struct dup_inode), "duplicate inode header");
6473 di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0 ;
6474 di->num_dupblocks = 0;
6475 di->block_list = 0;
6476 di->inode = *inode;
6477 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
6478 }
6479 blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
6480 sizeof(struct block_el), "block element");
6481 blk_el->block = blk;
6482 blk_el->next = di->block_list;
6483 di->block_list = blk_el;
6484 di->num_dupblocks++;
6485}
6486
6487/*
6488 * Free a duplicate inode record
6489 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006490static void inode_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006491{
6492 struct dup_inode *di;
6493 struct block_el *p, *next;
6494
6495 di = (struct dup_inode *) dnode_get(node);
6496 for (p = di->block_list; p; p = next) {
6497 next = p->next;
6498 free(p);
6499 }
6500 free(node);
6501}
6502
6503/*
6504 * Free a duplicate block record
6505 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006506static void block_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006507{
6508 struct dup_block *db;
6509 struct inode_el *p, *next;
6510
6511 db = (struct dup_block *) dnode_get(node);
6512 for (p = db->inode_list; p; p = next) {
6513 next = p->next;
6514 free(p);
6515 }
6516 free(node);
6517}
6518
6519
6520/*
6521 * Main procedure for handling duplicate blocks
6522 */
6523void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
6524{
6525 ext2_filsys fs = ctx->fs;
6526 struct problem_context pctx;
6527
6528 clear_problem_context(&pctx);
6529
6530 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
6531 _("multiply claimed inode map"), &inode_dup_map);
6532 if (pctx.errcode) {
6533 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
6534 ctx->flags |= E2F_FLAG_ABORT;
6535 return;
6536 }
6537
6538 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
6539 dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006540 dict_set_allocator(&ino_dict, inode_dnode_free);
6541 dict_set_allocator(&blk_dict, block_dnode_free);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006542
6543 pass1b(ctx, block_buf);
6544 pass1c(ctx, block_buf);
6545 pass1d(ctx, block_buf);
6546
6547 /*
6548 * Time to free all of the accumulated data structures that we
6549 * don't need anymore.
6550 */
6551 dict_free_nodes(&ino_dict);
6552 dict_free_nodes(&blk_dict);
6553}
6554
6555/*
6556 * Scan the inodes looking for inodes that contain duplicate blocks.
6557 */
6558struct process_block_struct_1b {
6559 e2fsck_t ctx;
6560 ext2_ino_t ino;
6561 int dup_blocks;
6562 struct ext2_inode *inode;
6563 struct problem_context *pctx;
6564};
6565
6566static void pass1b(e2fsck_t ctx, char *block_buf)
6567{
6568 ext2_filsys fs = ctx->fs;
6569 ext2_ino_t ino;
6570 struct ext2_inode inode;
6571 ext2_inode_scan scan;
6572 struct process_block_struct_1b pb;
6573 struct problem_context pctx;
6574
6575 clear_problem_context(&pctx);
6576
6577 if (!(ctx->options & E2F_OPT_PREEN))
6578 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
6579 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
6580 &scan);
6581 if (pctx.errcode) {
6582 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6583 ctx->flags |= E2F_FLAG_ABORT;
6584 return;
6585 }
6586 ctx->stashed_inode = &inode;
6587 pb.ctx = ctx;
6588 pb.pctx = &pctx;
6589 pctx.str = "pass1b";
6590 while (1) {
6591 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
6592 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
6593 continue;
6594 if (pctx.errcode) {
6595 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6596 ctx->flags |= E2F_FLAG_ABORT;
6597 return;
6598 }
6599 if (!ino)
6600 break;
6601 pctx.ino = ctx->stashed_ino = ino;
6602 if ((ino != EXT2_BAD_INO) &&
6603 !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
6604 continue;
6605
6606 pb.ino = ino;
6607 pb.dup_blocks = 0;
6608 pb.inode = &inode;
6609
6610 if (ext2fs_inode_has_valid_blocks(&inode) ||
6611 (ino == EXT2_BAD_INO))
6612 pctx.errcode = ext2fs_block_iterate2(fs, ino,
6613 0, block_buf, process_pass1b_block, &pb);
6614 if (inode.i_file_acl)
6615 process_pass1b_block(fs, &inode.i_file_acl,
6616 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
6617 if (pb.dup_blocks) {
6618 end_problem_latch(ctx, PR_LATCH_DBLOCK);
6619 if (ino >= EXT2_FIRST_INODE(fs->super) ||
6620 ino == EXT2_ROOT_INO)
6621 dup_inode_count++;
6622 }
6623 if (pctx.errcode)
6624 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
6625 }
6626 ext2fs_close_inode_scan(scan);
6627 e2fsck_use_inode_shortcuts(ctx, 0);
6628}
6629
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006630static int process_pass1b_block(ext2_filsys fs FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006631 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006632 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
6633 blk_t ref_blk FSCK_ATTR((unused)),
6634 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006635 void *priv_data)
6636{
6637 struct process_block_struct_1b *p;
6638 e2fsck_t ctx;
6639
6640 if (HOLE_BLKADDR(*block_nr))
6641 return 0;
6642 p = (struct process_block_struct_1b *) priv_data;
6643 ctx = p->ctx;
6644
6645 if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
6646 return 0;
6647
6648 /* OK, this is a duplicate block */
6649 if (p->ino != EXT2_BAD_INO) {
6650 p->pctx->blk = *block_nr;
6651 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
6652 }
6653 p->dup_blocks++;
6654 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
6655
6656 add_dupe(ctx, p->ino, *block_nr, p->inode);
6657
6658 return 0;
6659}
6660
6661/*
6662 * Pass 1c: Scan directories for inodes with duplicate blocks. This
6663 * is used so that we can print pathnames when prompting the user for
6664 * what to do.
6665 */
6666struct search_dir_struct {
6667 int count;
6668 ext2_ino_t first_inode;
6669 ext2_ino_t max_inode;
6670};
6671
6672static int search_dirent_proc(ext2_ino_t dir, int entry,
6673 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006674 int offset FSCK_ATTR((unused)),
6675 int blocksize FSCK_ATTR((unused)),
6676 char *buf FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006677 void *priv_data)
6678{
6679 struct search_dir_struct *sd;
6680 struct dup_inode *p;
6681 dnode_t *n;
6682
6683 sd = (struct search_dir_struct *) priv_data;
6684
6685 if (dirent->inode > sd->max_inode)
6686 /* Should abort this inode, but not everything */
6687 return 0;
6688
6689 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
6690 !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
6691 return 0;
6692
6693 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
6694 if (!n)
6695 return 0;
6696 p = (struct dup_inode *) dnode_get(n);
6697 p->dir = dir;
6698 sd->count--;
6699
6700 return(sd->count ? 0 : DIRENT_ABORT);
6701}
6702
6703
6704static void pass1c(e2fsck_t ctx, char *block_buf)
6705{
6706 ext2_filsys fs = ctx->fs;
6707 struct search_dir_struct sd;
6708 struct problem_context pctx;
6709
6710 clear_problem_context(&pctx);
6711
6712 if (!(ctx->options & E2F_OPT_PREEN))
6713 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
6714
6715 /*
6716 * Search through all directories to translate inodes to names
6717 * (by searching for the containing directory for that inode.)
6718 */
6719 sd.count = dup_inode_count;
6720 sd.first_inode = EXT2_FIRST_INODE(fs->super);
6721 sd.max_inode = fs->super->s_inodes_count;
6722 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
6723 search_dirent_proc, &sd);
6724}
6725
6726static void pass1d(e2fsck_t ctx, char *block_buf)
6727{
6728 ext2_filsys fs = ctx->fs;
6729 struct dup_inode *p, *t;
6730 struct dup_block *q;
6731 ext2_ino_t *shared, ino;
6732 int shared_len;
6733 int i;
6734 int file_ok;
6735 int meta_data = 0;
6736 struct problem_context pctx;
6737 dnode_t *n, *m;
6738 struct block_el *s;
6739 struct inode_el *r;
6740
6741 clear_problem_context(&pctx);
6742
6743 if (!(ctx->options & E2F_OPT_PREEN))
6744 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
6745 e2fsck_read_bitmaps(ctx);
6746
6747 pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
6748 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
6749 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
6750 sizeof(ext2_ino_t) * dict_count(&ino_dict),
6751 "Shared inode list");
6752 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
6753 p = (struct dup_inode *) dnode_get(n);
6754 shared_len = 0;
6755 file_ok = 1;
6756 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
6757 if (ino == EXT2_BAD_INO)
6758 continue;
6759
6760 /*
6761 * Find all of the inodes which share blocks with this
6762 * one. First we find all of the duplicate blocks
6763 * belonging to this inode, and then search each block
6764 * get the list of inodes, and merge them together.
6765 */
6766 for (s = p->block_list; s; s = s->next) {
6767 m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
6768 if (!m)
6769 continue; /* Should never happen... */
6770 q = (struct dup_block *) dnode_get(m);
6771 if (q->num_bad > 1)
6772 file_ok = 0;
6773 if (check_if_fs_block(ctx, s->block)) {
6774 file_ok = 0;
6775 meta_data = 1;
6776 }
6777
6778 /*
6779 * Add all inodes used by this block to the
6780 * shared[] --- which is a unique list, so
6781 * if an inode is already in shared[], don't
6782 * add it again.
6783 */
6784 for (r = q->inode_list; r; r = r->next) {
6785 if (r->inode == ino)
6786 continue;
6787 for (i = 0; i < shared_len; i++)
6788 if (shared[i] == r->inode)
6789 break;
6790 if (i == shared_len) {
6791 shared[shared_len++] = r->inode;
6792 }
6793 }
6794 }
6795
6796 /*
6797 * Report the inode that we are working on
6798 */
6799 pctx.inode = &p->inode;
6800 pctx.ino = ino;
6801 pctx.dir = p->dir;
6802 pctx.blkcount = p->num_dupblocks;
6803 pctx.num = meta_data ? shared_len+1 : shared_len;
6804 fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
6805 pctx.blkcount = 0;
6806 pctx.num = 0;
6807
6808 if (meta_data)
6809 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
6810
6811 for (i = 0; i < shared_len; i++) {
6812 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
6813 if (!m)
6814 continue; /* should never happen */
6815 t = (struct dup_inode *) dnode_get(m);
6816 /*
6817 * Report the inode that we are sharing with
6818 */
6819 pctx.inode = &t->inode;
6820 pctx.ino = shared[i];
6821 pctx.dir = t->dir;
6822 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
6823 }
6824 if (file_ok) {
6825 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
6826 continue;
6827 }
6828 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
6829 pctx.errcode = clone_file(ctx, ino, p, block_buf);
6830 if (pctx.errcode)
6831 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
6832 else
6833 continue;
6834 }
6835 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
6836 delete_file(ctx, ino, p, block_buf);
6837 else
6838 ext2fs_unmark_valid(fs);
6839 }
6840 ext2fs_free_mem(&shared);
6841}
6842
6843/*
6844 * Drop the refcount on the dup_block structure, and clear the entry
6845 * in the block_dup_map if appropriate.
6846 */
6847static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
6848{
6849 p->num_bad--;
6850 if (p->num_bad <= 0 ||
6851 (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
6852 ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
6853}
6854
6855static int delete_file_block(ext2_filsys fs,
6856 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006857 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
6858 blk_t ref_block FSCK_ATTR((unused)),
6859 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006860 void *priv_data)
6861{
6862 struct process_block_struct_1b *pb;
6863 struct dup_block *p;
6864 dnode_t *n;
6865 e2fsck_t ctx;
6866
6867 pb = (struct process_block_struct_1b *) priv_data;
6868 ctx = pb->ctx;
6869
6870 if (HOLE_BLKADDR(*block_nr))
6871 return 0;
6872
6873 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
6874 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
6875 if (n) {
6876 p = (struct dup_block *) dnode_get(n);
6877 decrement_badcount(ctx, *block_nr, p);
6878 } else
6879 com_err("delete_file_block", 0,
6880 _("internal error; can't find dup_blk for %d\n"),
6881 *block_nr);
6882 } else {
6883 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
6884 ext2fs_block_alloc_stats(fs, *block_nr, -1);
6885 }
6886
6887 return 0;
6888}
6889
6890static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
6891 struct dup_inode *dp, char* block_buf)
6892{
6893 ext2_filsys fs = ctx->fs;
6894 struct process_block_struct_1b pb;
6895 struct ext2_inode inode;
6896 struct problem_context pctx;
6897 unsigned int count;
6898
6899 clear_problem_context(&pctx);
6900 pctx.ino = pb.ino = ino;
6901 pb.dup_blocks = dp->num_dupblocks;
6902 pb.ctx = ctx;
6903 pctx.str = "delete_file";
6904
6905 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
6906 if (ext2fs_inode_has_valid_blocks(&inode))
6907 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
6908 delete_file_block, &pb);
6909 if (pctx.errcode)
6910 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
6911 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
6912 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
6913 if (ctx->inode_bad_map)
6914 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
6915 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
6916
6917 /* Inode may have changed by block_iterate, so reread it */
6918 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
6919 inode.i_links_count = 0;
6920 inode.i_dtime = time(0);
6921 if (inode.i_file_acl &&
6922 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
6923 count = 1;
6924 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
6925 block_buf, -1, &count);
6926 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
6927 pctx.errcode = 0;
6928 count = 1;
6929 }
6930 if (pctx.errcode) {
6931 pctx.blk = inode.i_file_acl;
6932 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
6933 }
6934 /*
6935 * If the count is zero, then arrange to have the
6936 * block deleted. If the block is in the block_dup_map,
6937 * also call delete_file_block since it will take care
6938 * of keeping the accounting straight.
6939 */
6940 if ((count == 0) ||
6941 ext2fs_test_block_bitmap(ctx->block_dup_map,
6942 inode.i_file_acl))
6943 delete_file_block(fs, &inode.i_file_acl,
6944 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
6945 }
6946 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
6947}
6948
6949struct clone_struct {
6950 errcode_t errcode;
6951 ext2_ino_t dir;
6952 char *buf;
6953 e2fsck_t ctx;
6954};
6955
6956static int clone_file_block(ext2_filsys fs,
6957 blk_t *block_nr,
6958 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006959 blk_t ref_block FSCK_ATTR((unused)),
6960 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006961 void *priv_data)
6962{
6963 struct dup_block *p;
6964 blk_t new_block;
6965 errcode_t retval;
6966 struct clone_struct *cs = (struct clone_struct *) priv_data;
6967 dnode_t *n;
6968 e2fsck_t ctx;
6969
6970 ctx = cs->ctx;
6971
6972 if (HOLE_BLKADDR(*block_nr))
6973 return 0;
6974
6975 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
6976 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
6977 if (n) {
6978 p = (struct dup_block *) dnode_get(n);
6979 retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
6980 &new_block);
6981 if (retval) {
6982 cs->errcode = retval;
6983 return BLOCK_ABORT;
6984 }
6985 if (cs->dir && (blockcnt >= 0)) {
6986 retval = ext2fs_set_dir_block(fs->dblist,
6987 cs->dir, new_block, blockcnt);
6988 if (retval) {
6989 cs->errcode = retval;
6990 return BLOCK_ABORT;
6991 }
6992 }
6993#if 0
6994 printf("Cloning block %u to %u\n", *block_nr,
6995 new_block);
6996#endif
6997 retval = io_channel_read_blk(fs->io, *block_nr, 1,
6998 cs->buf);
6999 if (retval) {
7000 cs->errcode = retval;
7001 return BLOCK_ABORT;
7002 }
7003 retval = io_channel_write_blk(fs->io, new_block, 1,
7004 cs->buf);
7005 if (retval) {
7006 cs->errcode = retval;
7007 return BLOCK_ABORT;
7008 }
7009 decrement_badcount(ctx, *block_nr, p);
7010 *block_nr = new_block;
7011 ext2fs_mark_block_bitmap(ctx->block_found_map,
7012 new_block);
7013 ext2fs_mark_block_bitmap(fs->block_map, new_block);
7014 return BLOCK_CHANGED;
7015 } else
7016 com_err("clone_file_block", 0,
7017 _("internal error; can't find dup_blk for %d\n"),
7018 *block_nr);
7019 }
7020 return 0;
7021}
7022
7023static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
7024 struct dup_inode *dp, char* block_buf)
7025{
7026 ext2_filsys fs = ctx->fs;
7027 errcode_t retval;
7028 struct clone_struct cs;
7029 struct problem_context pctx;
7030 blk_t blk;
7031 dnode_t *n;
7032 struct inode_el *ino_el;
7033 struct dup_block *db;
7034 struct dup_inode *di;
7035
7036 clear_problem_context(&pctx);
7037 cs.errcode = 0;
7038 cs.dir = 0;
7039 cs.ctx = ctx;
7040 retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
7041 if (retval)
7042 return retval;
7043
7044 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
7045 cs.dir = ino;
7046
7047 pctx.ino = ino;
7048 pctx.str = "clone_file";
7049 if (ext2fs_inode_has_valid_blocks(&dp->inode))
7050 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
7051 clone_file_block, &cs);
7052 ext2fs_mark_bb_dirty(fs);
7053 if (pctx.errcode) {
7054 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
7055 retval = pctx.errcode;
7056 goto errout;
7057 }
7058 if (cs.errcode) {
7059 com_err("clone_file", cs.errcode,
7060 _("returned from clone_file_block"));
7061 retval = cs.errcode;
7062 goto errout;
7063 }
7064 /* The inode may have changed on disk, so we have to re-read it */
7065 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
7066 blk = dp->inode.i_file_acl;
7067 if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
7068 BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
7069 BLOCK_CHANGED)) {
7070 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
7071 /*
7072 * If we cloned the EA block, find all other inodes
7073 * which refered to that EA block, and modify
7074 * them to point to the new EA block.
7075 */
7076 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
7077 db = (struct dup_block *) dnode_get(n);
7078 for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
7079 if (ino_el->inode == ino)
7080 continue;
7081 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
7082 di = (struct dup_inode *) dnode_get(n);
7083 if (di->inode.i_file_acl == blk) {
7084 di->inode.i_file_acl = dp->inode.i_file_acl;
7085 e2fsck_write_inode(ctx, ino_el->inode,
7086 &di->inode, "clone file EA");
7087 decrement_badcount(ctx, blk, db);
7088 }
7089 }
7090 }
7091 retval = 0;
7092errout:
7093 ext2fs_free_mem(&cs.buf);
7094 return retval;
7095}
7096
7097/*
7098 * This routine returns 1 if a block overlaps with one of the superblocks,
7099 * group descriptors, inode bitmaps, or block bitmaps.
7100 */
7101static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
7102{
7103 ext2_filsys fs = ctx->fs;
7104 blk_t block;
7105 dgrp_t i;
7106
7107 block = fs->super->s_first_data_block;
7108 for (i = 0; i < fs->group_desc_count; i++) {
7109
7110 /* Check superblocks/block group descriptros */
7111 if (ext2fs_bg_has_super(fs, i)) {
7112 if (test_block >= block &&
7113 (test_block <= block + fs->desc_blocks))
7114 return 1;
7115 }
7116
7117 /* Check the inode table */
7118 if ((fs->group_desc[i].bg_inode_table) &&
7119 (test_block >= fs->group_desc[i].bg_inode_table) &&
7120 (test_block < (fs->group_desc[i].bg_inode_table +
7121 fs->inode_blocks_per_group)))
7122 return 1;
7123
7124 /* Check the bitmap blocks */
7125 if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
7126 (test_block == fs->group_desc[i].bg_inode_bitmap))
7127 return 1;
7128
7129 block += fs->super->s_blocks_per_group;
7130 }
7131 return 0;
7132}
7133/*
7134 * pass2.c --- check directory structure
7135 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007136 * Pass 2 of e2fsck iterates through all active directory inodes, and
7137 * applies to following tests to each directory entry in the directory
7138 * blocks in the inodes:
7139 *
7140 * - The length of the directory entry (rec_len) should be at
7141 * least 8 bytes, and no more than the remaining space
7142 * left in the directory block.
7143 * - The length of the name in the directory entry (name_len)
7144 * should be less than (rec_len - 8).
7145 * - The inode number in the directory entry should be within
7146 * legal bounds.
7147 * - The inode number should refer to a in-use inode.
7148 * - The first entry should be '.', and its inode should be
7149 * the inode of the directory.
7150 * - The second entry should be '..'.
7151 *
7152 * To minimize disk seek time, the directory blocks are processed in
7153 * sorted order of block numbers.
7154 *
7155 * Pass 2 also collects the following information:
7156 * - The inode numbers of the subdirectories for each directory.
7157 *
7158 * Pass 2 relies on the following information from previous passes:
7159 * - The directory information collected in pass 1.
7160 * - The inode_used_map bitmap
7161 * - The inode_bad_map bitmap
7162 * - The inode_dir_map bitmap
7163 *
7164 * Pass 2 frees the following data structures
7165 * - The inode_bad_map bitmap
7166 * - The inode_reg_map bitmap
7167 */
7168
7169/* #define DX_DEBUG */
7170
7171/*
7172 * Keeps track of how many times an inode is referenced.
7173 */
7174static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
7175static int check_dir_block(ext2_filsys fs,
7176 struct ext2_db_entry *dir_blocks_info,
7177 void *priv_data);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007178static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info,
7179 struct problem_context *pctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007180static int update_dir_block(ext2_filsys fs,
7181 blk_t *block_nr,
7182 e2_blkcnt_t blockcnt,
7183 blk_t ref_block,
7184 int ref_offset,
7185 void *priv_data);
7186static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
7187static int htree_depth(struct dx_dir_info *dx_dir,
7188 struct dx_dirblock_info *dx_db);
7189static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
7190
7191struct check_dir_struct {
7192 char *buf;
7193 struct problem_context pctx;
7194 int count, max;
7195 e2fsck_t ctx;
7196};
7197
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007198static void e2fsck_pass2(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007199{
7200 struct ext2_super_block *sb = ctx->fs->super;
7201 struct problem_context pctx;
7202 ext2_filsys fs = ctx->fs;
7203 char *buf;
7204#ifdef RESOURCE_TRACK
7205 struct resource_track rtrack;
7206#endif
7207 struct dir_info *dir;
7208 struct check_dir_struct cd;
7209 struct dx_dir_info *dx_dir;
7210 struct dx_dirblock_info *dx_db, *dx_parent;
7211 int b;
7212 int i, depth;
7213 problem_t code;
7214 int bad_dir;
7215
7216#ifdef RESOURCE_TRACK
7217 init_resource_track(&rtrack);
7218#endif
7219
7220 clear_problem_context(&cd.pctx);
7221
7222#ifdef MTRACE
7223 mtrace_print("Pass 2");
7224#endif
7225
7226 if (!(ctx->options & E2F_OPT_PREEN))
7227 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
7228
7229 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
7230 0, ctx->inode_link_info,
7231 &ctx->inode_count);
7232 if (cd.pctx.errcode) {
7233 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
7234 ctx->flags |= E2F_FLAG_ABORT;
7235 return;
7236 }
7237 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
7238 "directory scan buffer");
7239
7240 /*
7241 * Set up the parent pointer for the root directory, if
7242 * present. (If the root directory is not present, we will
7243 * create it in pass 3.)
7244 */
7245 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
7246 if (dir)
7247 dir->parent = EXT2_ROOT_INO;
7248
7249 cd.buf = buf;
7250 cd.ctx = ctx;
7251 cd.count = 1;
7252 cd.max = ext2fs_dblist_count(fs->dblist);
7253
7254 if (ctx->progress)
7255 (void) (ctx->progress)(ctx, 2, 0, cd.max);
7256
7257 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
7258 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
7259
7260 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
7261 &cd);
7262 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7263 return;
7264 if (cd.pctx.errcode) {
7265 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
7266 ctx->flags |= E2F_FLAG_ABORT;
7267 return;
7268 }
7269
7270#ifdef ENABLE_HTREE
7271 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
7272 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7273 return;
7274 if (dx_dir->numblocks == 0)
7275 continue;
7276 clear_problem_context(&pctx);
7277 bad_dir = 0;
7278 pctx.dir = dx_dir->ino;
7279 dx_db = dx_dir->dx_block;
7280 if (dx_db->flags & DX_FLAG_REFERENCED)
7281 dx_db->flags |= DX_FLAG_DUP_REF;
7282 else
7283 dx_db->flags |= DX_FLAG_REFERENCED;
7284 /*
7285 * Find all of the first and last leaf blocks, and
7286 * update their parent's min and max hash values
7287 */
7288 for (b=0, dx_db = dx_dir->dx_block;
7289 b < dx_dir->numblocks;
7290 b++, dx_db++) {
7291 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
7292 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
7293 continue;
7294 dx_parent = &dx_dir->dx_block[dx_db->parent];
7295 /*
7296 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
7297 */
7298 if (dx_db->flags & DX_FLAG_FIRST)
7299 dx_parent->min_hash = dx_db->min_hash;
7300 /*
7301 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
7302 */
7303 if (dx_db->flags & DX_FLAG_LAST)
7304 dx_parent->max_hash = dx_db->max_hash;
7305 }
7306
7307 for (b=0, dx_db = dx_dir->dx_block;
7308 b < dx_dir->numblocks;
7309 b++, dx_db++) {
7310 pctx.blkcount = b;
7311 pctx.group = dx_db->parent;
7312 code = 0;
7313 if (!(dx_db->flags & DX_FLAG_FIRST) &&
7314 (dx_db->min_hash < dx_db->node_min_hash)) {
7315 pctx.blk = dx_db->min_hash;
7316 pctx.blk2 = dx_db->node_min_hash;
7317 code = PR_2_HTREE_MIN_HASH;
7318 fix_problem(ctx, code, &pctx);
7319 bad_dir++;
7320 }
7321 if (dx_db->type == DX_DIRBLOCK_LEAF) {
7322 depth = htree_depth(dx_dir, dx_db);
7323 if (depth != dx_dir->depth) {
7324 code = PR_2_HTREE_BAD_DEPTH;
7325 fix_problem(ctx, code, &pctx);
7326 bad_dir++;
7327 }
7328 }
7329 /*
7330 * This test doesn't apply for the root block
7331 * at block #0
7332 */
7333 if (b &&
7334 (dx_db->max_hash > dx_db->node_max_hash)) {
7335 pctx.blk = dx_db->max_hash;
7336 pctx.blk2 = dx_db->node_max_hash;
7337 code = PR_2_HTREE_MAX_HASH;
7338 fix_problem(ctx, code, &pctx);
7339 bad_dir++;
7340 }
7341 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
7342 code = PR_2_HTREE_NOTREF;
7343 fix_problem(ctx, code, &pctx);
7344 bad_dir++;
7345 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
7346 code = PR_2_HTREE_DUPREF;
7347 fix_problem(ctx, code, &pctx);
7348 bad_dir++;
7349 }
7350 if (code == 0)
7351 continue;
7352 }
7353 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
7354 clear_htree(ctx, dx_dir->ino);
7355 dx_dir->numblocks = 0;
7356 }
7357 }
7358#endif
7359 ext2fs_free_mem(&buf);
7360 ext2fs_free_dblist(fs->dblist);
7361
7362 if (ctx->inode_bad_map) {
7363 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
7364 ctx->inode_bad_map = 0;
7365 }
7366 if (ctx->inode_reg_map) {
7367 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
7368 ctx->inode_reg_map = 0;
7369 }
7370
7371 clear_problem_context(&pctx);
7372 if (ctx->large_files) {
7373 if (!(sb->s_feature_ro_compat &
7374 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
7375 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
7376 sb->s_feature_ro_compat |=
7377 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7378 ext2fs_mark_super_dirty(fs);
7379 }
7380 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
7381 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
7382 ext2fs_update_dynamic_rev(fs);
7383 ext2fs_mark_super_dirty(fs);
7384 }
7385 } else if (!ctx->large_files &&
7386 (sb->s_feature_ro_compat &
7387 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
7388 if (fs->flags & EXT2_FLAG_RW) {
7389 sb->s_feature_ro_compat &=
7390 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7391 ext2fs_mark_super_dirty(fs);
7392 }
7393 }
7394
7395#ifdef RESOURCE_TRACK
7396 if (ctx->options & E2F_OPT_TIME2) {
7397 e2fsck_clear_progbar(ctx);
7398 print_resource_track(_("Pass 2"), &rtrack);
7399 }
7400#endif
7401}
7402
7403#define MAX_DEPTH 32000
7404static int htree_depth(struct dx_dir_info *dx_dir,
7405 struct dx_dirblock_info *dx_db)
7406{
7407 int depth = 0;
7408
7409 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
7410 dx_db = &dx_dir->dx_block[dx_db->parent];
7411 depth++;
7412 }
7413 return depth;
7414}
7415
7416static int dict_de_cmp(const void *a, const void *b)
7417{
7418 const struct ext2_dir_entry *de_a, *de_b;
7419 int a_len, b_len;
7420
7421 de_a = (const struct ext2_dir_entry *) a;
7422 a_len = de_a->name_len & 0xFF;
7423 de_b = (const struct ext2_dir_entry *) b;
7424 b_len = de_b->name_len & 0xFF;
7425
7426 if (a_len != b_len)
7427 return (a_len - b_len);
7428
7429 return strncmp(de_a->name, de_b->name, a_len);
7430}
7431
7432/*
7433 * This is special sort function that makes sure that directory blocks
7434 * with a dirblock of zero are sorted to the beginning of the list.
7435 * This guarantees that the root node of the htree directories are
7436 * processed first, so we know what hash version to use.
7437 */
7438static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
7439{
7440 const struct ext2_db_entry *db_a =
7441 (const struct ext2_db_entry *) a;
7442 const struct ext2_db_entry *db_b =
7443 (const struct ext2_db_entry *) b;
7444
7445 if (db_a->blockcnt && !db_b->blockcnt)
7446 return 1;
7447
7448 if (!db_a->blockcnt && db_b->blockcnt)
7449 return -1;
7450
7451 if (db_a->blk != db_b->blk)
7452 return (int) (db_a->blk - db_b->blk);
7453
7454 if (db_a->ino != db_b->ino)
7455 return (int) (db_a->ino - db_b->ino);
7456
7457 return (int) (db_a->blockcnt - db_b->blockcnt);
7458}
7459
7460
7461/*
7462 * Make sure the first entry in the directory is '.', and that the
7463 * directory entry is sane.
7464 */
7465static int check_dot(e2fsck_t ctx,
7466 struct ext2_dir_entry *dirent,
7467 ext2_ino_t ino, struct problem_context *pctx)
7468{
7469 struct ext2_dir_entry *nextdir;
7470 int status = 0;
7471 int created = 0;
7472 int new_len;
7473 int problem = 0;
7474
7475 if (!dirent->inode)
7476 problem = PR_2_MISSING_DOT;
7477 else if (((dirent->name_len & 0xFF) != 1) ||
7478 (dirent->name[0] != '.'))
7479 problem = PR_2_1ST_NOT_DOT;
7480 else if (dirent->name[1] != '\0')
7481 problem = PR_2_DOT_NULL_TERM;
7482
7483 if (problem) {
7484 if (fix_problem(ctx, problem, pctx)) {
7485 if (dirent->rec_len < 12)
7486 dirent->rec_len = 12;
7487 dirent->inode = ino;
7488 dirent->name_len = 1;
7489 dirent->name[0] = '.';
7490 dirent->name[1] = '\0';
7491 status = 1;
7492 created = 1;
7493 }
7494 }
7495 if (dirent->inode != ino) {
7496 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
7497 dirent->inode = ino;
7498 status = 1;
7499 }
7500 }
7501 if (dirent->rec_len > 12) {
7502 new_len = dirent->rec_len - 12;
7503 if (new_len > 12) {
7504 if (created ||
7505 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
7506 nextdir = (struct ext2_dir_entry *)
7507 ((char *) dirent + 12);
7508 dirent->rec_len = 12;
7509 nextdir->rec_len = new_len;
7510 nextdir->inode = 0;
7511 nextdir->name_len = 0;
7512 status = 1;
7513 }
7514 }
7515 }
7516 return status;
7517}
7518
7519/*
7520 * Make sure the second entry in the directory is '..', and that the
7521 * directory entry is sane. We do not check the inode number of '..'
7522 * here; this gets done in pass 3.
7523 */
7524static int check_dotdot(e2fsck_t ctx,
7525 struct ext2_dir_entry *dirent,
7526 struct dir_info *dir, struct problem_context *pctx)
7527{
7528 int problem = 0;
7529
7530 if (!dirent->inode)
7531 problem = PR_2_MISSING_DOT_DOT;
7532 else if (((dirent->name_len & 0xFF) != 2) ||
7533 (dirent->name[0] != '.') ||
7534 (dirent->name[1] != '.'))
7535 problem = PR_2_2ND_NOT_DOT_DOT;
7536 else if (dirent->name[2] != '\0')
7537 problem = PR_2_DOT_DOT_NULL_TERM;
7538
7539 if (problem) {
7540 if (fix_problem(ctx, problem, pctx)) {
7541 if (dirent->rec_len < 12)
7542 dirent->rec_len = 12;
7543 /*
7544 * Note: we don't have the parent inode just
7545 * yet, so we will fill it in with the root
7546 * inode. This will get fixed in pass 3.
7547 */
7548 dirent->inode = EXT2_ROOT_INO;
7549 dirent->name_len = 2;
7550 dirent->name[0] = '.';
7551 dirent->name[1] = '.';
7552 dirent->name[2] = '\0';
7553 return 1;
7554 }
7555 return 0;
7556 }
7557 dir->dotdot = dirent->inode;
7558 return 0;
7559}
7560
7561/*
7562 * Check to make sure a directory entry doesn't contain any illegal
7563 * characters.
7564 */
7565static int check_name(e2fsck_t ctx,
7566 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007567 struct problem_context *pctx)
7568{
7569 int i;
7570 int fixup = -1;
7571 int ret = 0;
7572
7573 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
7574 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
7575 if (fixup < 0) {
7576 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
7577 }
7578 if (fixup) {
7579 dirent->name[i] = '.';
7580 ret = 1;
7581 }
7582 }
7583 }
7584 return ret;
7585}
7586
7587/*
7588 * Check the directory filetype (if present)
7589 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007590
7591/*
7592 * Given a mode, return the ext2 file type
7593 */
7594static int ext2_file_type(unsigned int mode)
7595{
7596 if (LINUX_S_ISREG(mode))
7597 return EXT2_FT_REG_FILE;
7598
7599 if (LINUX_S_ISDIR(mode))
7600 return EXT2_FT_DIR;
7601
7602 if (LINUX_S_ISCHR(mode))
7603 return EXT2_FT_CHRDEV;
7604
7605 if (LINUX_S_ISBLK(mode))
7606 return EXT2_FT_BLKDEV;
7607
7608 if (LINUX_S_ISLNK(mode))
7609 return EXT2_FT_SYMLINK;
7610
7611 if (LINUX_S_ISFIFO(mode))
7612 return EXT2_FT_FIFO;
7613
7614 if (LINUX_S_ISSOCK(mode))
7615 return EXT2_FT_SOCK;
7616
7617 return 0;
7618}
7619
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007620static _INLINE_ int check_filetype(e2fsck_t ctx,
7621 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007622 struct problem_context *pctx)
7623{
7624 int filetype = dirent->name_len >> 8;
7625 int should_be = EXT2_FT_UNKNOWN;
7626 struct ext2_inode inode;
7627
7628 if (!(ctx->fs->super->s_feature_incompat &
7629 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
7630 if (filetype == 0 ||
7631 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
7632 return 0;
7633 dirent->name_len = dirent->name_len & 0xFF;
7634 return 1;
7635 }
7636
7637 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
7638 should_be = EXT2_FT_DIR;
7639 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
7640 dirent->inode)) {
7641 should_be = EXT2_FT_REG_FILE;
7642 } else if (ctx->inode_bad_map &&
7643 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
7644 dirent->inode))
7645 should_be = 0;
7646 else {
7647 e2fsck_read_inode(ctx, dirent->inode, &inode,
7648 "check_filetype");
7649 should_be = ext2_file_type(inode.i_mode);
7650 }
7651 if (filetype == should_be)
7652 return 0;
7653 pctx->num = should_be;
7654
7655 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
7656 pctx) == 0)
7657 return 0;
7658
7659 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
7660 return 1;
7661}
7662
7663#ifdef ENABLE_HTREE
7664static void parse_int_node(ext2_filsys fs,
7665 struct ext2_db_entry *db,
7666 struct check_dir_struct *cd,
7667 struct dx_dir_info *dx_dir,
7668 char *block_buf)
7669{
7670 struct ext2_dx_root_info *root;
7671 struct ext2_dx_entry *ent;
7672 struct ext2_dx_countlimit *limit;
7673 struct dx_dirblock_info *dx_db;
7674 int i, expect_limit, count;
7675 blk_t blk;
7676 ext2_dirhash_t min_hash = 0xffffffff;
7677 ext2_dirhash_t max_hash = 0;
7678 ext2_dirhash_t hash = 0, prev_hash;
7679
7680 if (db->blockcnt == 0) {
7681 root = (struct ext2_dx_root_info *) (block_buf + 24);
7682
7683#ifdef DX_DEBUG
7684 printf("Root node dump:\n");
7685 printf("\t Reserved zero: %d\n", root->reserved_zero);
7686 printf("\t Hash Version: %d\n", root->hash_version);
7687 printf("\t Info length: %d\n", root->info_length);
7688 printf("\t Indirect levels: %d\n", root->indirect_levels);
7689 printf("\t Flags: %d\n", root->unused_flags);
7690#endif
7691
7692 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
7693 } else {
7694 ent = (struct ext2_dx_entry *) (block_buf+8);
7695 }
7696 limit = (struct ext2_dx_countlimit *) ent;
7697
7698#ifdef DX_DEBUG
7699 printf("Number of entries (count): %d\n",
7700 ext2fs_le16_to_cpu(limit->count));
7701 printf("Number of entries (limit): %d\n",
7702 ext2fs_le16_to_cpu(limit->limit));
7703#endif
7704
7705 count = ext2fs_le16_to_cpu(limit->count);
7706 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
7707 sizeof(struct ext2_dx_entry);
7708 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
7709 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
7710 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
7711 goto clear_and_exit;
7712 }
7713 if (count > expect_limit) {
7714 cd->pctx.num = count;
7715 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
7716 goto clear_and_exit;
7717 count = expect_limit;
7718 }
7719
7720 for (i=0; i < count; i++) {
7721 prev_hash = hash;
7722 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
7723#ifdef DX_DEBUG
7724 printf("Entry #%d: Hash 0x%08x, block %d\n", i,
7725 hash, ext2fs_le32_to_cpu(ent[i].block));
7726#endif
7727 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
7728 /* Check to make sure the block is valid */
7729 if (blk > (blk_t) dx_dir->numblocks) {
7730 cd->pctx.blk = blk;
7731 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
7732 &cd->pctx))
7733 goto clear_and_exit;
7734 }
7735 if (hash < prev_hash &&
7736 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
7737 goto clear_and_exit;
7738 dx_db = &dx_dir->dx_block[blk];
7739 if (dx_db->flags & DX_FLAG_REFERENCED) {
7740 dx_db->flags |= DX_FLAG_DUP_REF;
7741 } else {
7742 dx_db->flags |= DX_FLAG_REFERENCED;
7743 dx_db->parent = db->blockcnt;
7744 }
7745 if (hash < min_hash)
7746 min_hash = hash;
7747 if (hash > max_hash)
7748 max_hash = hash;
7749 dx_db->node_min_hash = hash;
7750 if ((i+1) < count)
7751 dx_db->node_max_hash =
7752 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
7753 else {
7754 dx_db->node_max_hash = 0xfffffffe;
7755 dx_db->flags |= DX_FLAG_LAST;
7756 }
7757 if (i == 0)
7758 dx_db->flags |= DX_FLAG_FIRST;
7759 }
7760#ifdef DX_DEBUG
7761 printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
7762 db->blockcnt, min_hash, max_hash);
7763#endif
7764 dx_db = &dx_dir->dx_block[db->blockcnt];
7765 dx_db->min_hash = min_hash;
7766 dx_db->max_hash = max_hash;
7767 return;
7768
7769clear_and_exit:
7770 clear_htree(cd->ctx, cd->pctx.ino);
7771 dx_dir->numblocks = 0;
7772}
7773#endif /* ENABLE_HTREE */
7774
7775/*
7776 * Given a busted directory, try to salvage it somehow.
7777 *
7778 */
7779static void salvage_directory(ext2_filsys fs,
7780 struct ext2_dir_entry *dirent,
7781 struct ext2_dir_entry *prev,
7782 unsigned int *offset)
7783{
7784 char *cp = (char *) dirent;
7785 int left = fs->blocksize - *offset - dirent->rec_len;
7786 int name_len = dirent->name_len & 0xFF;
7787
7788 /*
7789 * Special case of directory entry of size 8: copy what's left
7790 * of the directory block up to cover up the invalid hole.
7791 */
7792 if ((left >= 12) && (dirent->rec_len == 8)) {
7793 memmove(cp, cp+8, left);
7794 memset(cp + left, 0, 8);
7795 return;
7796 }
7797 /*
7798 * If the directory entry overruns the end of the directory
7799 * block, and the name is small enough to fit, then adjust the
7800 * record length.
7801 */
7802 if ((left < 0) &&
7803 (name_len + 8 <= dirent->rec_len + left) &&
7804 dirent->inode <= fs->super->s_inodes_count &&
7805 strnlen(dirent->name, name_len) == name_len) {
7806 dirent->rec_len += left;
7807 return;
7808 }
7809 /*
7810 * If the directory entry is a multiple of four, so it is
7811 * valid, let the previous directory entry absorb the invalid
7812 * one.
7813 */
7814 if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
7815 prev->rec_len += dirent->rec_len;
7816 *offset += dirent->rec_len;
7817 return;
7818 }
7819 /*
7820 * Default salvage method --- kill all of the directory
7821 * entries for the rest of the block. We will either try to
7822 * absorb it into the previous directory entry, or create a
7823 * new empty directory entry the rest of the directory block.
7824 */
7825 if (prev) {
7826 prev->rec_len += fs->blocksize - *offset;
7827 *offset = fs->blocksize;
7828 } else {
7829 dirent->rec_len = fs->blocksize - *offset;
7830 dirent->name_len = 0;
7831 dirent->inode = 0;
7832 }
7833}
7834
7835static int check_dir_block(ext2_filsys fs,
7836 struct ext2_db_entry *db,
7837 void *priv_data)
7838{
7839 struct dir_info *subdir, *dir;
7840 struct dx_dir_info *dx_dir;
7841#ifdef ENABLE_HTREE
7842 struct dx_dirblock_info *dx_db = 0;
7843#endif /* ENABLE_HTREE */
7844 struct ext2_dir_entry *dirent, *prev;
7845 ext2_dirhash_t hash;
7846 unsigned int offset = 0;
7847 int dir_modified = 0;
7848 int dot_state;
7849 blk_t block_nr = db->blk;
7850 ext2_ino_t ino = db->ino;
7851 __u16 links;
7852 struct check_dir_struct *cd;
7853 char *buf;
7854 e2fsck_t ctx;
7855 int problem;
7856 struct ext2_dx_root_info *root;
7857 struct ext2_dx_countlimit *limit;
7858 static dict_t de_dict;
7859 struct problem_context pctx;
7860 int dups_found = 0;
7861
7862 cd = (struct check_dir_struct *) priv_data;
7863 buf = cd->buf;
7864 ctx = cd->ctx;
7865
7866 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7867 return DIRENT_ABORT;
7868
7869 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
7870 return DIRENT_ABORT;
7871
7872 /*
7873 * Make sure the inode is still in use (could have been
7874 * deleted in the duplicate/bad blocks pass.
7875 */
7876 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
7877 return 0;
7878
7879 cd->pctx.ino = ino;
7880 cd->pctx.blk = block_nr;
7881 cd->pctx.blkcount = db->blockcnt;
7882 cd->pctx.ino2 = 0;
7883 cd->pctx.dirent = 0;
7884 cd->pctx.num = 0;
7885
7886 if (db->blk == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007887 if (allocate_dir_block(ctx, db, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007888 return 0;
7889 block_nr = db->blk;
7890 }
7891
7892 if (db->blockcnt)
7893 dot_state = 2;
7894 else
7895 dot_state = 0;
7896
7897 if (ctx->dirs_to_hash &&
7898 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
7899 dups_found++;
7900
7901#if 0
7902 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
7903 db->blockcnt, ino);
7904#endif
7905
7906 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
7907 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
7908 cd->pctx.errcode = 0; /* We'll handle this ourselves */
7909 if (cd->pctx.errcode) {
7910 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
7911 ctx->flags |= E2F_FLAG_ABORT;
7912 return DIRENT_ABORT;
7913 }
7914 memset(buf, 0, fs->blocksize);
7915 }
7916#ifdef ENABLE_HTREE
7917 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
7918 if (dx_dir && dx_dir->numblocks) {
7919 if (db->blockcnt >= dx_dir->numblocks) {
7920 printf("XXX should never happen!!!\n");
7921 abort();
7922 }
7923 dx_db = &dx_dir->dx_block[db->blockcnt];
7924 dx_db->type = DX_DIRBLOCK_LEAF;
7925 dx_db->phys = block_nr;
7926 dx_db->min_hash = ~0;
7927 dx_db->max_hash = 0;
7928
7929 dirent = (struct ext2_dir_entry *) buf;
7930 limit = (struct ext2_dx_countlimit *) (buf+8);
7931 if (db->blockcnt == 0) {
7932 root = (struct ext2_dx_root_info *) (buf + 24);
7933 dx_db->type = DX_DIRBLOCK_ROOT;
7934 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
7935 if ((root->reserved_zero ||
7936 root->info_length < 8 ||
7937 root->indirect_levels > 1) &&
7938 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
7939 clear_htree(ctx, ino);
7940 dx_dir->numblocks = 0;
7941 dx_db = 0;
7942 }
7943 dx_dir->hashversion = root->hash_version;
7944 dx_dir->depth = root->indirect_levels + 1;
7945 } else if ((dirent->inode == 0) &&
7946 (dirent->rec_len == fs->blocksize) &&
7947 (dirent->name_len == 0) &&
7948 (ext2fs_le16_to_cpu(limit->limit) ==
7949 ((fs->blocksize-8) /
7950 sizeof(struct ext2_dx_entry))))
7951 dx_db->type = DX_DIRBLOCK_NODE;
7952 }
7953#endif /* ENABLE_HTREE */
7954
7955 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
7956 prev = 0;
7957 do {
7958 problem = 0;
7959 dirent = (struct ext2_dir_entry *) (buf + offset);
7960 cd->pctx.dirent = dirent;
7961 cd->pctx.num = offset;
7962 if (((offset + dirent->rec_len) > fs->blocksize) ||
7963 (dirent->rec_len < 12) ||
7964 ((dirent->rec_len % 4) != 0) ||
7965 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
7966 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
7967 salvage_directory(fs, dirent, prev, &offset);
7968 dir_modified++;
7969 continue;
7970 } else
7971 goto abort_free_dict;
7972 }
7973 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
7974 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
7975 dirent->name_len = EXT2_NAME_LEN;
7976 dir_modified++;
7977 }
7978 }
7979
7980 if (dot_state == 0) {
7981 if (check_dot(ctx, dirent, ino, &cd->pctx))
7982 dir_modified++;
7983 } else if (dot_state == 1) {
7984 dir = e2fsck_get_dir_info(ctx, ino);
7985 if (!dir) {
7986 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
7987 goto abort_free_dict;
7988 }
7989 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
7990 dir_modified++;
7991 } else if (dirent->inode == ino) {
7992 problem = PR_2_LINK_DOT;
7993 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
7994 dirent->inode = 0;
7995 dir_modified++;
7996 goto next;
7997 }
7998 }
7999 if (!dirent->inode)
8000 goto next;
8001
8002 /*
8003 * Make sure the inode listed is a legal one.
8004 */
8005 if (((dirent->inode != EXT2_ROOT_INO) &&
8006 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
8007 (dirent->inode > fs->super->s_inodes_count)) {
8008 problem = PR_2_BAD_INO;
8009 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
8010 dirent->inode))) {
8011 /*
8012 * If the inode is unused, offer to clear it.
8013 */
8014 problem = PR_2_UNUSED_INODE;
8015 } else if (ctx->inode_bb_map &&
8016 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
8017 dirent->inode))) {
8018 /*
8019 * If the inode is in a bad block, offer to
8020 * clear it.
8021 */
8022 problem = PR_2_BB_INODE;
8023 } else if ((dot_state > 1) &&
8024 ((dirent->name_len & 0xFF) == 1) &&
8025 (dirent->name[0] == '.')) {
8026 /*
8027 * If there's a '.' entry in anything other
8028 * than the first directory entry, it's a
8029 * duplicate entry that should be removed.
8030 */
8031 problem = PR_2_DUP_DOT;
8032 } else if ((dot_state > 1) &&
8033 ((dirent->name_len & 0xFF) == 2) &&
8034 (dirent->name[0] == '.') &&
8035 (dirent->name[1] == '.')) {
8036 /*
8037 * If there's a '..' entry in anything other
8038 * than the second directory entry, it's a
8039 * duplicate entry that should be removed.
8040 */
8041 problem = PR_2_DUP_DOT_DOT;
8042 } else if ((dot_state > 1) &&
8043 (dirent->inode == EXT2_ROOT_INO)) {
8044 /*
8045 * Don't allow links to the root directory.
8046 * We check this specially to make sure we
8047 * catch this error case even if the root
8048 * directory hasn't been created yet.
8049 */
8050 problem = PR_2_LINK_ROOT;
8051 } else if ((dot_state > 1) &&
8052 (dirent->name_len & 0xFF) == 0) {
8053 /*
8054 * Don't allow zero-length directory names.
8055 */
8056 problem = PR_2_NULL_NAME;
8057 }
8058
8059 if (problem) {
8060 if (fix_problem(ctx, problem, &cd->pctx)) {
8061 dirent->inode = 0;
8062 dir_modified++;
8063 goto next;
8064 } else {
8065 ext2fs_unmark_valid(fs);
8066 if (problem == PR_2_BAD_INO)
8067 goto next;
8068 }
8069 }
8070
8071 /*
8072 * If the inode was marked as having bad fields in
8073 * pass1, process it and offer to fix/clear it.
8074 * (We wait until now so that we can display the
8075 * pathname to the user.)
8076 */
8077 if (ctx->inode_bad_map &&
8078 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
8079 dirent->inode)) {
8080 if (e2fsck_process_bad_inode(ctx, ino,
8081 dirent->inode,
8082 buf + fs->blocksize)) {
8083 dirent->inode = 0;
8084 dir_modified++;
8085 goto next;
8086 }
8087 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8088 return DIRENT_ABORT;
8089 }
8090
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008091 if (check_name(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008092 dir_modified++;
8093
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008094 if (check_filetype(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008095 dir_modified++;
8096
8097#ifdef ENABLE_HTREE
8098 if (dx_db) {
8099 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
8100 (dirent->name_len & 0xFF),
8101 fs->super->s_hash_seed, &hash, 0);
8102 if (hash < dx_db->min_hash)
8103 dx_db->min_hash = hash;
8104 if (hash > dx_db->max_hash)
8105 dx_db->max_hash = hash;
8106 }
8107#endif
8108
8109 /*
8110 * If this is a directory, then mark its parent in its
8111 * dir_info structure. If the parent field is already
8112 * filled in, then this directory has more than one
8113 * hard link. We assume the first link is correct,
8114 * and ask the user if he/she wants to clear this one.
8115 */
8116 if ((dot_state > 1) &&
8117 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8118 dirent->inode))) {
8119 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
8120 if (!subdir) {
8121 cd->pctx.ino = dirent->inode;
8122 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
8123 goto abort_free_dict;
8124 }
8125 if (subdir->parent) {
8126 cd->pctx.ino2 = subdir->parent;
8127 if (fix_problem(ctx, PR_2_LINK_DIR,
8128 &cd->pctx)) {
8129 dirent->inode = 0;
8130 dir_modified++;
8131 goto next;
8132 }
8133 cd->pctx.ino2 = 0;
8134 } else
8135 subdir->parent = ino;
8136 }
8137
8138 if (dups_found) {
8139 ;
8140 } else if (dict_lookup(&de_dict, dirent)) {
8141 clear_problem_context(&pctx);
8142 pctx.ino = ino;
8143 pctx.dirent = dirent;
8144 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
8145 if (!ctx->dirs_to_hash)
8146 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
8147 if (ctx->dirs_to_hash)
8148 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8149 dups_found++;
8150 } else
8151 dict_alloc_insert(&de_dict, dirent, dirent);
8152
8153 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
8154 &links);
8155 if (links > 1)
8156 ctx->fs_links_count++;
8157 ctx->fs_total_count++;
8158 next:
8159 prev = dirent;
8160 offset += dirent->rec_len;
8161 dot_state++;
8162 } while (offset < fs->blocksize);
8163#if 0
8164 printf("\n");
8165#endif
8166#ifdef ENABLE_HTREE
8167 if (dx_db) {
8168#ifdef DX_DEBUG
8169 printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
8170 db->blockcnt, dx_db->type,
8171 dx_db->min_hash, dx_db->max_hash);
8172#endif
8173 cd->pctx.dir = cd->pctx.ino;
8174 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
8175 (dx_db->type == DX_DIRBLOCK_NODE))
8176 parse_int_node(fs, db, cd, dx_dir, buf);
8177 }
8178#endif /* ENABLE_HTREE */
8179 if (offset != fs->blocksize) {
8180 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
8181 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
8182 dirent->rec_len = cd->pctx.num;
8183 dir_modified++;
8184 }
8185 }
8186 if (dir_modified) {
8187 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
8188 if (cd->pctx.errcode) {
8189 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
8190 &cd->pctx))
8191 goto abort_free_dict;
8192 }
8193 ext2fs_mark_changed(fs);
8194 }
8195 dict_free_nodes(&de_dict);
8196 return 0;
8197abort_free_dict:
8198 dict_free_nodes(&de_dict);
8199 ctx->flags |= E2F_FLAG_ABORT;
8200 return DIRENT_ABORT;
8201}
8202
8203/*
8204 * This function is called to deallocate a block, and is an interator
8205 * functioned called by deallocate inode via ext2fs_iterate_block().
8206 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008207static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00008208 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
8209 blk_t ref_block FSCK_ATTR((unused)),
8210 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008211 void *priv_data)
8212{
8213 e2fsck_t ctx = (e2fsck_t) priv_data;
8214
8215 if (HOLE_BLKADDR(*block_nr))
8216 return 0;
8217 if ((*block_nr < fs->super->s_first_data_block) ||
8218 (*block_nr >= fs->super->s_blocks_count))
8219 return 0;
8220 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
8221 ext2fs_block_alloc_stats(fs, *block_nr, -1);
8222 return 0;
8223}
8224
8225/*
8226 * This fuction deallocates an inode
8227 */
8228static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
8229{
8230 ext2_filsys fs = ctx->fs;
8231 struct ext2_inode inode;
8232 struct problem_context pctx;
8233 __u32 count;
8234
8235 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
8236 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
8237 inode.i_links_count = 0;
8238 inode.i_dtime = time(0);
8239 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
8240 clear_problem_context(&pctx);
8241 pctx.ino = ino;
8242
8243 /*
8244 * Fix up the bitmaps...
8245 */
8246 e2fsck_read_bitmaps(ctx);
8247 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
8248 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
8249 if (ctx->inode_bad_map)
8250 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8251 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
8252
8253 if (inode.i_file_acl &&
8254 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
8255 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
8256 block_buf, -1, &count);
8257 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
8258 pctx.errcode = 0;
8259 count = 1;
8260 }
8261 if (pctx.errcode) {
8262 pctx.blk = inode.i_file_acl;
8263 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
8264 ctx->flags |= E2F_FLAG_ABORT;
8265 return;
8266 }
8267 if (count == 0) {
8268 ext2fs_unmark_block_bitmap(ctx->block_found_map,
8269 inode.i_file_acl);
8270 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
8271 }
8272 inode.i_file_acl = 0;
8273 }
8274
8275 if (!ext2fs_inode_has_valid_blocks(&inode))
8276 return;
8277
8278 if (LINUX_S_ISREG(inode.i_mode) &&
8279 (inode.i_size_high || inode.i_size & 0x80000000UL))
8280 ctx->large_files--;
8281
8282 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
8283 deallocate_inode_block, ctx);
8284 if (pctx.errcode) {
8285 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
8286 ctx->flags |= E2F_FLAG_ABORT;
8287 return;
8288 }
8289}
8290
8291/*
8292 * This fuction clears the htree flag on an inode
8293 */
8294static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
8295{
8296 struct ext2_inode inode;
8297
8298 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
8299 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
8300 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
8301 if (ctx->dirs_to_hash)
8302 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8303}
8304
8305
8306static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
8307 ext2_ino_t ino, char *buf)
8308{
8309 ext2_filsys fs = ctx->fs;
8310 struct ext2_inode inode;
8311 int inode_modified = 0;
8312 int not_fixed = 0;
8313 unsigned char *frag, *fsize;
8314 struct problem_context pctx;
8315 int problem = 0;
8316
8317 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
8318
8319 clear_problem_context(&pctx);
8320 pctx.ino = ino;
8321 pctx.dir = dir;
8322 pctx.inode = &inode;
8323
8324 if (inode.i_file_acl &&
8325 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
8326 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
8327 inode.i_file_acl = 0;
8328#ifdef EXT2FS_ENABLE_SWAPFS
8329 /*
8330 * This is a special kludge to deal with long symlinks
8331 * on big endian systems. i_blocks had already been
8332 * decremented earlier in pass 1, but since i_file_acl
8333 * hadn't yet been cleared, ext2fs_read_inode()
8334 * assumed that the file was short symlink and would
8335 * not have byte swapped i_block[0]. Hence, we have
8336 * to byte-swap it here.
8337 */
8338 if (LINUX_S_ISLNK(inode.i_mode) &&
8339 (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
8340 (inode.i_blocks == fs->blocksize >> 9))
8341 inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
8342#endif
8343 inode_modified++;
8344 } else
8345 not_fixed++;
8346
8347 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
8348 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
8349 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
8350 !(LINUX_S_ISSOCK(inode.i_mode)))
8351 problem = PR_2_BAD_MODE;
8352 else if (LINUX_S_ISCHR(inode.i_mode)
8353 && !e2fsck_pass1_check_device_inode(fs, &inode))
8354 problem = PR_2_BAD_CHAR_DEV;
8355 else if (LINUX_S_ISBLK(inode.i_mode)
8356 && !e2fsck_pass1_check_device_inode(fs, &inode))
8357 problem = PR_2_BAD_BLOCK_DEV;
8358 else if (LINUX_S_ISFIFO(inode.i_mode)
8359 && !e2fsck_pass1_check_device_inode(fs, &inode))
8360 problem = PR_2_BAD_FIFO;
8361 else if (LINUX_S_ISSOCK(inode.i_mode)
8362 && !e2fsck_pass1_check_device_inode(fs, &inode))
8363 problem = PR_2_BAD_SOCKET;
8364 else if (LINUX_S_ISLNK(inode.i_mode)
8365 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
8366 problem = PR_2_INVALID_SYMLINK;
8367 }
8368
8369 if (problem) {
8370 if (fix_problem(ctx, problem, &pctx)) {
8371 deallocate_inode(ctx, ino, 0);
8372 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8373 return 0;
8374 return 1;
8375 } else
8376 not_fixed++;
8377 problem = 0;
8378 }
8379
8380 if (inode.i_faddr) {
8381 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
8382 inode.i_faddr = 0;
8383 inode_modified++;
8384 } else
8385 not_fixed++;
8386 }
8387
8388 switch (fs->super->s_creator_os) {
8389 case EXT2_OS_LINUX:
8390 frag = &inode.osd2.linux2.l_i_frag;
8391 fsize = &inode.osd2.linux2.l_i_fsize;
8392 break;
8393 case EXT2_OS_HURD:
8394 frag = &inode.osd2.hurd2.h_i_frag;
8395 fsize = &inode.osd2.hurd2.h_i_fsize;
8396 break;
8397 case EXT2_OS_MASIX:
8398 frag = &inode.osd2.masix2.m_i_frag;
8399 fsize = &inode.osd2.masix2.m_i_fsize;
8400 break;
8401 default:
8402 frag = fsize = 0;
8403 }
8404 if (frag && *frag) {
8405 pctx.num = *frag;
8406 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
8407 *frag = 0;
8408 inode_modified++;
8409 } else
8410 not_fixed++;
8411 pctx.num = 0;
8412 }
8413 if (fsize && *fsize) {
8414 pctx.num = *fsize;
8415 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
8416 *fsize = 0;
8417 inode_modified++;
8418 } else
8419 not_fixed++;
8420 pctx.num = 0;
8421 }
8422
8423 if (inode.i_file_acl &&
8424 ((inode.i_file_acl < fs->super->s_first_data_block) ||
8425 (inode.i_file_acl >= fs->super->s_blocks_count))) {
8426 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
8427 inode.i_file_acl = 0;
8428 inode_modified++;
8429 } else
8430 not_fixed++;
8431 }
8432 if (inode.i_dir_acl &&
8433 LINUX_S_ISDIR(inode.i_mode)) {
8434 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
8435 inode.i_dir_acl = 0;
8436 inode_modified++;
8437 } else
8438 not_fixed++;
8439 }
8440
8441 if (inode_modified)
8442 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
8443 if (!not_fixed)
8444 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8445 return 0;
8446}
8447
8448
8449/*
8450 * allocate_dir_block --- this function allocates a new directory
8451 * block for a particular inode; this is done if a directory has
8452 * a "hole" in it, or if a directory has a illegal block number
8453 * that was zeroed out and now needs to be replaced.
8454 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008455static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008456 struct problem_context *pctx)
8457{
8458 ext2_filsys fs = ctx->fs;
8459 blk_t blk;
8460 char *block;
8461 struct ext2_inode inode;
8462
8463 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
8464 return 1;
8465
8466 /*
8467 * Read the inode and block bitmaps in; we'll be messing with
8468 * them.
8469 */
8470 e2fsck_read_bitmaps(ctx);
8471
8472 /*
8473 * First, find a free block
8474 */
8475 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8476 if (pctx->errcode) {
8477 pctx->str = "ext2fs_new_block";
8478 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8479 return 1;
8480 }
8481 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8482 ext2fs_mark_block_bitmap(fs->block_map, blk);
8483 ext2fs_mark_bb_dirty(fs);
8484
8485 /*
8486 * Now let's create the actual data block for the inode
8487 */
8488 if (db->blockcnt)
8489 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
8490 else
8491 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
8492 EXT2_ROOT_INO, &block);
8493
8494 if (pctx->errcode) {
8495 pctx->str = "ext2fs_new_dir_block";
8496 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8497 return 1;
8498 }
8499
8500 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
8501 ext2fs_free_mem(&block);
8502 if (pctx->errcode) {
8503 pctx->str = "ext2fs_write_dir_block";
8504 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8505 return 1;
8506 }
8507
8508 /*
8509 * Update the inode block count
8510 */
8511 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
8512 inode.i_blocks += fs->blocksize / 512;
8513 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
8514 inode.i_size = (db->blockcnt+1) * fs->blocksize;
8515 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
8516
8517 /*
8518 * Finally, update the block pointers for the inode
8519 */
8520 db->blk = blk;
8521 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
8522 0, update_dir_block, db);
8523 if (pctx->errcode) {
8524 pctx->str = "ext2fs_block_iterate";
8525 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8526 return 1;
8527 }
8528
8529 return 0;
8530}
8531
8532/*
8533 * This is a helper function for allocate_dir_block().
8534 */
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00008535static int update_dir_block(ext2_filsys fs FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008536 blk_t *block_nr,
8537 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00008538 blk_t ref_block FSCK_ATTR((unused)),
8539 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008540 void *priv_data)
8541{
8542 struct ext2_db_entry *db;
8543
8544 db = (struct ext2_db_entry *) priv_data;
8545 if (db->blockcnt == (int) blockcnt) {
8546 *block_nr = db->blk;
8547 return BLOCK_CHANGED;
8548 }
8549 return 0;
8550}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008551
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008552/*
8553 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
8554 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008555 * Pass #3 assures that all directories are connected to the
8556 * filesystem tree, using the following algorithm:
8557 *
8558 * First, the root directory is checked to make sure it exists; if
8559 * not, e2fsck will offer to create a new one. It is then marked as
8560 * "done".
8561 *
8562 * Then, pass3 interates over all directory inodes; for each directory
8563 * it attempts to trace up the filesystem tree, using dirinfo.parent
8564 * until it reaches a directory which has been marked "done". If it
8565 * can not do so, then the directory must be disconnected, and e2fsck
8566 * will offer to reconnect it to /lost+found. While it is chasing
8567 * parent pointers up the filesystem tree, if pass3 sees a directory
8568 * twice, then it has detected a filesystem loop, and it will again
8569 * offer to reconnect the directory to /lost+found in to break the
8570 * filesystem loop.
8571 *
8572 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
8573 * reconnect inodes to /lost+found; this subroutine is also used by
8574 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
8575 * is responsible for creating /lost+found if it does not exist.
8576 *
8577 * Pass 3 frees the following data structures:
8578 * - The dirinfo directory information cache.
8579 */
8580
8581static void check_root(e2fsck_t ctx);
8582static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8583 struct problem_context *pctx);
8584static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
8585
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008586static ext2fs_inode_bitmap inode_loop_detect;
8587static ext2fs_inode_bitmap inode_done_map;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008588
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008589static void e2fsck_pass3(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008590{
8591 ext2_filsys fs = ctx->fs;
8592 int i;
8593#ifdef RESOURCE_TRACK
8594 struct resource_track rtrack;
8595#endif
8596 struct problem_context pctx;
8597 struct dir_info *dir;
8598 unsigned long maxdirs, count;
8599
8600#ifdef RESOURCE_TRACK
8601 init_resource_track(&rtrack);
8602#endif
8603
8604 clear_problem_context(&pctx);
8605
8606#ifdef MTRACE
8607 mtrace_print("Pass 3");
8608#endif
8609
8610 if (!(ctx->options & E2F_OPT_PREEN))
8611 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
8612
8613 /*
8614 * Allocate some bitmaps to do loop detection.
8615 */
8616 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
8617 &inode_done_map);
8618 if (pctx.errcode) {
8619 pctx.num = 2;
8620 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
8621 ctx->flags |= E2F_FLAG_ABORT;
8622 goto abort_exit;
8623 }
8624#ifdef RESOURCE_TRACK
8625 if (ctx->options & E2F_OPT_TIME) {
8626 e2fsck_clear_progbar(ctx);
8627 print_resource_track(_("Peak memory"), &ctx->global_rtrack);
8628 }
8629#endif
8630
8631 check_root(ctx);
8632 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8633 goto abort_exit;
8634
8635 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
8636
8637 maxdirs = e2fsck_get_num_dirinfo(ctx);
8638 count = 1;
8639
8640 if (ctx->progress)
8641 if ((ctx->progress)(ctx, 3, 0, maxdirs))
8642 goto abort_exit;
8643
8644 for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
8645 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8646 goto abort_exit;
8647 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
8648 goto abort_exit;
8649 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
8650 if (check_directory(ctx, dir, &pctx))
8651 goto abort_exit;
8652 }
8653
8654 /*
8655 * Force the creation of /lost+found if not present
8656 */
8657 if ((ctx->flags & E2F_OPT_READONLY) == 0)
8658 e2fsck_get_lost_and_found(ctx, 1);
8659
8660 /*
8661 * If there are any directories that need to be indexed or
8662 * optimized, do it here.
8663 */
8664 e2fsck_rehash_directories(ctx);
8665
8666abort_exit:
8667 e2fsck_free_dir_info(ctx);
8668 if (inode_loop_detect) {
8669 ext2fs_free_inode_bitmap(inode_loop_detect);
8670 inode_loop_detect = 0;
8671 }
8672 if (inode_done_map) {
8673 ext2fs_free_inode_bitmap(inode_done_map);
8674 inode_done_map = 0;
8675 }
8676
8677#ifdef RESOURCE_TRACK
8678 if (ctx->options & E2F_OPT_TIME2) {
8679 e2fsck_clear_progbar(ctx);
8680 print_resource_track(_("Pass 3"), &rtrack);
8681 }
8682#endif
8683}
8684
8685/*
8686 * This makes sure the root inode is present; if not, we ask if the
8687 * user wants us to create it. Not creating it is a fatal error.
8688 */
8689static void check_root(e2fsck_t ctx)
8690{
8691 ext2_filsys fs = ctx->fs;
8692 blk_t blk;
8693 struct ext2_inode inode;
8694 char * block;
8695 struct problem_context pctx;
8696
8697 clear_problem_context(&pctx);
8698
8699 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
8700 /*
8701 * If the root inode is not a directory, die here. The
8702 * user must have answered 'no' in pass1 when we
8703 * offered to clear it.
8704 */
8705 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8706 EXT2_ROOT_INO))) {
8707 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
8708 ctx->flags |= E2F_FLAG_ABORT;
8709 }
8710 return;
8711 }
8712
8713 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
8714 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
8715 ctx->flags |= E2F_FLAG_ABORT;
8716 return;
8717 }
8718
8719 e2fsck_read_bitmaps(ctx);
8720
8721 /*
8722 * First, find a free block
8723 */
8724 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8725 if (pctx.errcode) {
8726 pctx.str = "ext2fs_new_block";
8727 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8728 ctx->flags |= E2F_FLAG_ABORT;
8729 return;
8730 }
8731 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8732 ext2fs_mark_block_bitmap(fs->block_map, blk);
8733 ext2fs_mark_bb_dirty(fs);
8734
8735 /*
8736 * Now let's create the actual data block for the inode
8737 */
8738 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
8739 &block);
8740 if (pctx.errcode) {
8741 pctx.str = "ext2fs_new_dir_block";
8742 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8743 ctx->flags |= E2F_FLAG_ABORT;
8744 return;
8745 }
8746
8747 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
8748 if (pctx.errcode) {
8749 pctx.str = "ext2fs_write_dir_block";
8750 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8751 ctx->flags |= E2F_FLAG_ABORT;
8752 return;
8753 }
8754 ext2fs_free_mem(&block);
8755
8756 /*
8757 * Set up the inode structure
8758 */
8759 memset(&inode, 0, sizeof(inode));
8760 inode.i_mode = 040755;
8761 inode.i_size = fs->blocksize;
8762 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
8763 inode.i_links_count = 2;
8764 inode.i_blocks = fs->blocksize / 512;
8765 inode.i_block[0] = blk;
8766
8767 /*
8768 * Write out the inode.
8769 */
8770 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
8771 if (pctx.errcode) {
8772 pctx.str = "ext2fs_write_inode";
8773 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8774 ctx->flags |= E2F_FLAG_ABORT;
8775 return;
8776 }
8777
8778 /*
8779 * Miscellaneous bookkeeping...
8780 */
8781 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
8782 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
8783 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
8784
8785 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
8786 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
8787 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
8788 ext2fs_mark_ib_dirty(fs);
8789}
8790
8791/*
8792 * This subroutine is responsible for making sure that a particular
8793 * directory is connected to the root; if it isn't we trace it up as
8794 * far as we can go, and then offer to connect the resulting parent to
8795 * the lost+found. We have to do loop detection; if we ever discover
8796 * a loop, we treat that as a disconnected directory and offer to
8797 * reparent it to lost+found.
8798 *
8799 * However, loop detection is expensive, because for very large
8800 * filesystems, the inode_loop_detect bitmap is huge, and clearing it
8801 * is non-trivial. Loops in filesystems are also a rare error case,
8802 * and we shouldn't optimize for error cases. So we try two passes of
8803 * the algorithm. The first time, we ignore loop detection and merely
8804 * increment a counter; if the counter exceeds some extreme threshold,
8805 * then we try again with the loop detection bitmap enabled.
8806 */
8807static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8808 struct problem_context *pctx)
8809{
8810 ext2_filsys fs = ctx->fs;
8811 struct dir_info *p = dir;
8812 int loop_pass = 0, parent_count = 0;
8813
8814 if (!p)
8815 return 0;
8816
8817 while (1) {
8818 /*
8819 * Mark this inode as being "done"; by the time we
8820 * return from this function, the inode we either be
8821 * verified as being connected to the directory tree,
8822 * or we will have offered to reconnect this to
8823 * lost+found.
8824 *
8825 * If it was marked done already, then we've reached a
8826 * parent we've already checked.
8827 */
8828 if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
8829 break;
8830
8831 /*
8832 * If this directory doesn't have a parent, or we've
8833 * seen the parent once already, then offer to
8834 * reparent it to lost+found
8835 */
8836 if (!p->parent ||
8837 (loop_pass &&
8838 (ext2fs_test_inode_bitmap(inode_loop_detect,
8839 p->parent)))) {
8840 pctx->ino = p->ino;
8841 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
8842 if (e2fsck_reconnect_file(ctx, pctx->ino))
8843 ext2fs_unmark_valid(fs);
8844 else {
8845 p = e2fsck_get_dir_info(ctx, pctx->ino);
8846 p->parent = ctx->lost_and_found;
8847 fix_dotdot(ctx, p, ctx->lost_and_found);
8848 }
8849 }
8850 break;
8851 }
8852 p = e2fsck_get_dir_info(ctx, p->parent);
8853 if (!p) {
8854 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
8855 return 0;
8856 }
8857 if (loop_pass) {
8858 ext2fs_mark_inode_bitmap(inode_loop_detect,
8859 p->ino);
8860 } else if (parent_count++ > 2048) {
8861 /*
8862 * If we've run into a path depth that's
8863 * greater than 2048, try again with the inode
8864 * loop bitmap turned on and start from the
8865 * top.
8866 */
8867 loop_pass = 1;
8868 if (inode_loop_detect)
8869 ext2fs_clear_inode_bitmap(inode_loop_detect);
8870 else {
8871 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
8872 if (pctx->errcode) {
8873 pctx->num = 1;
8874 fix_problem(ctx,
8875 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
8876 ctx->flags |= E2F_FLAG_ABORT;
8877 return -1;
8878 }
8879 }
8880 p = dir;
8881 }
8882 }
8883
8884 /*
8885 * Make sure that .. and the parent directory are the same;
8886 * offer to fix it if not.
8887 */
8888 if (dir->parent != dir->dotdot) {
8889 pctx->ino = dir->ino;
8890 pctx->ino2 = dir->dotdot;
8891 pctx->dir = dir->parent;
8892 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
8893 fix_dotdot(ctx, dir, dir->parent);
8894 }
8895 return 0;
8896}
8897
8898/*
8899 * This routine gets the lost_and_found inode, making it a directory
8900 * if necessary
8901 */
8902ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
8903{
8904 ext2_filsys fs = ctx->fs;
8905 ext2_ino_t ino;
8906 blk_t blk;
8907 errcode_t retval;
8908 struct ext2_inode inode;
8909 char * block;
8910 static const char name[] = "lost+found";
8911 struct problem_context pctx;
8912 struct dir_info *dirinfo;
8913
8914 if (ctx->lost_and_found)
8915 return ctx->lost_and_found;
8916
8917 clear_problem_context(&pctx);
8918
8919 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
8920 sizeof(name)-1, 0, &ino);
8921 if (retval && !fix)
8922 return 0;
8923 if (!retval) {
8924 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
8925 ctx->lost_and_found = ino;
8926 return ino;
8927 }
8928
8929 /* Lost+found isn't a directory! */
8930 if (!fix)
8931 return 0;
8932 pctx.ino = ino;
8933 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
8934 return 0;
8935
8936 /* OK, unlink the old /lost+found file. */
8937 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
8938 if (pctx.errcode) {
8939 pctx.str = "ext2fs_unlink";
8940 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
8941 return 0;
8942 }
8943 dirinfo = e2fsck_get_dir_info(ctx, ino);
8944 if (dirinfo)
8945 dirinfo->parent = 0;
8946 e2fsck_adjust_inode_count(ctx, ino, -1);
8947 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
8948 pctx.errcode = retval;
8949 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
8950 }
8951 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
8952 return 0;
8953
8954 /*
8955 * Read the inode and block bitmaps in; we'll be messing with
8956 * them.
8957 */
8958 e2fsck_read_bitmaps(ctx);
8959
8960 /*
8961 * First, find a free block
8962 */
8963 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8964 if (retval) {
8965 pctx.errcode = retval;
8966 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
8967 return 0;
8968 }
8969 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8970 ext2fs_block_alloc_stats(fs, blk, +1);
8971
8972 /*
8973 * Next find a free inode.
8974 */
8975 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
8976 ctx->inode_used_map, &ino);
8977 if (retval) {
8978 pctx.errcode = retval;
8979 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
8980 return 0;
8981 }
8982 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
8983 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
8984 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
8985
8986 /*
8987 * Now let's create the actual data block for the inode
8988 */
8989 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
8990 if (retval) {
8991 pctx.errcode = retval;
8992 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
8993 return 0;
8994 }
8995
8996 retval = ext2fs_write_dir_block(fs, blk, block);
8997 ext2fs_free_mem(&block);
8998 if (retval) {
8999 pctx.errcode = retval;
9000 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
9001 return 0;
9002 }
9003
9004 /*
9005 * Set up the inode structure
9006 */
9007 memset(&inode, 0, sizeof(inode));
9008 inode.i_mode = 040700;
9009 inode.i_size = fs->blocksize;
9010 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
9011 inode.i_links_count = 2;
9012 inode.i_blocks = fs->blocksize / 512;
9013 inode.i_block[0] = blk;
9014
9015 /*
9016 * Next, write out the inode.
9017 */
9018 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
9019 if (pctx.errcode) {
9020 pctx.str = "ext2fs_write_inode";
9021 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
9022 return 0;
9023 }
9024 /*
9025 * Finally, create the directory link
9026 */
9027 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
9028 if (pctx.errcode) {
9029 pctx.str = "ext2fs_link";
9030 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
9031 return 0;
9032 }
9033
9034 /*
9035 * Miscellaneous bookkeeping that needs to be kept straight.
9036 */
9037 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
9038 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
9039 ext2fs_icount_store(ctx->inode_count, ino, 2);
9040 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
9041 ctx->lost_and_found = ino;
9042#if 0
9043 printf("/lost+found created; inode #%lu\n", ino);
9044#endif
9045 return ino;
9046}
9047
9048/*
9049 * This routine will connect a file to lost+found
9050 */
9051int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
9052{
9053 ext2_filsys fs = ctx->fs;
9054 errcode_t retval;
9055 char name[80];
9056 struct problem_context pctx;
9057 struct ext2_inode inode;
9058 int file_type = 0;
9059
9060 clear_problem_context(&pctx);
9061 pctx.ino = ino;
9062
9063 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
9064 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
9065 ctx->bad_lost_and_found++;
9066 }
9067 if (ctx->bad_lost_and_found) {
9068 fix_problem(ctx, PR_3_NO_LPF, &pctx);
9069 return 1;
9070 }
9071
9072 sprintf(name, "#%u", ino);
9073 if (ext2fs_read_inode(fs, ino, &inode) == 0)
9074 file_type = ext2_file_type(inode.i_mode);
9075 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
9076 if (retval == EXT2_ET_DIR_NO_SPACE) {
9077 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
9078 return 1;
9079 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
9080 1, 0);
9081 if (retval) {
9082 pctx.errcode = retval;
9083 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
9084 return 1;
9085 }
9086 retval = ext2fs_link(fs, ctx->lost_and_found, name,
9087 ino, file_type);
9088 }
9089 if (retval) {
9090 pctx.errcode = retval;
9091 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
9092 return 1;
9093 }
9094 e2fsck_adjust_inode_count(ctx, ino, 1);
9095
9096 return 0;
9097}
9098
9099/*
9100 * Utility routine to adjust the inode counts on an inode.
9101 */
9102errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
9103{
9104 ext2_filsys fs = ctx->fs;
9105 errcode_t retval;
9106 struct ext2_inode inode;
9107
9108 if (!ino)
9109 return 0;
9110
9111 retval = ext2fs_read_inode(fs, ino, &inode);
9112 if (retval)
9113 return retval;
9114
9115#if 0
9116 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
9117 inode.i_links_count);
9118#endif
9119
9120 if (adj == 1) {
9121 ext2fs_icount_increment(ctx->inode_count, ino, 0);
9122 if (inode.i_links_count == (__u16) ~0)
9123 return 0;
9124 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
9125 inode.i_links_count++;
9126 } else if (adj == -1) {
9127 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
9128 if (inode.i_links_count == 0)
9129 return 0;
9130 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
9131 inode.i_links_count--;
9132 }
9133
9134 retval = ext2fs_write_inode(fs, ino, &inode);
9135 if (retval)
9136 return retval;
9137
9138 return 0;
9139}
9140
9141/*
9142 * Fix parent --- this routine fixes up the parent of a directory.
9143 */
9144struct fix_dotdot_struct {
9145 ext2_filsys fs;
9146 ext2_ino_t parent;
9147 int done;
9148 e2fsck_t ctx;
9149};
9150
9151static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00009152 int offset FSCK_ATTR((unused)),
9153 int blocksize FSCK_ATTR((unused)),
9154 char *buf FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009155 void *priv_data)
9156{
9157 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
9158 errcode_t retval;
9159 struct problem_context pctx;
9160
9161 if ((dirent->name_len & 0xFF) != 2)
9162 return 0;
9163 if (strncmp(dirent->name, "..", 2))
9164 return 0;
9165
9166 clear_problem_context(&pctx);
9167
9168 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
9169 if (retval) {
9170 pctx.errcode = retval;
9171 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9172 }
9173 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
9174 if (retval) {
9175 pctx.errcode = retval;
9176 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9177 }
9178 dirent->inode = fp->parent;
9179
9180 fp->done++;
9181 return DIRENT_ABORT | DIRENT_CHANGED;
9182}
9183
9184static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
9185{
9186 ext2_filsys fs = ctx->fs;
9187 errcode_t retval;
9188 struct fix_dotdot_struct fp;
9189 struct problem_context pctx;
9190
9191 fp.fs = fs;
9192 fp.parent = parent;
9193 fp.done = 0;
9194 fp.ctx = ctx;
9195
9196#if 0
9197 printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent);
9198#endif
9199
9200 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
9201 0, fix_dotdot_proc, &fp);
9202 if (retval || !fp.done) {
9203 clear_problem_context(&pctx);
9204 pctx.ino = dir->ino;
9205 pctx.errcode = retval;
9206 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
9207 PR_3_FIX_PARENT_NOFIND, &pctx);
9208 ext2fs_unmark_valid(fs);
9209 }
9210 dir->dotdot = parent;
9211
9212 return;
9213}
9214
9215/*
9216 * These routines are responsible for expanding a /lost+found if it is
9217 * too small.
9218 */
9219
9220struct expand_dir_struct {
9221 int num;
9222 int guaranteed_size;
9223 int newblocks;
9224 int last_block;
9225 errcode_t err;
9226 e2fsck_t ctx;
9227};
9228
9229static int expand_dir_proc(ext2_filsys fs,
9230 blk_t *blocknr,
9231 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00009232 blk_t ref_block FSCK_ATTR((unused)),
9233 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009234 void *priv_data)
9235{
9236 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
9237 blk_t new_blk;
9238 static blk_t last_blk = 0;
9239 char *block;
9240 errcode_t retval;
9241 e2fsck_t ctx;
9242
9243 ctx = es->ctx;
9244
9245 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
9246 return BLOCK_ABORT;
9247
9248 if (blockcnt > 0)
9249 es->last_block = blockcnt;
9250 if (*blocknr) {
9251 last_blk = *blocknr;
9252 return 0;
9253 }
9254 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
9255 &new_blk);
9256 if (retval) {
9257 es->err = retval;
9258 return BLOCK_ABORT;
9259 }
9260 if (blockcnt > 0) {
9261 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
9262 if (retval) {
9263 es->err = retval;
9264 return BLOCK_ABORT;
9265 }
9266 es->num--;
9267 retval = ext2fs_write_dir_block(fs, new_blk, block);
9268 } else {
9269 retval = ext2fs_get_mem(fs->blocksize, &block);
9270 if (retval) {
9271 es->err = retval;
9272 return BLOCK_ABORT;
9273 }
9274 memset(block, 0, fs->blocksize);
9275 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
9276 }
9277 if (retval) {
9278 es->err = retval;
9279 return BLOCK_ABORT;
9280 }
9281 ext2fs_free_mem(&block);
9282 *blocknr = new_blk;
9283 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
9284 ext2fs_block_alloc_stats(fs, new_blk, +1);
9285 es->newblocks++;
9286
9287 if (es->num == 0)
9288 return (BLOCK_CHANGED | BLOCK_ABORT);
9289 else
9290 return BLOCK_CHANGED;
9291}
9292
9293errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
9294 int num, int guaranteed_size)
9295{
9296 ext2_filsys fs = ctx->fs;
9297 errcode_t retval;
9298 struct expand_dir_struct es;
9299 struct ext2_inode inode;
9300
9301 if (!(fs->flags & EXT2_FLAG_RW))
9302 return EXT2_ET_RO_FILSYS;
9303
9304 /*
9305 * Read the inode and block bitmaps in; we'll be messing with
9306 * them.
9307 */
9308 e2fsck_read_bitmaps(ctx);
9309
9310 retval = ext2fs_check_directory(fs, dir);
9311 if (retval)
9312 return retval;
9313
9314 es.num = num;
9315 es.guaranteed_size = guaranteed_size;
9316 es.last_block = 0;
9317 es.err = 0;
9318 es.newblocks = 0;
9319 es.ctx = ctx;
9320
9321 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
9322 0, expand_dir_proc, &es);
9323
9324 if (es.err)
9325 return es.err;
9326
9327 /*
9328 * Update the size and block count fields in the inode.
9329 */
9330 retval = ext2fs_read_inode(fs, dir, &inode);
9331 if (retval)
9332 return retval;
9333
9334 inode.i_size = (es.last_block + 1) * fs->blocksize;
9335 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
9336
9337 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
9338
9339 return 0;
9340}
9341
9342/*
9343 * pass4.c -- pass #4 of e2fsck: Check reference counts
9344 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009345 * Pass 4 frees the following data structures:
9346 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
9347 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
9348 */
9349
9350/*
9351 * This routine is called when an inode is not connected to the
9352 * directory tree.
9353 *
9354 * This subroutine returns 1 then the caller shouldn't bother with the
9355 * rest of the pass 4 tests.
9356 */
9357static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
9358{
9359 ext2_filsys fs = ctx->fs;
9360 struct ext2_inode inode;
9361 struct problem_context pctx;
9362
9363 e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
9364 clear_problem_context(&pctx);
9365 pctx.ino = i;
9366 pctx.inode = &inode;
9367
9368 /*
9369 * Offer to delete any zero-length files that does not have
9370 * blocks. If there is an EA block, it might have useful
9371 * information, so we won't prompt to delete it, but let it be
9372 * reconnected to lost+found.
9373 */
9374 if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
9375 LINUX_S_ISDIR(inode.i_mode))) {
9376 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
9377 ext2fs_icount_store(ctx->inode_link_info, i, 0);
9378 inode.i_links_count = 0;
9379 inode.i_dtime = time(0);
9380 e2fsck_write_inode(ctx, i, &inode,
9381 "disconnect_inode");
9382 /*
9383 * Fix up the bitmaps...
9384 */
9385 e2fsck_read_bitmaps(ctx);
9386 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
9387 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
9388 ext2fs_inode_alloc_stats2(fs, i, -1,
9389 LINUX_S_ISDIR(inode.i_mode));
9390 return 0;
9391 }
9392 }
9393
9394 /*
9395 * Prompt to reconnect.
9396 */
9397 if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
9398 if (e2fsck_reconnect_file(ctx, i))
9399 ext2fs_unmark_valid(fs);
9400 } else {
9401 /*
9402 * If we don't attach the inode, then skip the
9403 * i_links_test since there's no point in trying to
9404 * force i_links_count to zero.
9405 */
9406 ext2fs_unmark_valid(fs);
9407 return 1;
9408 }
9409 return 0;
9410}
9411
9412
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009413static void e2fsck_pass4(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009414{
9415 ext2_filsys fs = ctx->fs;
9416 ext2_ino_t i;
9417 struct ext2_inode inode;
9418#ifdef RESOURCE_TRACK
9419 struct resource_track rtrack;
9420#endif
9421 struct problem_context pctx;
9422 __u16 link_count, link_counted;
9423 char *buf = 0;
9424 int group, maxgroup;
9425
9426#ifdef RESOURCE_TRACK
9427 init_resource_track(&rtrack);
9428#endif
9429
9430#ifdef MTRACE
9431 mtrace_print("Pass 4");
9432#endif
9433
9434 clear_problem_context(&pctx);
9435
9436 if (!(ctx->options & E2F_OPT_PREEN))
9437 fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
9438
9439 group = 0;
9440 maxgroup = fs->group_desc_count;
9441 if (ctx->progress)
9442 if ((ctx->progress)(ctx, 4, 0, maxgroup))
9443 return;
9444
9445 for (i=1; i <= fs->super->s_inodes_count; i++) {
9446 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9447 return;
9448 if ((i % fs->super->s_inodes_per_group) == 0) {
9449 group++;
9450 if (ctx->progress)
9451 if ((ctx->progress)(ctx, 4, group, maxgroup))
9452 return;
9453 }
9454 if (i == EXT2_BAD_INO ||
9455 (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
9456 continue;
9457 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
9458 (ctx->inode_imagic_map &&
9459 ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) ||
9460 (ctx->inode_bb_map &&
9461 ext2fs_test_inode_bitmap(ctx->inode_bb_map, i)))
9462 continue;
9463 ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
9464 ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
9465 if (link_counted == 0) {
9466 if (!buf)
9467 buf = e2fsck_allocate_memory(ctx,
9468 fs->blocksize, "bad_inode buffer");
9469 if (e2fsck_process_bad_inode(ctx, 0, i, buf))
9470 continue;
9471 if (disconnect_inode(ctx, i))
9472 continue;
9473 ext2fs_icount_fetch(ctx->inode_link_info, i,
9474 &link_count);
9475 ext2fs_icount_fetch(ctx->inode_count, i,
9476 &link_counted);
9477 }
9478 if (link_counted != link_count) {
9479 e2fsck_read_inode(ctx, i, &inode, "pass4");
9480 pctx.ino = i;
9481 pctx.inode = &inode;
9482 if (link_count != inode.i_links_count) {
9483 pctx.num = link_count;
9484 fix_problem(ctx,
9485 PR_4_INCONSISTENT_COUNT, &pctx);
9486 }
9487 pctx.num = link_counted;
9488 if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
9489 inode.i_links_count = link_counted;
9490 e2fsck_write_inode(ctx, i, &inode, "pass4");
9491 }
9492 }
9493 }
9494 ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
9495 ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
9496 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
9497 ctx->inode_bb_map = 0;
9498 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
9499 ctx->inode_imagic_map = 0;
9500 if (buf)
9501 ext2fs_free_mem(&buf);
9502#ifdef RESOURCE_TRACK
9503 if (ctx->options & E2F_OPT_TIME2) {
9504 e2fsck_clear_progbar(ctx);
9505 print_resource_track(_("Pass 4"), &rtrack);
9506 }
9507#endif
9508}
9509
9510/*
9511 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009512 */
9513
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009514#define NO_BLK ((blk_t) -1)
9515
9516static void print_bitmap_problem(e2fsck_t ctx, int problem,
9517 struct problem_context *pctx)
9518{
9519 switch (problem) {
9520 case PR_5_BLOCK_UNUSED:
9521 if (pctx->blk == pctx->blk2)
9522 pctx->blk2 = 0;
9523 else
9524 problem = PR_5_BLOCK_RANGE_UNUSED;
9525 break;
9526 case PR_5_BLOCK_USED:
9527 if (pctx->blk == pctx->blk2)
9528 pctx->blk2 = 0;
9529 else
9530 problem = PR_5_BLOCK_RANGE_USED;
9531 break;
9532 case PR_5_INODE_UNUSED:
9533 if (pctx->ino == pctx->ino2)
9534 pctx->ino2 = 0;
9535 else
9536 problem = PR_5_INODE_RANGE_UNUSED;
9537 break;
9538 case PR_5_INODE_USED:
9539 if (pctx->ino == pctx->ino2)
9540 pctx->ino2 = 0;
9541 else
9542 problem = PR_5_INODE_RANGE_USED;
9543 break;
9544 }
9545 fix_problem(ctx, problem, pctx);
9546 pctx->blk = pctx->blk2 = NO_BLK;
9547 pctx->ino = pctx->ino2 = 0;
9548}
9549
9550static void check_block_bitmaps(e2fsck_t ctx)
9551{
9552 ext2_filsys fs = ctx->fs;
9553 blk_t i;
9554 int *free_array;
9555 int group = 0;
9556 unsigned int blocks = 0;
9557 unsigned int free_blocks = 0;
9558 int group_free = 0;
9559 int actual, bitmap;
9560 struct problem_context pctx;
9561 int problem, save_problem, fixit, had_problem;
9562 errcode_t retval;
9563
9564 clear_problem_context(&pctx);
9565 free_array = (int *) e2fsck_allocate_memory(ctx,
9566 fs->group_desc_count * sizeof(int), "free block count array");
9567
9568 if ((fs->super->s_first_data_block <
9569 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
9570 (fs->super->s_blocks_count-1 >
9571 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
9572 pctx.num = 1;
9573 pctx.blk = fs->super->s_first_data_block;
9574 pctx.blk2 = fs->super->s_blocks_count -1;
9575 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
9576 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
9577 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9578
9579 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9580 return;
9581 }
9582
9583 if ((fs->super->s_first_data_block <
9584 ext2fs_get_block_bitmap_start(fs->block_map)) ||
9585 (fs->super->s_blocks_count-1 >
9586 ext2fs_get_block_bitmap_end(fs->block_map))) {
9587 pctx.num = 2;
9588 pctx.blk = fs->super->s_first_data_block;
9589 pctx.blk2 = fs->super->s_blocks_count -1;
9590 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
9591 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
9592 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9593
9594 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9595 return;
9596 }
9597
9598redo_counts:
9599 had_problem = 0;
9600 save_problem = 0;
9601 pctx.blk = pctx.blk2 = NO_BLK;
9602 for (i = fs->super->s_first_data_block;
9603 i < fs->super->s_blocks_count;
9604 i++) {
9605 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
9606 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
9607
9608 if (actual == bitmap)
9609 goto do_counts;
9610
9611 if (!actual && bitmap) {
9612 /*
9613 * Block not used, but marked in use in the bitmap.
9614 */
9615 problem = PR_5_BLOCK_UNUSED;
9616 } else {
9617 /*
9618 * Block used, but not marked in use in the bitmap.
9619 */
9620 problem = PR_5_BLOCK_USED;
9621 }
9622 if (pctx.blk == NO_BLK) {
9623 pctx.blk = pctx.blk2 = i;
9624 save_problem = problem;
9625 } else {
9626 if ((problem == save_problem) &&
9627 (pctx.blk2 == i-1))
9628 pctx.blk2++;
9629 else {
9630 print_bitmap_problem(ctx, save_problem, &pctx);
9631 pctx.blk = pctx.blk2 = i;
9632 save_problem = problem;
9633 }
9634 }
9635 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
9636 had_problem++;
9637
9638 do_counts:
9639 if (!bitmap) {
9640 group_free++;
9641 free_blocks++;
9642 }
9643 blocks ++;
9644 if ((blocks == fs->super->s_blocks_per_group) ||
9645 (i == fs->super->s_blocks_count-1)) {
9646 free_array[group] = group_free;
9647 group ++;
9648 blocks = 0;
9649 group_free = 0;
9650 if (ctx->progress)
9651 if ((ctx->progress)(ctx, 5, group,
9652 fs->group_desc_count*2))
9653 return;
9654 }
9655 }
9656 if (pctx.blk != NO_BLK)
9657 print_bitmap_problem(ctx, save_problem, &pctx);
9658 if (had_problem)
9659 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
9660 else
9661 fixit = -1;
9662 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
9663
9664 if (fixit == 1) {
9665 ext2fs_free_block_bitmap(fs->block_map);
9666 retval = ext2fs_copy_bitmap(ctx->block_found_map,
9667 &fs->block_map);
9668 if (retval) {
9669 clear_problem_context(&pctx);
9670 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
9671 ctx->flags |= E2F_FLAG_ABORT;
9672 return;
9673 }
9674 ext2fs_set_bitmap_padding(fs->block_map);
9675 ext2fs_mark_bb_dirty(fs);
9676
9677 /* Redo the counts */
9678 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
9679 memset(free_array, 0, fs->group_desc_count * sizeof(int));
9680 goto redo_counts;
9681 } else if (fixit == 0)
9682 ext2fs_unmark_valid(fs);
9683
9684 for (i = 0; i < fs->group_desc_count; i++) {
9685 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
9686 pctx.group = i;
9687 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
9688 pctx.blk2 = free_array[i];
9689
9690 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
9691 &pctx)) {
9692 fs->group_desc[i].bg_free_blocks_count =
9693 free_array[i];
9694 ext2fs_mark_super_dirty(fs);
9695 } else
9696 ext2fs_unmark_valid(fs);
9697 }
9698 }
9699 if (free_blocks != fs->super->s_free_blocks_count) {
9700 pctx.group = 0;
9701 pctx.blk = fs->super->s_free_blocks_count;
9702 pctx.blk2 = free_blocks;
9703
9704 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
9705 fs->super->s_free_blocks_count = free_blocks;
9706 ext2fs_mark_super_dirty(fs);
9707 } else
9708 ext2fs_unmark_valid(fs);
9709 }
9710 ext2fs_free_mem(&free_array);
9711}
9712
9713static void check_inode_bitmaps(e2fsck_t ctx)
9714{
9715 ext2_filsys fs = ctx->fs;
9716 ext2_ino_t i;
9717 unsigned int free_inodes = 0;
9718 int group_free = 0;
9719 int dirs_count = 0;
9720 int group = 0;
9721 unsigned int inodes = 0;
9722 int *free_array;
9723 int *dir_array;
9724 int actual, bitmap;
9725 errcode_t retval;
9726 struct problem_context pctx;
9727 int problem, save_problem, fixit, had_problem;
9728
9729 clear_problem_context(&pctx);
9730 free_array = (int *) e2fsck_allocate_memory(ctx,
9731 fs->group_desc_count * sizeof(int), "free inode count array");
9732
9733 dir_array = (int *) e2fsck_allocate_memory(ctx,
9734 fs->group_desc_count * sizeof(int), "directory count array");
9735
9736 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
9737 (fs->super->s_inodes_count >
9738 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
9739 pctx.num = 3;
9740 pctx.blk = 1;
9741 pctx.blk2 = fs->super->s_inodes_count;
9742 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
9743 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
9744 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9745
9746 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9747 return;
9748 }
9749 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
9750 (fs->super->s_inodes_count >
9751 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
9752 pctx.num = 4;
9753 pctx.blk = 1;
9754 pctx.blk2 = fs->super->s_inodes_count;
9755 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
9756 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
9757 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9758
9759 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9760 return;
9761 }
9762
9763redo_counts:
9764 had_problem = 0;
9765 save_problem = 0;
9766 pctx.ino = pctx.ino2 = 0;
9767 for (i = 1; i <= fs->super->s_inodes_count; i++) {
9768 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
9769 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
9770
9771 if (actual == bitmap)
9772 goto do_counts;
9773
9774 if (!actual && bitmap) {
9775 /*
9776 * Inode wasn't used, but marked in bitmap
9777 */
9778 problem = PR_5_INODE_UNUSED;
9779 } else /* if (actual && !bitmap) */ {
9780 /*
9781 * Inode used, but not in bitmap
9782 */
9783 problem = PR_5_INODE_USED;
9784 }
9785 if (pctx.ino == 0) {
9786 pctx.ino = pctx.ino2 = i;
9787 save_problem = problem;
9788 } else {
9789 if ((problem == save_problem) &&
9790 (pctx.ino2 == i-1))
9791 pctx.ino2++;
9792 else {
9793 print_bitmap_problem(ctx, save_problem, &pctx);
9794 pctx.ino = pctx.ino2 = i;
9795 save_problem = problem;
9796 }
9797 }
9798 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
9799 had_problem++;
9800
9801do_counts:
9802 if (!bitmap) {
9803 group_free++;
9804 free_inodes++;
9805 } else {
9806 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
9807 dirs_count++;
9808 }
9809 inodes++;
9810 if ((inodes == fs->super->s_inodes_per_group) ||
9811 (i == fs->super->s_inodes_count)) {
9812 free_array[group] = group_free;
9813 dir_array[group] = dirs_count;
9814 group ++;
9815 inodes = 0;
9816 group_free = 0;
9817 dirs_count = 0;
9818 if (ctx->progress)
9819 if ((ctx->progress)(ctx, 5,
9820 group + fs->group_desc_count,
9821 fs->group_desc_count*2))
9822 return;
9823 }
9824 }
9825 if (pctx.ino)
9826 print_bitmap_problem(ctx, save_problem, &pctx);
9827
9828 if (had_problem)
9829 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
9830 else
9831 fixit = -1;
9832 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
9833
9834 if (fixit == 1) {
9835 ext2fs_free_inode_bitmap(fs->inode_map);
9836 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
9837 &fs->inode_map);
9838 if (retval) {
9839 clear_problem_context(&pctx);
9840 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
9841 ctx->flags |= E2F_FLAG_ABORT;
9842 return;
9843 }
9844 ext2fs_set_bitmap_padding(fs->inode_map);
9845 ext2fs_mark_ib_dirty(fs);
9846
9847 /* redo counts */
9848 inodes = 0; free_inodes = 0; group_free = 0;
9849 dirs_count = 0; group = 0;
9850 memset(free_array, 0, fs->group_desc_count * sizeof(int));
9851 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
9852 goto redo_counts;
9853 } else if (fixit == 0)
9854 ext2fs_unmark_valid(fs);
9855
9856 for (i = 0; i < fs->group_desc_count; i++) {
9857 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
9858 pctx.group = i;
9859 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
9860 pctx.ino2 = free_array[i];
9861 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
9862 &pctx)) {
9863 fs->group_desc[i].bg_free_inodes_count =
9864 free_array[i];
9865 ext2fs_mark_super_dirty(fs);
9866 } else
9867 ext2fs_unmark_valid(fs);
9868 }
9869 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
9870 pctx.group = i;
9871 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
9872 pctx.ino2 = dir_array[i];
9873
9874 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
9875 &pctx)) {
9876 fs->group_desc[i].bg_used_dirs_count =
9877 dir_array[i];
9878 ext2fs_mark_super_dirty(fs);
9879 } else
9880 ext2fs_unmark_valid(fs);
9881 }
9882 }
9883 if (free_inodes != fs->super->s_free_inodes_count) {
9884 pctx.group = -1;
9885 pctx.ino = fs->super->s_free_inodes_count;
9886 pctx.ino2 = free_inodes;
9887
9888 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
9889 fs->super->s_free_inodes_count = free_inodes;
9890 ext2fs_mark_super_dirty(fs);
9891 } else
9892 ext2fs_unmark_valid(fs);
9893 }
9894 ext2fs_free_mem(&free_array);
9895 ext2fs_free_mem(&dir_array);
9896}
9897
9898static void check_inode_end(e2fsck_t ctx)
9899{
9900 ext2_filsys fs = ctx->fs;
9901 ext2_ino_t end, save_inodes_count, i;
9902 struct problem_context pctx;
9903
9904 clear_problem_context(&pctx);
9905
9906 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
9907 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
9908 &save_inodes_count);
9909 if (pctx.errcode) {
9910 pctx.num = 1;
9911 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9912 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9913 return;
9914 }
9915 if (save_inodes_count == end)
9916 return;
9917
9918 for (i = save_inodes_count + 1; i <= end; i++) {
9919 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
9920 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
9921 for (i = save_inodes_count + 1; i <= end; i++)
9922 ext2fs_mark_inode_bitmap(fs->inode_map,
9923 i);
9924 ext2fs_mark_ib_dirty(fs);
9925 } else
9926 ext2fs_unmark_valid(fs);
9927 break;
9928 }
9929 }
9930
9931 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
9932 save_inodes_count, 0);
9933 if (pctx.errcode) {
9934 pctx.num = 2;
9935 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9936 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9937 return;
9938 }
9939}
9940
9941static void check_block_end(e2fsck_t ctx)
9942{
9943 ext2_filsys fs = ctx->fs;
9944 blk_t end, save_blocks_count, i;
9945 struct problem_context pctx;
9946
9947 clear_problem_context(&pctx);
9948
9949 end = fs->block_map->start +
9950 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
9951 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
9952 &save_blocks_count);
9953 if (pctx.errcode) {
9954 pctx.num = 3;
9955 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9956 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9957 return;
9958 }
9959 if (save_blocks_count == end)
9960 return;
9961
9962 for (i = save_blocks_count + 1; i <= end; i++) {
9963 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
9964 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
9965 for (i = save_blocks_count + 1; i <= end; i++)
9966 ext2fs_mark_block_bitmap(fs->block_map,
9967 i);
9968 ext2fs_mark_bb_dirty(fs);
9969 } else
9970 ext2fs_unmark_valid(fs);
9971 break;
9972 }
9973 }
9974
9975 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
9976 save_blocks_count, 0);
9977 if (pctx.errcode) {
9978 pctx.num = 4;
9979 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9980 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9981 return;
9982 }
9983}
9984
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009985static void e2fsck_pass5(e2fsck_t ctx)
9986{
9987#ifdef RESOURCE_TRACK
9988 struct resource_track rtrack;
9989#endif
9990 struct problem_context pctx;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009991
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009992#ifdef MTRACE
9993 mtrace_print("Pass 5");
9994#endif
9995
9996#ifdef RESOURCE_TRACK
9997 init_resource_track(&rtrack);
9998#endif
9999
10000 clear_problem_context(&pctx);
10001
10002 if (!(ctx->options & E2F_OPT_PREEN))
10003 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
10004
10005 if (ctx->progress)
10006 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
10007 return;
10008
10009 e2fsck_read_bitmaps(ctx);
10010
10011 check_block_bitmaps(ctx);
10012 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
10013 return;
10014 check_inode_bitmaps(ctx);
10015 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
10016 return;
10017 check_inode_end(ctx);
10018 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
10019 return;
10020 check_block_end(ctx);
10021 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
10022 return;
10023
10024 ext2fs_free_inode_bitmap(ctx->inode_used_map);
10025 ctx->inode_used_map = 0;
10026 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
10027 ctx->inode_dir_map = 0;
10028 ext2fs_free_block_bitmap(ctx->block_found_map);
10029 ctx->block_found_map = 0;
10030
10031#ifdef RESOURCE_TRACK
10032 if (ctx->options & E2F_OPT_TIME2) {
10033 e2fsck_clear_progbar(ctx);
10034 print_resource_track(_("Pass 5"), &rtrack);
10035 }
10036#endif
10037}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010038
10039/*
10040 * problem.c --- report filesystem problems to the user
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010041 */
10042
10043#define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */
10044#define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */
10045#define PR_NO_DEFAULT 0x000004 /* Default to no */
10046#define PR_MSG_ONLY 0x000008 /* Print message only */
10047
10048/* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */
10049
10050#define PR_FATAL 0x001000 /* Fatal error */
10051#define PR_AFTER_CODE 0x002000 /* After asking the first question, */
10052 /* ask another */
10053#define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */
10054#define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */
10055#define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */
10056#define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */
10057#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
10058
10059
10060#define PROMPT_NONE 0
10061#define PROMPT_FIX 1
10062#define PROMPT_CLEAR 2
10063#define PROMPT_RELOCATE 3
10064#define PROMPT_ALLOCATE 4
10065#define PROMPT_EXPAND 5
10066#define PROMPT_CONNECT 6
10067#define PROMPT_CREATE 7
10068#define PROMPT_SALVAGE 8
10069#define PROMPT_TRUNCATE 9
10070#define PROMPT_CLEAR_INODE 10
10071#define PROMPT_ABORT 11
10072#define PROMPT_SPLIT 12
10073#define PROMPT_CONTINUE 13
10074#define PROMPT_CLONE 14
10075#define PROMPT_DELETE 15
10076#define PROMPT_SUPPRESS 16
10077#define PROMPT_UNLINK 17
10078#define PROMPT_CLEAR_HTREE 18
10079#define PROMPT_RECREATE 19
10080#define PROMPT_NULL 20
10081
10082struct e2fsck_problem {
10083 problem_t e2p_code;
10084 const char * e2p_description;
10085 char prompt;
10086 int flags;
10087 problem_t second_code;
10088};
10089
10090struct latch_descr {
10091 int latch_code;
10092 problem_t question;
10093 problem_t end_message;
10094 int flags;
10095};
10096
10097/*
10098 * These are the prompts which are used to ask the user if they want
10099 * to fix a problem.
10100 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010101static const char * const prompt[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010102 N_("(no prompt)"), /* 0 */
10103 N_("Fix"), /* 1 */
10104 N_("Clear"), /* 2 */
10105 N_("Relocate"), /* 3 */
10106 N_("Allocate"), /* 4 */
10107 N_("Expand"), /* 5 */
10108 N_("Connect to /lost+found"), /* 6 */
10109 N_("Create"), /* 7 */
10110 N_("Salvage"), /* 8 */
10111 N_("Truncate"), /* 9 */
10112 N_("Clear inode"), /* 10 */
10113 N_("Abort"), /* 11 */
10114 N_("Split"), /* 12 */
10115 N_("Continue"), /* 13 */
10116 N_("Clone duplicate/bad blocks"), /* 14 */
10117 N_("Delete file"), /* 15 */
10118 N_("Suppress messages"),/* 16 */
10119 N_("Unlink"), /* 17 */
10120 N_("Clear HTree index"),/* 18 */
10121 N_("Recreate"), /* 19 */
10122 "", /* 20 */
10123};
10124
10125/*
10126 * These messages are printed when we are preen mode and we will be
10127 * automatically fixing the problem.
10128 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010129static const char * const preen_msg[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010130 N_("(NONE)"), /* 0 */
10131 N_("FIXED"), /* 1 */
10132 N_("CLEARED"), /* 2 */
10133 N_("RELOCATED"), /* 3 */
10134 N_("ALLOCATED"), /* 4 */
10135 N_("EXPANDED"), /* 5 */
10136 N_("RECONNECTED"), /* 6 */
10137 N_("CREATED"), /* 7 */
10138 N_("SALVAGED"), /* 8 */
10139 N_("TRUNCATED"), /* 9 */
10140 N_("INODE CLEARED"), /* 10 */
10141 N_("ABORTED"), /* 11 */
10142 N_("SPLIT"), /* 12 */
10143 N_("CONTINUING"), /* 13 */
10144 N_("DUPLICATE/BAD BLOCKS CLONED"), /* 14 */
10145 N_("FILE DELETED"), /* 15 */
10146 N_("SUPPRESSED"), /* 16 */
10147 N_("UNLINKED"), /* 17 */
10148 N_("HTREE INDEX CLEARED"),/* 18 */
10149 N_("WILL RECREATE"), /* 19 */
10150 "", /* 20 */
10151};
10152
10153static const struct e2fsck_problem problem_table[] = {
10154
10155 /* Pre-Pass 1 errors */
10156
10157 /* Block bitmap not in group */
10158 { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
10159 PROMPT_RELOCATE, PR_LATCH_RELOC },
10160
10161 /* Inode bitmap not in group */
10162 { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
10163 PROMPT_RELOCATE, PR_LATCH_RELOC },
10164
10165 /* Inode table not in group */
10166 { PR_0_ITABLE_NOT_GROUP,
10167 N_("@i table for @g %g is not in @g. (@b %b)\n"
10168 "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
10169 PROMPT_RELOCATE, PR_LATCH_RELOC },
10170
10171 /* Superblock corrupt */
10172 { PR_0_SB_CORRUPT,
10173 N_("\nThe @S could not be read or does not describe a correct ext2\n"
10174 "@f. If the @v is valid and it really contains an ext2\n"
10175 "@f (and not swap or ufs or something else), then the @S\n"
10176 "is corrupt, and you might try running e2fsck with an alternate @S:\n"
10177 " e2fsck -b %S <@v>\n\n"),
10178 PROMPT_NONE, PR_FATAL },
10179
10180 /* Filesystem size is wrong */
10181 { PR_0_FS_SIZE_WRONG,
10182 N_("The @f size (according to the @S) is %b @bs\n"
10183 "The physical size of the @v is %c @bs\n"
10184 "Either the @S or the partition table is likely to be corrupt!\n"),
10185 PROMPT_ABORT, 0 },
10186
10187 /* Fragments not supported */
10188 { PR_0_NO_FRAGMENTS,
10189 N_("@S @b_size = %b, fragsize = %c.\n"
10190 "This version of e2fsck does not support fragment sizes different\n"
10191 "from the @b size.\n"),
10192 PROMPT_NONE, PR_FATAL },
10193
10194 /* Bad blocks_per_group */
10195 { PR_0_BLOCKS_PER_GROUP,
10196 N_("@S @bs_per_group = %b, should have been %c\n"),
10197 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10198
10199 /* Bad first_data_block */
10200 { PR_0_FIRST_DATA_BLOCK,
10201 N_("@S first_data_@b = %b, should have been %c\n"),
10202 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10203
10204 /* Adding UUID to filesystem */
10205 { PR_0_ADD_UUID,
10206 N_("@f did not have a UUID; generating one.\n\n"),
10207 PROMPT_NONE, 0 },
10208
10209 /* Relocate hint */
10210 { PR_0_RELOCATE_HINT,
10211 N_("Note: if there is several inode or block bitmap blocks\n"
10212 "which require relocation, or one part of the inode table\n"
10213 "which must be moved, you may wish to try running e2fsck\n"
10214 "with the '-b %S' option first. The problem may lie only\n"
10215 "with the primary block group descriptor, and the backup\n"
10216 "block group descriptor may be OK.\n\n"),
10217 PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
10218
10219 /* Miscellaneous superblock corruption */
10220 { PR_0_MISC_CORRUPT_SUPER,
10221 N_("Corruption found in @S. (%s = %N).\n"),
10222 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10223
10224 /* Error determing physical device size of filesystem */
10225 { PR_0_GETSIZE_ERROR,
10226 N_("Error determining size of the physical @v: %m\n"),
10227 PROMPT_NONE, PR_FATAL },
10228
10229 /* Inode count in superblock is incorrect */
10230 { PR_0_INODE_COUNT_WRONG,
10231 N_("@i count in @S is %i, should be %j.\n"),
10232 PROMPT_FIX, 0 },
10233
10234 { PR_0_HURD_CLEAR_FILETYPE,
10235 N_("The Hurd does not support the filetype feature.\n"),
10236 PROMPT_CLEAR, 0 },
10237
10238 /* Journal inode is invalid */
10239 { PR_0_JOURNAL_BAD_INODE,
10240 N_("@S has a bad ext3 @j (@i %i).\n"),
10241 PROMPT_CLEAR, PR_PREEN_OK },
10242
10243 /* The external journal has (unsupported) multiple filesystems */
10244 { PR_0_JOURNAL_UNSUPP_MULTIFS,
10245 N_("External @j has multiple @f users (unsupported).\n"),
10246 PROMPT_NONE, PR_FATAL },
10247
10248 /* Can't find external journal */
10249 { PR_0_CANT_FIND_JOURNAL,
10250 N_("Can't find external @j\n"),
10251 PROMPT_NONE, PR_FATAL },
10252
10253 /* External journal has bad superblock */
10254 { PR_0_EXT_JOURNAL_BAD_SUPER,
10255 N_("External @j has bad @S\n"),
10256 PROMPT_NONE, PR_FATAL },
10257
10258 /* Superblock has a bad journal UUID */
10259 { PR_0_JOURNAL_BAD_UUID,
10260 N_("External @j does not support this @f\n"),
10261 PROMPT_NONE, PR_FATAL },
10262
10263 /* Journal has an unknown superblock type */
10264 { PR_0_JOURNAL_UNSUPP_SUPER,
10265 N_("Ext3 @j @S is unknown type %N (unsupported).\n"
10266 "It is likely that your copy of e2fsck is old and/or doesn't "
10267 "support this @j format.\n"
10268 "It is also possible the @j @S is corrupt.\n"),
10269 PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
10270
10271 /* Journal superblock is corrupt */
10272 { PR_0_JOURNAL_BAD_SUPER,
10273 N_("Ext3 @j @S is corrupt.\n"),
10274 PROMPT_FIX, PR_PREEN_OK },
10275
10276 /* Superblock flag should be cleared */
10277 { PR_0_JOURNAL_HAS_JOURNAL,
10278 N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
10279 PROMPT_CLEAR, PR_PREEN_OK },
10280
10281 /* Superblock flag is incorrect */
10282 { PR_0_JOURNAL_RECOVER_SET,
10283 N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
10284 PROMPT_CLEAR, PR_PREEN_OK },
10285
10286 /* Journal has data, but recovery flag is clear */
10287 { PR_0_JOURNAL_RECOVERY_CLEAR,
10288 N_("ext3 recovery flag clear, but @j has data.\n"),
10289 PROMPT_NONE, 0 },
10290
10291 /* Ask if we should clear the journal */
10292 { PR_0_JOURNAL_RESET_JOURNAL,
10293 N_("Clear @j"),
10294 PROMPT_NULL, PR_PREEN_NOMSG },
10295
10296 /* Ask if we should run the journal anyway */
10297 { PR_0_JOURNAL_RUN,
10298 N_("Run @j anyway"),
10299 PROMPT_NULL, 0 },
10300
10301 /* Run the journal by default */
10302 { PR_0_JOURNAL_RUN_DEFAULT,
10303 N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
10304 PROMPT_NONE, 0 },
10305
10306 /* Clearing orphan inode */
10307 { PR_0_ORPHAN_CLEAR_INODE,
10308 N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
10309 PROMPT_NONE, 0 },
10310
10311 /* Illegal block found in orphaned inode */
10312 { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
10313 N_("@I @b #%B (%b) found in @o @i %i.\n"),
10314 PROMPT_NONE, 0 },
10315
10316 /* Already cleared block found in orphaned inode */
10317 { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
10318 N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
10319 PROMPT_NONE, 0 },
10320
10321 /* Illegal orphan inode in superblock */
10322 { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
10323 N_("@I @o @i %i in @S.\n"),
10324 PROMPT_NONE, 0 },
10325
10326 /* Illegal inode in orphaned inode list */
10327 { PR_0_ORPHAN_ILLEGAL_INODE,
10328 N_("@I @i %i in @o @i list.\n"),
10329 PROMPT_NONE, 0 },
10330
10331 /* Filesystem revision is 0, but feature flags are set */
10332 { PR_0_FS_REV_LEVEL,
10333 "@f has feature flag(s) set, but is a revision 0 @f. ",
10334 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10335
10336 /* Journal superblock has an unknown read-only feature flag set */
10337 { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
10338 N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
10339 PROMPT_ABORT, 0 },
10340
10341 /* Journal superblock has an unknown incompatible feature flag set */
10342 { PR_0_JOURNAL_UNSUPP_INCOMPAT,
10343 N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
10344 PROMPT_ABORT, 0 },
10345
10346 /* Journal has unsupported version number */
10347 { PR_0_JOURNAL_UNSUPP_VERSION,
10348 N_("@j version not supported by this e2fsck.\n"),
10349 PROMPT_ABORT, 0 },
10350
10351 /* Moving journal to hidden file */
10352 { PR_0_MOVE_JOURNAL,
10353 N_("Moving @j from /%s to hidden inode.\n\n"),
10354 PROMPT_NONE, 0 },
10355
10356 /* Error moving journal to hidden file */
10357 { PR_0_ERR_MOVE_JOURNAL,
10358 N_("Error moving @j: %m\n\n"),
10359 PROMPT_NONE, 0 },
10360
10361 /* Clearing V2 journal superblock */
10362 { PR_0_CLEAR_V2_JOURNAL,
10363 N_("Found invalid V2 @j @S fields (from V1 journal).\n"
10364 "Clearing fields beyond the V1 @j @S...\n\n"),
10365 PROMPT_NONE, 0 },
10366
10367 /* Backup journal inode blocks */
10368 { PR_0_BACKUP_JNL,
10369 N_("Backing up @j @i @b information.\n\n"),
10370 PROMPT_NONE, 0 },
10371
10372 /* Reserved blocks w/o resize_inode */
10373 { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
10374 N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
10375 "is %N; @s zero. "),
10376 PROMPT_FIX, 0 },
10377
10378 /* Resize_inode not enabled, but resize inode is non-zero */
10379 { PR_0_CLEAR_RESIZE_INODE,
10380 N_("Resize_@i not enabled, but the resize inode is non-zero. "),
10381 PROMPT_CLEAR, 0 },
10382
10383 /* Resize inode invalid */
10384 { PR_0_RESIZE_INODE_INVALID,
10385 N_("Resize @i not valid. "),
10386 PROMPT_RECREATE, 0 },
10387
10388 /* Pass 1 errors */
10389
10390 /* Pass 1: Checking inodes, blocks, and sizes */
10391 { PR_1_PASS_HEADER,
10392 N_("Pass 1: Checking @is, @bs, and sizes\n"),
10393 PROMPT_NONE, 0 },
10394
10395 /* Root directory is not an inode */
10396 { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
10397 PROMPT_CLEAR, 0 },
10398
10399 /* Root directory has dtime set */
10400 { PR_1_ROOT_DTIME,
10401 N_("@r has dtime set (probably due to old mke2fs). "),
10402 PROMPT_FIX, PR_PREEN_OK },
10403
10404 /* Reserved inode has bad mode */
10405 { PR_1_RESERVED_BAD_MODE,
10406 N_("Reserved @i %i %Q has bad mode. "),
10407 PROMPT_CLEAR, PR_PREEN_OK },
10408
10409 /* Deleted inode has zero dtime */
10410 { PR_1_ZERO_DTIME,
10411 N_("@D @i %i has zero dtime. "),
10412 PROMPT_FIX, PR_PREEN_OK },
10413
10414 /* Inode in use, but dtime set */
10415 { PR_1_SET_DTIME,
10416 N_("@i %i is in use, but has dtime set. "),
10417 PROMPT_FIX, PR_PREEN_OK },
10418
10419 /* Zero-length directory */
10420 { PR_1_ZERO_LENGTH_DIR,
10421 N_("@i %i is a @z @d. "),
10422 PROMPT_CLEAR, PR_PREEN_OK },
10423
10424 /* Block bitmap conflicts with some other fs block */
10425 { PR_1_BB_CONFLICT,
10426 N_("@g %g's @b @B at %b @C.\n"),
10427 PROMPT_RELOCATE, 0 },
10428
10429 /* Inode bitmap conflicts with some other fs block */
10430 { PR_1_IB_CONFLICT,
10431 N_("@g %g's @i @B at %b @C.\n"),
10432 PROMPT_RELOCATE, 0 },
10433
10434 /* Inode table conflicts with some other fs block */
10435 { PR_1_ITABLE_CONFLICT,
10436 N_("@g %g's @i table at %b @C.\n"),
10437 PROMPT_RELOCATE, 0 },
10438
10439 /* Block bitmap is on a bad block */
10440 { PR_1_BB_BAD_BLOCK,
10441 N_("@g %g's @b @B (%b) is bad. "),
10442 PROMPT_RELOCATE, 0 },
10443
10444 /* Inode bitmap is on a bad block */
10445 { PR_1_IB_BAD_BLOCK,
10446 N_("@g %g's @i @B (%b) is bad. "),
10447 PROMPT_RELOCATE, 0 },
10448
10449 /* Inode has incorrect i_size */
10450 { PR_1_BAD_I_SIZE,
10451 N_("@i %i, i_size is %Is, @s %N. "),
10452 PROMPT_FIX, PR_PREEN_OK },
10453
10454 /* Inode has incorrect i_blocks */
10455 { PR_1_BAD_I_BLOCKS,
10456 N_("@i %i, i_@bs is %Ib, @s %N. "),
10457 PROMPT_FIX, PR_PREEN_OK },
10458
10459 /* Illegal blocknumber in inode */
10460 { PR_1_ILLEGAL_BLOCK_NUM,
10461 N_("@I @b #%B (%b) in @i %i. "),
10462 PROMPT_CLEAR, PR_LATCH_BLOCK },
10463
10464 /* Block number overlaps fs metadata */
10465 { PR_1_BLOCK_OVERLAPS_METADATA,
10466 N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
10467 PROMPT_CLEAR, PR_LATCH_BLOCK },
10468
10469 /* Inode has illegal blocks (latch question) */
10470 { PR_1_INODE_BLOCK_LATCH,
10471 N_("@i %i has illegal @b(s). "),
10472 PROMPT_CLEAR, 0 },
10473
10474 /* Too many bad blocks in inode */
10475 { PR_1_TOO_MANY_BAD_BLOCKS,
10476 N_("Too many illegal @bs in @i %i.\n"),
10477 PROMPT_CLEAR_INODE, PR_NO_OK },
10478
10479 /* Illegal block number in bad block inode */
10480 { PR_1_BB_ILLEGAL_BLOCK_NUM,
10481 N_("@I @b #%B (%b) in bad @b @i. "),
10482 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10483
10484 /* Bad block inode has illegal blocks (latch question) */
10485 { PR_1_INODE_BBLOCK_LATCH,
10486 N_("Bad @b @i has illegal @b(s). "),
10487 PROMPT_CLEAR, 0 },
10488
10489 /* Duplicate or bad blocks in use! */
10490 { PR_1_DUP_BLOCKS_PREENSTOP,
10491 N_("Duplicate or bad @b in use!\n"),
10492 PROMPT_NONE, 0 },
10493
10494 /* Bad block used as bad block indirect block */
10495 { PR_1_BBINODE_BAD_METABLOCK,
10496 N_("Bad @b %b used as bad @b @i indirect @b. "),
10497 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10498
10499 /* Inconsistency can't be fixed prompt */
10500 { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
10501 N_("\nThe bad @b @i has probably been corrupted. You probably\n"
10502 "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
10503 "in the @f.\n"),
10504 PROMPT_CONTINUE, PR_PREEN_NOMSG },
10505
10506 /* Bad primary block */
10507 { PR_1_BAD_PRIMARY_BLOCK,
10508 N_("\nIf the @b is really bad, the @f can not be fixed.\n"),
10509 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
10510
10511 /* Bad primary block prompt */
10512 { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
10513 N_("You can clear the this @b (and hope for the best) from the\n"
10514 "bad @b list and hope that @b is really OK, but there are no\n"
10515 "guarantees.\n\n"),
10516 PROMPT_CLEAR, PR_PREEN_NOMSG },
10517
10518 /* Bad primary superblock */
10519 { PR_1_BAD_PRIMARY_SUPERBLOCK,
10520 N_("The primary @S (%b) is on the bad @b list.\n"),
10521 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10522
10523 /* Bad primary block group descriptors */
10524 { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
10525 N_("Block %b in the primary @g descriptors "
10526 "is on the bad @b list\n"),
10527 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10528
10529 /* Bad superblock in group */
10530 { PR_1_BAD_SUPERBLOCK,
10531 N_("Warning: Group %g's @S (%b) is bad.\n"),
10532 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10533
10534 /* Bad block group descriptors in group */
10535 { PR_1_BAD_GROUP_DESCRIPTORS,
10536 N_("Warning: Group %g's copy of the @g descriptors has a bad "
10537 "@b (%b).\n"),
10538 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10539
10540 /* Block claimed for no reason */
10541 { PR_1_PROGERR_CLAIMED_BLOCK,
10542 N_("Programming error? @b #%b claimed for no reason in "
10543 "process_bad_@b.\n"),
10544 PROMPT_NONE, PR_PREEN_OK },
10545
10546 /* Error allocating blocks for relocating metadata */
10547 { PR_1_RELOC_BLOCK_ALLOCATE,
10548 N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
10549 PROMPT_NONE, PR_PREEN_OK },
10550
10551 /* Error allocating block buffer during relocation process */
10552 { PR_1_RELOC_MEMORY_ALLOCATE,
10553 N_("@A @b buffer for relocating %s\n"),
10554 PROMPT_NONE, PR_PREEN_OK },
10555
10556 /* Relocating metadata group information from X to Y */
10557 { PR_1_RELOC_FROM_TO,
10558 N_("Relocating @g %g's %s from %b to %c...\n"),
10559 PROMPT_NONE, PR_PREEN_OK },
10560
10561 /* Relocating metatdata group information to X */
10562 { PR_1_RELOC_TO,
10563 N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
10564 PROMPT_NONE, PR_PREEN_OK },
10565
10566 /* Block read error during relocation process */
10567 { PR_1_RELOC_READ_ERR,
10568 N_("Warning: could not read @b %b of %s: %m\n"),
10569 PROMPT_NONE, PR_PREEN_OK },
10570
10571 /* Block write error during relocation process */
10572 { PR_1_RELOC_WRITE_ERR,
10573 N_("Warning: could not write @b %b for %s: %m\n"),
10574 PROMPT_NONE, PR_PREEN_OK },
10575
10576 /* Error allocating inode bitmap */
10577 { PR_1_ALLOCATE_IBITMAP_ERROR,
10578 "@A @i @B (%N): %m\n",
10579 PROMPT_NONE, PR_FATAL },
10580
10581 /* Error allocating block bitmap */
10582 { PR_1_ALLOCATE_BBITMAP_ERROR,
10583 "@A @b @B (%N): %m\n",
10584 PROMPT_NONE, PR_FATAL },
10585
10586 /* Error allocating icount structure */
10587 { PR_1_ALLOCATE_ICOUNT,
10588 N_("@A icount link information: %m\n"),
10589 PROMPT_NONE, PR_FATAL },
10590
10591 /* Error allocating dbcount */
10592 { PR_1_ALLOCATE_DBCOUNT,
10593 N_("@A @d @b array: %m\n"),
10594 PROMPT_NONE, PR_FATAL },
10595
10596 /* Error while scanning inodes */
10597 { PR_1_ISCAN_ERROR,
10598 N_("Error while scanning @is (%i): %m\n"),
10599 PROMPT_NONE, PR_FATAL },
10600
10601 /* Error while iterating over blocks */
10602 { PR_1_BLOCK_ITERATE,
10603 N_("Error while iterating over @bs in @i %i: %m\n"),
10604 PROMPT_NONE, PR_FATAL },
10605
10606 /* Error while storing inode count information */
10607 { PR_1_ICOUNT_STORE,
10608 N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
10609 PROMPT_NONE, PR_FATAL },
10610
10611 /* Error while storing directory block information */
10612 { PR_1_ADD_DBLOCK,
10613 N_("Error storing @d @b information "
10614 "(@i=%i, @b=%b, num=%N): %m\n"),
10615 PROMPT_NONE, PR_FATAL },
10616
10617 /* Error while reading inode (for clearing) */
10618 { PR_1_READ_INODE,
10619 N_("Error reading @i %i: %m\n"),
10620 PROMPT_NONE, PR_FATAL },
10621
10622 /* Suppress messages prompt */
10623 { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
10624
10625 /* Imagic flag set on an inode when filesystem doesn't support it */
10626 { PR_1_SET_IMAGIC,
10627 N_("@i %i has imagic flag set. "),
10628 PROMPT_CLEAR, 0 },
10629
10630 /* Immutable flag set on a device or socket inode */
10631 { PR_1_SET_IMMUTABLE,
10632 N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
10633 "or append-only flag set. "),
10634 PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
10635
10636 /* Compression flag set on an inode when filesystem doesn't support it */
10637 { PR_1_COMPR_SET,
10638 N_("@i %i has @cion flag set on @f without @cion support. "),
10639 PROMPT_CLEAR, 0 },
10640
10641 /* Non-zero size for device, fifo or socket inode */
10642 { PR_1_SET_NONZSIZE,
10643 "Special (@v/socket/fifo) @i %i has non-zero size. ",
10644 PROMPT_FIX, PR_PREEN_OK },
10645
10646 /* Filesystem revision is 0, but feature flags are set */
10647 { PR_1_FS_REV_LEVEL,
10648 "@f has feature flag(s) set, but is a revision 0 @f. ",
10649 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10650
10651 /* Journal inode is not in use, but contains data */
10652 { PR_1_JOURNAL_INODE_NOT_CLEAR,
10653 "@j @i is not in use, but contains data. ",
10654 PROMPT_CLEAR, PR_PREEN_OK },
10655
10656 /* Journal has bad mode */
10657 { PR_1_JOURNAL_BAD_MODE,
10658 N_("@j is not regular file. "),
10659 PROMPT_FIX, PR_PREEN_OK },
10660
10661 /* Deal with inodes that were part of orphan linked list */
10662 { PR_1_LOW_DTIME,
10663 N_("@i %i was part of the orphaned @i list. "),
10664 PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
10665
10666 /* Deal with inodes that were part of corrupted orphan linked
10667 list (latch question) */
10668 { PR_1_ORPHAN_LIST_REFUGEES,
10669 N_("@is that were part of a corrupted orphan linked list found. "),
10670 PROMPT_FIX, 0 },
10671
10672 /* Error allocating refcount structure */
10673 { PR_1_ALLOCATE_REFCOUNT,
10674 "@A refcount structure (%N): %m\n",
10675 PROMPT_NONE, PR_FATAL },
10676
10677 /* Error reading extended attribute block */
10678 { PR_1_READ_EA_BLOCK,
10679 N_("Error reading @a @b %b for @i %i. "),
10680 PROMPT_CLEAR, 0 },
10681
10682 /* Invalid extended attribute block */
10683 { PR_1_BAD_EA_BLOCK,
10684 N_("@i %i has a bad @a @b %b. "),
10685 PROMPT_CLEAR, 0 },
10686
10687 /* Error reading Extended Attribute block while fixing refcount */
10688 { PR_1_EXTATTR_READ_ABORT,
10689 N_("Error reading @a @b %b (%m). "),
10690 PROMPT_ABORT, 0 },
10691
10692 /* Extended attribute reference count incorrect */
10693 { PR_1_EXTATTR_REFCOUNT,
10694 N_("@a @b %b has reference count %B, should be %N. "),
10695 PROMPT_FIX, 0 },
10696
10697 /* Error writing Extended Attribute block while fixing refcount */
10698 { PR_1_EXTATTR_WRITE,
10699 N_("Error writing @a @b %b (%m). "),
10700 PROMPT_ABORT, 0 },
10701
10702 /* Multiple EA blocks not supported */
10703 { PR_1_EA_MULTI_BLOCK,
10704 N_("@a @b %b has h_blocks > 1. "),
10705 PROMPT_CLEAR, 0},
10706
10707 /* Error allocating EA region allocation structure */
10708 { PR_1_EA_ALLOC_REGION,
10709 N_("Error allocating @a @b %b. "),
10710 PROMPT_ABORT, 0},
10711
10712 /* Error EA allocation collision */
10713 { PR_1_EA_ALLOC_COLLISION,
10714 N_("@a @b %b is corrupt (allocation collision). "),
10715 PROMPT_CLEAR, 0},
10716
10717 /* Bad extended attribute name */
10718 { PR_1_EA_BAD_NAME,
10719 N_("@a @b %b is corrupt (invalid name). "),
10720 PROMPT_CLEAR, 0},
10721
10722 /* Bad extended attribute value */
10723 { PR_1_EA_BAD_VALUE,
10724 N_("@a @b %b is corrupt (invalid value). "),
10725 PROMPT_CLEAR, 0},
10726
10727 /* Inode too big (latch question) */
10728 { PR_1_INODE_TOOBIG,
10729 N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
10730
10731 /* Directory too big */
10732 { PR_1_TOOBIG_DIR,
10733 N_("@b #%B (%b) causes @d to be too big. "),
10734 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10735
10736 /* Regular file too big */
10737 { PR_1_TOOBIG_REG,
10738 N_("@b #%B (%b) causes file to be too big. "),
10739 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10740
10741 /* Symlink too big */
10742 { PR_1_TOOBIG_SYMLINK,
10743 N_("@b #%B (%b) causes symlink to be too big. "),
10744 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10745
10746 /* INDEX_FL flag set on a non-HTREE filesystem */
10747 { PR_1_HTREE_SET,
10748 N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
10749 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10750
10751 /* INDEX_FL flag set on a non-directory */
10752 { PR_1_HTREE_NODIR,
10753 N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
10754 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10755
10756 /* Invalid root node in HTREE directory */
10757 { PR_1_HTREE_BADROOT,
10758 N_("@h %i has an invalid root node.\n"),
10759 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10760
10761 /* Unsupported hash version in HTREE directory */
10762 { PR_1_HTREE_HASHV,
10763 N_("@h %i has an unsupported hash version (%N)\n"),
10764 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10765
10766 /* Incompatible flag in HTREE root node */
10767 { PR_1_HTREE_INCOMPAT,
10768 N_("@h %i uses an incompatible htree root node flag.\n"),
10769 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10770
10771 /* HTREE too deep */
10772 { PR_1_HTREE_DEPTH,
10773 N_("@h %i has a tree depth (%N) which is too big\n"),
10774 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10775
10776 /* Bad block has indirect block that conflicts with filesystem block */
10777 { PR_1_BB_FS_BLOCK,
10778 N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
10779 "@f metadata. "),
10780 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10781
10782 /* Resize inode failed */
10783 { PR_1_RESIZE_INODE_CREATE,
10784 N_("Resize @i (re)creation failed: %m."),
10785 PROMPT_ABORT, 0 },
10786
10787 /* invalid inode->i_extra_isize */
10788 { PR_1_EXTRA_ISIZE,
10789 N_("@i %i has a extra size (%IS) which is invalid\n"),
10790 PROMPT_FIX, PR_PREEN_OK },
10791
10792 /* invalid ea entry->e_name_len */
10793 { PR_1_ATTR_NAME_LEN,
10794 N_("@a in @i %i has a namelen (%N) which is invalid\n"),
10795 PROMPT_CLEAR, PR_PREEN_OK },
10796
10797 /* invalid ea entry->e_value_size */
10798 { PR_1_ATTR_VALUE_SIZE,
10799 N_("@a in @i %i has a value size (%N) which is invalid\n"),
10800 PROMPT_CLEAR, PR_PREEN_OK },
10801
10802 /* invalid ea entry->e_value_offs */
10803 { PR_1_ATTR_VALUE_OFFSET,
10804 N_("@a in @i %i has a value offset (%N) which is invalid\n"),
10805 PROMPT_CLEAR, PR_PREEN_OK },
10806
10807 /* invalid ea entry->e_value_block */
10808 { PR_1_ATTR_VALUE_BLOCK,
10809 N_("@a in @i %i has a value block (%N) which is invalid (must be 0)\n"),
10810 PROMPT_CLEAR, PR_PREEN_OK },
10811
10812 /* invalid ea entry->e_hash */
10813 { PR_1_ATTR_HASH,
10814 N_("@a in @i %i has a hash (%N) which is invalid (must be 0)\n"),
10815 PROMPT_CLEAR, PR_PREEN_OK },
10816
10817 /* Pass 1b errors */
10818
10819 /* Pass 1B: Rescan for duplicate/bad blocks */
10820 { PR_1B_PASS_HEADER,
10821 N_("Duplicate @bs found... invoking duplicate @b passes.\n"
10822 "Pass 1B: Rescan for duplicate/bad @bs\n"),
10823 PROMPT_NONE, 0 },
10824
10825 /* Duplicate/bad block(s) header */
10826 { PR_1B_DUP_BLOCK_HEADER,
10827 N_("Duplicate/bad @b(s) in @i %i:"),
10828 PROMPT_NONE, 0 },
10829
10830 /* Duplicate/bad block(s) in inode */
10831 { PR_1B_DUP_BLOCK,
10832 " %b",
10833 PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
10834
10835 /* Duplicate/bad block(s) end */
10836 { PR_1B_DUP_BLOCK_END,
10837 "\n",
10838 PROMPT_NONE, PR_PREEN_NOHDR },
10839
10840 /* Error while scanning inodes */
10841 { PR_1B_ISCAN_ERROR,
10842 N_("Error while scanning inodes (%i): %m\n"),
10843 PROMPT_NONE, PR_FATAL },
10844
10845 /* Error allocating inode bitmap */
10846 { PR_1B_ALLOCATE_IBITMAP_ERROR,
10847 N_("@A @i @B (inode_dup_map): %m\n"),
10848 PROMPT_NONE, PR_FATAL },
10849
10850 /* Error while iterating over blocks */
10851 { PR_1B_BLOCK_ITERATE,
10852 N_("Error while iterating over @bs in @i %i (%s): %m\n"),
10853 PROMPT_NONE, 0 },
10854
10855 /* Error adjusting EA refcount */
10856 { PR_1B_ADJ_EA_REFCOUNT,
10857 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
10858 PROMPT_NONE, 0 },
10859
10860
10861 /* Pass 1C: Scan directories for inodes with dup blocks. */
10862 { PR_1C_PASS_HEADER,
10863 N_("Pass 1C: Scan directories for @is with dup @bs.\n"),
10864 PROMPT_NONE, 0 },
10865
10866
10867 /* Pass 1D: Reconciling duplicate blocks */
10868 { PR_1D_PASS_HEADER,
10869 N_("Pass 1D: Reconciling duplicate @bs\n"),
10870 PROMPT_NONE, 0 },
10871
10872 /* File has duplicate blocks */
10873 { PR_1D_DUP_FILE,
10874 N_("File %Q (@i #%i, mod time %IM) \n"
10875 " has %B duplicate @b(s), shared with %N file(s):\n"),
10876 PROMPT_NONE, 0 },
10877
10878 /* List of files sharing duplicate blocks */
10879 { PR_1D_DUP_FILE_LIST,
10880 N_("\t%Q (@i #%i, mod time %IM)\n"),
10881 PROMPT_NONE, 0 },
10882
10883 /* File sharing blocks with filesystem metadata */
10884 { PR_1D_SHARE_METADATA,
10885 N_("\t<@f metadata>\n"),
10886 PROMPT_NONE, 0 },
10887
10888 /* Report of how many duplicate/bad inodes */
10889 { PR_1D_NUM_DUP_INODES,
10890 N_("(There are %N @is containing duplicate/bad @bs.)\n\n"),
10891 PROMPT_NONE, 0 },
10892
10893 /* Duplicated blocks already reassigned or cloned. */
10894 { PR_1D_DUP_BLOCKS_DEALT,
10895 N_("Duplicated @bs already reassigned or cloned.\n\n"),
10896 PROMPT_NONE, 0 },
10897
10898 /* Clone duplicate/bad blocks? */
10899 { PR_1D_CLONE_QUESTION,
10900 "", PROMPT_CLONE, PR_NO_OK },
10901
10902 /* Delete file? */
10903 { PR_1D_DELETE_QUESTION,
10904 "", PROMPT_DELETE, 0 },
10905
10906 /* Couldn't clone file (error) */
10907 { PR_1D_CLONE_ERROR,
10908 N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
10909
10910 /* Pass 2 errors */
10911
10912 /* Pass 2: Checking directory structure */
10913 { PR_2_PASS_HEADER,
10914 N_("Pass 2: Checking @d structure\n"),
10915 PROMPT_NONE, 0 },
10916
10917 /* Bad inode number for '.' */
10918 { PR_2_BAD_INODE_DOT,
10919 N_("Bad @i number for '.' in @d @i %i.\n"),
10920 PROMPT_FIX, 0 },
10921
10922 /* Directory entry has bad inode number */
10923 { PR_2_BAD_INO,
10924 N_("@E has bad @i #: %Di.\n"),
10925 PROMPT_CLEAR, 0 },
10926
10927 /* Directory entry has deleted or unused inode */
10928 { PR_2_UNUSED_INODE,
10929 N_("@E has @D/unused @i %Di. "),
10930 PROMPT_CLEAR, PR_PREEN_OK },
10931
10932 /* Directry entry is link to '.' */
10933 { PR_2_LINK_DOT,
10934 N_("@E @L to '.' "),
10935 PROMPT_CLEAR, 0 },
10936
10937 /* Directory entry points to inode now located in a bad block */
10938 { PR_2_BB_INODE,
10939 N_("@E points to @i (%Di) located in a bad @b.\n"),
10940 PROMPT_CLEAR, 0 },
10941
10942 /* Directory entry contains a link to a directory */
10943 { PR_2_LINK_DIR,
10944 N_("@E @L to @d %P (%Di).\n"),
10945 PROMPT_CLEAR, 0 },
10946
10947 /* Directory entry contains a link to the root directry */
10948 { PR_2_LINK_ROOT,
10949 N_("@E @L to the @r.\n"),
10950 PROMPT_CLEAR, 0 },
10951
10952 /* Directory entry has illegal characters in its name */
10953 { PR_2_BAD_NAME,
10954 N_("@E has illegal characters in its name.\n"),
10955 PROMPT_FIX, 0 },
10956
10957 /* Missing '.' in directory inode */
10958 { PR_2_MISSING_DOT,
10959 N_("Missing '.' in @d @i %i.\n"),
10960 PROMPT_FIX, 0 },
10961
10962 /* Missing '..' in directory inode */
10963 { PR_2_MISSING_DOT_DOT,
10964 N_("Missing '..' in @d @i %i.\n"),
10965 PROMPT_FIX, 0 },
10966
10967 /* First entry in directory inode doesn't contain '.' */
10968 { PR_2_1ST_NOT_DOT,
10969 N_("First @e '%Dn' (inode=%Di) in @d @i %i (%p) @s '.'\n"),
10970 PROMPT_FIX, 0 },
10971
10972 /* Second entry in directory inode doesn't contain '..' */
10973 { PR_2_2ND_NOT_DOT_DOT,
10974 N_("Second @e '%Dn' (inode=%Di) in @d @i %i @s '..'\n"),
10975 PROMPT_FIX, 0 },
10976
10977 /* i_faddr should be zero */
10978 { PR_2_FADDR_ZERO,
10979 N_("i_faddr @F %IF, @s zero.\n"),
10980 PROMPT_CLEAR, 0 },
10981
10982 /* i_file_acl should be zero */
10983 { PR_2_FILE_ACL_ZERO,
10984 N_("i_file_acl @F %If, @s zero.\n"),
10985 PROMPT_CLEAR, 0 },
10986
10987 /* i_dir_acl should be zero */
10988 { PR_2_DIR_ACL_ZERO,
10989 N_("i_dir_acl @F %Id, @s zero.\n"),
10990 PROMPT_CLEAR, 0 },
10991
10992 /* i_frag should be zero */
10993 { PR_2_FRAG_ZERO,
10994 N_("i_frag @F %N, @s zero.\n"),
10995 PROMPT_CLEAR, 0 },
10996
10997 /* i_fsize should be zero */
10998 { PR_2_FSIZE_ZERO,
10999 N_("i_fsize @F %N, @s zero.\n"),
11000 PROMPT_CLEAR, 0 },
11001
11002 /* inode has bad mode */
11003 { PR_2_BAD_MODE,
11004 N_("@i %i (%Q) has a bad mode (%Im).\n"),
11005 PROMPT_CLEAR, 0 },
11006
11007 /* directory corrupted */
11008 { PR_2_DIR_CORRUPTED,
11009 N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
11010 PROMPT_SALVAGE, 0 },
11011
11012 /* filename too long */
11013 { PR_2_FILENAME_LONG,
11014 N_("@d @i %i, @b %B, offset %N: filename too long\n"),
11015 PROMPT_TRUNCATE, 0 },
11016
11017 /* Directory inode has a missing block (hole) */
11018 { PR_2_DIRECTORY_HOLE,
11019 N_("@d @i %i has an unallocated @b #%B. "),
11020 PROMPT_ALLOCATE, 0 },
11021
11022 /* '.' is not NULL terminated */
11023 { PR_2_DOT_NULL_TERM,
11024 N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
11025 PROMPT_FIX, 0 },
11026
11027 /* '..' is not NULL terminated */
11028 { PR_2_DOT_DOT_NULL_TERM,
11029 N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
11030 PROMPT_FIX, 0 },
11031
11032 /* Illegal character device inode */
11033 { PR_2_BAD_CHAR_DEV,
11034 N_("@i %i (%Q) is an @I character @v.\n"),
11035 PROMPT_CLEAR, 0 },
11036
11037 /* Illegal block device inode */
11038 { PR_2_BAD_BLOCK_DEV,
11039 N_("@i %i (%Q) is an @I @b @v.\n"),
11040 PROMPT_CLEAR, 0 },
11041
11042 /* Duplicate '.' entry */
11043 { PR_2_DUP_DOT,
11044 N_("@E is duplicate '.' @e.\n"),
11045 PROMPT_FIX, 0 },
11046
11047 /* Duplicate '..' entry */
11048 { PR_2_DUP_DOT_DOT,
11049 N_("@E is duplicate '..' @e.\n"),
11050 PROMPT_FIX, 0 },
11051
11052 /* Internal error: couldn't find dir_info */
11053 { PR_2_NO_DIRINFO,
11054 N_("Internal error: couldn't find dir_info for %i.\n"),
11055 PROMPT_NONE, PR_FATAL },
11056
11057 /* Final rec_len is wrong */
11058 { PR_2_FINAL_RECLEN,
11059 N_("@E has rec_len of %Dr, should be %N.\n"),
11060 PROMPT_FIX, 0 },
11061
11062 /* Error allocating icount structure */
11063 { PR_2_ALLOCATE_ICOUNT,
11064 N_("@A icount structure: %m\n"),
11065 PROMPT_NONE, PR_FATAL },
11066
11067 /* Error iterating over directory blocks */
11068 { PR_2_DBLIST_ITERATE,
11069 N_("Error iterating over @d @bs: %m\n"),
11070 PROMPT_NONE, PR_FATAL },
11071
11072 /* Error reading directory block */
11073 { PR_2_READ_DIRBLOCK,
11074 N_("Error reading @d @b %b (@i %i): %m\n"),
11075 PROMPT_CONTINUE, 0 },
11076
11077 /* Error writing directory block */
11078 { PR_2_WRITE_DIRBLOCK,
11079 N_("Error writing @d @b %b (@i %i): %m\n"),
11080 PROMPT_CONTINUE, 0 },
11081
11082 /* Error allocating new directory block */
11083 { PR_2_ALLOC_DIRBOCK,
11084 N_("@A new @d @b for @i %i (%s): %m\n"),
11085 PROMPT_NONE, 0 },
11086
11087 /* Error deallocating inode */
11088 { PR_2_DEALLOC_INODE,
11089 N_("Error deallocating @i %i: %m\n"),
11090 PROMPT_NONE, PR_FATAL },
11091
11092 /* Directory entry for '.' is big. Split? */
11093 { PR_2_SPLIT_DOT,
11094 N_("@d @e for '.' is big. "),
11095 PROMPT_SPLIT, PR_NO_OK },
11096
11097 /* Illegal FIFO inode */
11098 { PR_2_BAD_FIFO,
11099 N_("@i %i (%Q) is an @I FIFO.\n"),
11100 PROMPT_CLEAR, 0 },
11101
11102 /* Illegal socket inode */
11103 { PR_2_BAD_SOCKET,
11104 N_("@i %i (%Q) is an @I socket.\n"),
11105 PROMPT_CLEAR, 0 },
11106
11107 /* Directory filetype not set */
11108 { PR_2_SET_FILETYPE,
11109 N_("Setting filetype for @E to %N.\n"),
11110 PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
11111
11112 /* Directory filetype incorrect */
11113 { PR_2_BAD_FILETYPE,
11114 N_("@E has an incorrect filetype (was %Dt, should be %N).\n"),
11115 PROMPT_FIX, 0 },
11116
11117 /* Directory filetype set on filesystem */
11118 { PR_2_CLEAR_FILETYPE,
11119 N_("@E has filetype set.\n"),
11120 PROMPT_CLEAR, PR_PREEN_OK },
11121
11122 /* Directory filename is null */
11123 { PR_2_NULL_NAME,
11124 N_("@E has a zero-length name.\n"),
11125 PROMPT_CLEAR, 0 },
11126
11127 /* Invalid symlink */
11128 { PR_2_INVALID_SYMLINK,
11129 N_("Symlink %Q (@i #%i) is invalid.\n"),
11130 PROMPT_CLEAR, 0 },
11131
11132 /* i_file_acl (extended attribute block) is bad */
11133 { PR_2_FILE_ACL_BAD,
11134 N_("@a @b @F invalid (%If).\n"),
11135 PROMPT_CLEAR, 0 },
11136
11137 /* Filesystem contains large files, but has no such flag in sb */
11138 { PR_2_FEATURE_LARGE_FILES,
11139 N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
11140 PROMPT_FIX, 0 },
11141
11142 /* Node in HTREE directory not referenced */
11143 { PR_2_HTREE_NOTREF,
11144 N_("@p @h %d: node (%B) not referenced\n"),
11145 PROMPT_NONE, 0 },
11146
11147 /* Node in HTREE directory referenced twice */
11148 { PR_2_HTREE_DUPREF,
11149 N_("@p @h %d: node (%B) referenced twice\n"),
11150 PROMPT_NONE, 0 },
11151
11152 /* Node in HTREE directory has bad min hash */
11153 { PR_2_HTREE_MIN_HASH,
11154 N_("@p @h %d: node (%B) has bad min hash\n"),
11155 PROMPT_NONE, 0 },
11156
11157 /* Node in HTREE directory has bad max hash */
11158 { PR_2_HTREE_MAX_HASH,
11159 N_("@p @h %d: node (%B) has bad max hash\n"),
11160 PROMPT_NONE, 0 },
11161
11162 /* Clear invalid HTREE directory */
11163 { PR_2_HTREE_CLEAR,
11164 N_("Invalid @h %d (%q). "), PROMPT_CLEAR, 0 },
11165
11166 /* Bad block in htree interior node */
11167 { PR_2_HTREE_BADBLK,
11168 N_("@p @h %d (%q): bad @b number %b.\n"),
11169 PROMPT_CLEAR_HTREE, 0 },
11170
11171 /* Error adjusting EA refcount */
11172 { PR_2_ADJ_EA_REFCOUNT,
11173 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
11174 PROMPT_NONE, PR_FATAL },
11175
11176 /* Invalid HTREE root node */
11177 { PR_2_HTREE_BAD_ROOT,
11178 N_("@p @h %d: root node is invalid\n"),
11179 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11180
11181 /* Invalid HTREE limit */
11182 { PR_2_HTREE_BAD_LIMIT,
11183 N_("@p @h %d: node (%B) has bad limit (%N)\n"),
11184 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11185
11186 /* Invalid HTREE count */
11187 { PR_2_HTREE_BAD_COUNT,
11188 N_("@p @h %d: node (%B) has bad count (%N)\n"),
11189 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11190
11191 /* HTREE interior node has out-of-order hashes in table */
11192 { PR_2_HTREE_HASH_ORDER,
11193 N_("@p @h %d: node (%B) has an unordered hash table\n"),
11194 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11195
11196 /* Node in HTREE directory has bad depth */
11197 { PR_2_HTREE_BAD_DEPTH,
11198 N_("@p @h %d: node (%B) has bad depth\n"),
11199 PROMPT_NONE, 0 },
11200
11201 /* Duplicate directory entry found */
11202 { PR_2_DUPLICATE_DIRENT,
11203 N_("Duplicate @E found. "),
11204 PROMPT_CLEAR, 0 },
11205
11206 /* Non-unique filename found */
11207 { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
11208 N_("@E has a non-unique filename.\nRename to %s"),
11209 PROMPT_NULL, 0 },
11210
11211 /* Duplicate directory entry found */
11212 { PR_2_REPORT_DUP_DIRENT,
11213 N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
11214 PROMPT_NONE, 0 },
11215
11216 /* Pass 3 errors */
11217
11218 /* Pass 3: Checking directory connectivity */
11219 { PR_3_PASS_HEADER,
11220 N_("Pass 3: Checking @d connectivity\n"),
11221 PROMPT_NONE, 0 },
11222
11223 /* Root inode not allocated */
11224 { PR_3_NO_ROOT_INODE,
11225 N_("@r not allocated. "),
11226 PROMPT_ALLOCATE, 0 },
11227
11228 /* No room in lost+found */
11229 { PR_3_EXPAND_LF_DIR,
11230 N_("No room in @l @d. "),
11231 PROMPT_EXPAND, 0 },
11232
11233 /* Unconnected directory inode */
11234 { PR_3_UNCONNECTED_DIR,
11235 N_("Unconnected @d @i %i (%p)\n"),
11236 PROMPT_CONNECT, 0 },
11237
11238 /* /lost+found not found */
11239 { PR_3_NO_LF_DIR,
11240 N_("/@l not found. "),
11241 PROMPT_CREATE, PR_PREEN_OK },
11242
11243 /* .. entry is incorrect */
11244 { PR_3_BAD_DOT_DOT,
11245 N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
11246 PROMPT_FIX, 0 },
11247
11248 /* Bad or non-existent /lost+found. Cannot reconnect */
11249 { PR_3_NO_LPF,
11250 N_("Bad or non-existent /@l. Cannot reconnect.\n"),
11251 PROMPT_NONE, 0 },
11252
11253 /* Could not expand /lost+found */
11254 { PR_3_CANT_EXPAND_LPF,
11255 N_("Could not expand /@l: %m\n"),
11256 PROMPT_NONE, 0 },
11257
11258 /* Could not reconnect inode */
11259 { PR_3_CANT_RECONNECT,
11260 N_("Could not reconnect %i: %m\n"),
11261 PROMPT_NONE, 0 },
11262
11263 /* Error while trying to find /lost+found */
11264 { PR_3_ERR_FIND_LPF,
11265 N_("Error while trying to find /@l: %m\n"),
11266 PROMPT_NONE, 0 },
11267
11268 /* Error in ext2fs_new_block while creating /lost+found */
11269 { PR_3_ERR_LPF_NEW_BLOCK,
11270 N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
11271 PROMPT_NONE, 0 },
11272
11273 /* Error in ext2fs_new_inode while creating /lost+found */
11274 { PR_3_ERR_LPF_NEW_INODE,
11275 N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
11276 PROMPT_NONE, 0 },
11277
11278 /* Error in ext2fs_new_dir_block while creating /lost+found */
11279 { PR_3_ERR_LPF_NEW_DIR_BLOCK,
11280 N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
11281 PROMPT_NONE, 0 },
11282
11283 /* Error while writing directory block for /lost+found */
11284 { PR_3_ERR_LPF_WRITE_BLOCK,
11285 N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
11286 PROMPT_NONE, 0 },
11287
11288 /* Error while adjusting inode count */
11289 { PR_3_ADJUST_INODE,
11290 N_("Error while adjusting @i count on @i %i\n"),
11291 PROMPT_NONE, 0 },
11292
11293 /* Couldn't fix parent directory -- error */
11294 { PR_3_FIX_PARENT_ERR,
11295 N_("Couldn't fix parent of @i %i: %m\n\n"),
11296 PROMPT_NONE, 0 },
11297
11298 /* Couldn't fix parent directory -- couldn't find it */
11299 { PR_3_FIX_PARENT_NOFIND,
11300 N_("Couldn't fix parent of @i %i: Couldn't find parent @d entry\n\n"),
11301 PROMPT_NONE, 0 },
11302
11303 /* Error allocating inode bitmap */
11304 { PR_3_ALLOCATE_IBITMAP_ERROR,
11305 N_("@A @i @B (%N): %m\n"),
11306 PROMPT_NONE, PR_FATAL },
11307
11308 /* Error creating root directory */
11309 { PR_3_CREATE_ROOT_ERROR,
11310 N_("Error creating root @d (%s): %m\n"),
11311 PROMPT_NONE, PR_FATAL },
11312
11313 /* Error creating lost and found directory */
11314 { PR_3_CREATE_LPF_ERROR,
11315 N_("Error creating /@l @d (%s): %m\n"),
11316 PROMPT_NONE, PR_FATAL },
11317
11318 /* Root inode is not directory; aborting */
11319 { PR_3_ROOT_NOT_DIR_ABORT,
11320 N_("@r is not a @d; aborting.\n"),
11321 PROMPT_NONE, PR_FATAL },
11322
11323 /* Cannot proceed without a root inode. */
11324 { PR_3_NO_ROOT_INODE_ABORT,
11325 N_("Cannot proceed without a @r.\n"),
11326 PROMPT_NONE, PR_FATAL },
11327
11328 /* Internal error: couldn't find dir_info */
11329 { PR_3_NO_DIRINFO,
11330 N_("Internal error: couldn't find dir_info for %i.\n"),
11331 PROMPT_NONE, PR_FATAL },
11332
11333 /* Lost+found not a directory */
11334 { PR_3_LPF_NOTDIR,
11335 N_("/@l is not a @d (ino=%i)\n"),
11336 PROMPT_UNLINK, 0 },
11337
11338 /* Pass 3A Directory Optimization */
11339
11340 /* Pass 3A: Optimizing directories */
11341 { PR_3A_PASS_HEADER,
11342 N_("Pass 3A: Optimizing directories\n"),
11343 PROMPT_NONE, PR_PREEN_NOMSG },
11344
11345 /* Error iterating over directories */
11346 { PR_3A_OPTIMIZE_ITER,
11347 N_("Failed to create dirs_to_hash iterator: %m"),
11348 PROMPT_NONE, 0 },
11349
11350 /* Error rehash directory */
11351 { PR_3A_OPTIMIZE_DIR_ERR,
11352 N_("Failed to optimize directory %q (%d): %m"),
11353 PROMPT_NONE, 0 },
11354
11355 /* Rehashing dir header */
11356 { PR_3A_OPTIMIZE_DIR_HEADER,
11357 N_("Optimizing directories: "),
11358 PROMPT_NONE, PR_MSG_ONLY },
11359
11360 /* Rehashing directory %d */
11361 { PR_3A_OPTIMIZE_DIR,
11362 " %d",
11363 PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
11364
11365 /* Rehashing dir end */
11366 { PR_3A_OPTIMIZE_DIR_END,
11367 "\n",
11368 PROMPT_NONE, PR_PREEN_NOHDR },
11369
11370 /* Pass 4 errors */
11371
11372 /* Pass 4: Checking reference counts */
11373 { PR_4_PASS_HEADER,
11374 N_("Pass 4: Checking reference counts\n"),
11375 PROMPT_NONE, 0 },
11376
11377 /* Unattached zero-length inode */
11378 { PR_4_ZERO_LEN_INODE,
11379 "@u @z @i %i. ",
11380 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
11381
11382 /* Unattached inode */
11383 { PR_4_UNATTACHED_INODE,
11384 "@u @i %i\n",
11385 PROMPT_CONNECT, 0 },
11386
11387 /* Inode ref count wrong */
11388 { PR_4_BAD_REF_COUNT,
11389 N_("@i %i ref count is %Il, @s %N. "),
11390 PROMPT_FIX, PR_PREEN_OK },
11391
11392 { PR_4_INCONSISTENT_COUNT,
11393 N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
11394 "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
11395 "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
11396 "They should be the same!\n"),
11397 PROMPT_NONE, 0 },
11398
11399 /* Pass 5 errors */
11400
11401 /* Pass 5: Checking group summary information */
11402 { PR_5_PASS_HEADER,
11403 N_("Pass 5: Checking @g summary information\n"),
11404 PROMPT_NONE, 0 },
11405
11406 /* Padding at end of inode bitmap is not set. */
11407 { PR_5_INODE_BMAP_PADDING,
11408 N_("Padding at end of @i @B is not set. "),
11409 PROMPT_FIX, PR_PREEN_OK },
11410
11411 /* Padding at end of block bitmap is not set. */
11412 { PR_5_BLOCK_BMAP_PADDING,
11413 N_("Padding at end of @b @B is not set. "),
11414 PROMPT_FIX, PR_PREEN_OK },
11415
11416 /* Block bitmap differences header */
11417 { PR_5_BLOCK_BITMAP_HEADER,
11418 N_("@b @B differences: "),
11419 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
11420
11421 /* Block not used, but marked in bitmap */
11422 { PR_5_BLOCK_UNUSED,
11423 " -%b",
11424 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11425
11426 /* Block used, but not marked used in bitmap */
11427 { PR_5_BLOCK_USED,
11428 " +%b",
11429 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11430
11431 /* Block bitmap differences end */
11432 { PR_5_BLOCK_BITMAP_END,
11433 "\n",
11434 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11435
11436 /* Inode bitmap differences header */
11437 { PR_5_INODE_BITMAP_HEADER,
11438 N_("@i @B differences: "),
11439 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
11440
11441 /* Inode not used, but marked in bitmap */
11442 { PR_5_INODE_UNUSED,
11443 " -%i",
11444 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11445
11446 /* Inode used, but not marked used in bitmap */
11447 { PR_5_INODE_USED,
11448 " +%i",
11449 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11450
11451 /* Inode bitmap differences end */
11452 { PR_5_INODE_BITMAP_END,
11453 "\n",
11454 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11455
11456 /* Free inodes count for group wrong */
11457 { PR_5_FREE_INODE_COUNT_GROUP,
11458 N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
11459 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11460
11461 /* Directories count for group wrong */
11462 { PR_5_FREE_DIR_COUNT_GROUP,
11463 N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
11464 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11465
11466 /* Free inodes count wrong */
11467 { PR_5_FREE_INODE_COUNT,
11468 N_("Free @is count wrong (%i, counted=%j).\n"),
11469 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11470
11471 /* Free blocks count for group wrong */
11472 { PR_5_FREE_BLOCK_COUNT_GROUP,
11473 N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
11474 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11475
11476 /* Free blocks count wrong */
11477 { PR_5_FREE_BLOCK_COUNT,
11478 N_("Free @bs count wrong (%b, counted=%c).\n"),
11479 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11480
11481 /* Programming error: bitmap endpoints don't match */
11482 { PR_5_BMAP_ENDPOINTS,
11483 N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
11484 "match calculated @B endpoints (%i, %j)\n"),
11485 PROMPT_NONE, PR_FATAL },
11486
11487 /* Internal error: fudging end of bitmap */
11488 { PR_5_FUDGE_BITMAP_ERROR,
11489 N_("Internal error: fudging end of bitmap (%N)\n"),
11490 PROMPT_NONE, PR_FATAL },
11491
11492 /* Error copying in replacement inode bitmap */
11493 { PR_5_COPY_IBITMAP_ERROR,
11494 "Error copying in replacement @i @B: %m\n",
11495 PROMPT_NONE, PR_FATAL },
11496
11497 /* Error copying in replacement block bitmap */
11498 { PR_5_COPY_BBITMAP_ERROR,
11499 "Error copying in replacement @b @B: %m\n",
11500 PROMPT_NONE, PR_FATAL },
11501
11502 /* Block range not used, but marked in bitmap */
11503 { PR_5_BLOCK_RANGE_UNUSED,
11504 " -(%b--%c)",
11505 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11506
11507 /* Block range used, but not marked used in bitmap */
11508 { PR_5_BLOCK_RANGE_USED,
11509 " +(%b--%c)",
11510 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11511
11512 /* Inode range not used, but marked in bitmap */
11513 { PR_5_INODE_RANGE_UNUSED,
11514 " -(%i--%j)",
11515 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11516
11517 /* Inode range used, but not marked used in bitmap */
11518 { PR_5_INODE_RANGE_USED,
11519 " +(%i--%j)",
11520 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11521
11522 { 0 }
11523};
11524
11525/*
11526 * This is the latch flags register. It allows several problems to be
11527 * "latched" together. This means that the user has to answer but one
11528 * question for the set of problems, and all of the associated
11529 * problems will be either fixed or not fixed.
11530 */
11531static struct latch_descr pr_latch_info[] = {
11532 { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
11533 { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
11534 { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
11535 { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
11536 { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
11537 { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
11538 { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
11539 { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
11540 { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
11541 { -1, 0, 0 },
11542};
11543
11544static const struct e2fsck_problem *find_problem(problem_t code)
11545{
11546 int i;
11547
11548 for (i=0; problem_table[i].e2p_code; i++) {
11549 if (problem_table[i].e2p_code == code)
11550 return &problem_table[i];
11551 }
11552 return 0;
11553}
11554
11555static struct latch_descr *find_latch(int code)
11556{
11557 int i;
11558
11559 for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
11560 if (pr_latch_info[i].latch_code == code)
11561 return &pr_latch_info[i];
11562 }
11563 return 0;
11564}
11565
11566int end_problem_latch(e2fsck_t ctx, int mask)
11567{
11568 struct latch_descr *ldesc;
11569 struct problem_context pctx;
11570 int answer = -1;
11571
11572 ldesc = find_latch(mask);
11573 if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
11574 clear_problem_context(&pctx);
11575 answer = fix_problem(ctx, ldesc->end_message, &pctx);
11576 }
11577 ldesc->flags &= ~(PRL_VARIABLE);
11578 return answer;
11579}
11580
11581int set_latch_flags(int mask, int setflags, int clearflags)
11582{
11583 struct latch_descr *ldesc;
11584
11585 ldesc = find_latch(mask);
11586 if (!ldesc)
11587 return -1;
11588 ldesc->flags |= setflags;
11589 ldesc->flags &= ~clearflags;
11590 return 0;
11591}
11592
11593void clear_problem_context(struct problem_context *ctx)
11594{
11595 memset(ctx, 0, sizeof(struct problem_context));
11596 ctx->blkcount = -1;
11597 ctx->group = -1;
11598}
11599
11600int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
11601{
11602 ext2_filsys fs = ctx->fs;
11603 const struct e2fsck_problem *ptr;
11604 struct latch_descr *ldesc = 0;
11605 const char *message;
11606 int def_yn, answer, ans;
11607 int print_answer = 0;
11608 int suppress = 0;
11609
11610 ptr = find_problem(code);
11611 if (!ptr) {
11612 printf(_("Unhandled error code (0x%x)!\n"), code);
11613 return 0;
11614 }
11615 def_yn = 1;
11616 if ((ptr->flags & PR_NO_DEFAULT) ||
11617 ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
11618 (ctx->options & E2F_OPT_NO))
11619 def_yn= 0;
11620
11621 /*
11622 * Do special latch processing. This is where we ask the
11623 * latch question, if it exists
11624 */
11625 if (ptr->flags & PR_LATCH_MASK) {
11626 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
11627 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
11628 ans = fix_problem(ctx, ldesc->question, pctx);
11629 if (ans == 1)
11630 ldesc->flags |= PRL_YES;
11631 if (ans == 0)
11632 ldesc->flags |= PRL_NO;
11633 ldesc->flags |= PRL_LATCHED;
11634 }
11635 if (ldesc->flags & PRL_SUPPRESS)
11636 suppress++;
11637 }
11638 if ((ptr->flags & PR_PREEN_NOMSG) &&
11639 (ctx->options & E2F_OPT_PREEN))
11640 suppress++;
11641 if ((ptr->flags & PR_NO_NOMSG) &&
11642 (ctx->options & E2F_OPT_NO))
11643 suppress++;
11644 if (!suppress) {
11645 message = ptr->e2p_description;
11646 if ((ctx->options & E2F_OPT_PREEN) &&
11647 !(ptr->flags & PR_PREEN_NOHDR)) {
11648 printf("%s: ", ctx->device_name ?
11649 ctx->device_name : ctx->filesystem_name);
11650 }
11651 if (*message)
11652 print_e2fsck_message(ctx, _(message), pctx, 1);
11653 }
11654 if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
11655 preenhalt(ctx);
11656
11657 if (ptr->flags & PR_FATAL)
11658 fatal_error(ctx, 0);
11659
11660 if (ptr->prompt == PROMPT_NONE) {
11661 if (ptr->flags & PR_NOCOLLATE)
11662 answer = -1;
11663 else
11664 answer = def_yn;
11665 } else {
11666 if (ctx->options & E2F_OPT_PREEN) {
11667 answer = def_yn;
11668 if (!(ptr->flags & PR_PREEN_NOMSG))
11669 print_answer = 1;
11670 } else if ((ptr->flags & PR_LATCH_MASK) &&
11671 (ldesc->flags & (PRL_YES | PRL_NO))) {
11672 if (!suppress)
11673 print_answer = 1;
11674 if (ldesc->flags & PRL_YES)
11675 answer = 1;
11676 else
11677 answer = 0;
11678 } else
11679 answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
11680 if (!answer && !(ptr->flags & PR_NO_OK))
11681 ext2fs_unmark_valid(fs);
11682
11683 if (print_answer)
11684 printf("%s.\n", answer ?
11685 _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
11686
11687 }
11688
11689 if ((ptr->prompt == PROMPT_ABORT) && answer)
11690 fatal_error(ctx, 0);
11691
11692 if (ptr->flags & PR_AFTER_CODE)
11693 answer = fix_problem(ctx, ptr->second_code, pctx);
11694
11695 return answer;
11696}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011697
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011698/*
11699 * linux/fs/recovery.c
11700 *
11701 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011702 */
11703
11704/*
11705 * Maintain information about the progress of the recovery job, so that
11706 * the different passes can carry information between them.
11707 */
11708struct recovery_info
11709{
11710 tid_t start_transaction;
11711 tid_t end_transaction;
11712
11713 int nr_replays;
11714 int nr_revokes;
11715 int nr_revoke_hits;
11716};
11717
11718enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
11719static int do_one_pass(journal_t *journal,
11720 struct recovery_info *info, enum passtype pass);
11721static int scan_revoke_records(journal_t *, struct buffer_head *,
11722 tid_t, struct recovery_info *);
11723
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011724/*
11725 * Read a block from the journal
11726 */
11727
11728static int jread(struct buffer_head **bhp, journal_t *journal,
11729 unsigned int offset)
11730{
11731 int err;
11732 unsigned long blocknr;
11733 struct buffer_head *bh;
11734
11735 *bhp = NULL;
11736
11737 J_ASSERT (offset < journal->j_maxlen);
11738
11739 err = journal_bmap(journal, offset, &blocknr);
11740
11741 if (err) {
11742 printk (KERN_ERR "JBD: bad block at offset %u\n",
11743 offset);
11744 return err;
11745 }
11746
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011747 bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011748 if (!bh)
11749 return -ENOMEM;
11750
11751 if (!buffer_uptodate(bh)) {
11752 /* If this is a brand new buffer, start readahead.
11753 Otherwise, we assume we are already reading it. */
11754 if (!buffer_req(bh))
11755 do_readahead(journal, offset);
11756 wait_on_buffer(bh);
11757 }
11758
11759 if (!buffer_uptodate(bh)) {
11760 printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
11761 offset);
11762 brelse(bh);
11763 return -EIO;
11764 }
11765
11766 *bhp = bh;
11767 return 0;
11768}
11769
11770
11771/*
11772 * Count the number of in-use tags in a journal descriptor block.
11773 */
11774
11775static int count_tags(struct buffer_head *bh, int size)
11776{
11777 char * tagp;
11778 journal_block_tag_t * tag;
11779 int nr = 0;
11780
11781 tagp = &bh->b_data[sizeof(journal_header_t)];
11782
11783 while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
11784 tag = (journal_block_tag_t *) tagp;
11785
11786 nr++;
11787 tagp += sizeof(journal_block_tag_t);
11788 if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
11789 tagp += 16;
11790
11791 if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
11792 break;
11793 }
11794
11795 return nr;
11796}
11797
11798
11799/* Make sure we wrap around the log correctly! */
11800#define wrap(journal, var) \
11801do { \
11802 if (var >= (journal)->j_last) \
11803 var -= ((journal)->j_last - (journal)->j_first); \
11804} while (0)
11805
11806/**
11807 * int journal_recover(journal_t *journal) - recovers a on-disk journal
11808 * @journal: the journal to recover
11809 *
11810 * The primary function for recovering the log contents when mounting a
11811 * journaled device.
11812 *
11813 * Recovery is done in three passes. In the first pass, we look for the
11814 * end of the log. In the second, we assemble the list of revoke
11815 * blocks. In the third and final pass, we replay any un-revoked blocks
11816 * in the log.
11817 */
11818int journal_recover(journal_t *journal)
11819{
11820 int err;
11821 journal_superblock_t * sb;
11822
11823 struct recovery_info info;
11824
11825 memset(&info, 0, sizeof(info));
11826 sb = journal->j_superblock;
11827
11828 /*
11829 * The journal superblock's s_start field (the current log head)
11830 * is always zero if, and only if, the journal was cleanly
11831 * unmounted.
11832 */
11833
11834 if (!sb->s_start) {
11835 jbd_debug(1, "No recovery required, last transaction %d\n",
11836 ntohl(sb->s_sequence));
11837 journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
11838 return 0;
11839 }
11840
11841 err = do_one_pass(journal, &info, PASS_SCAN);
11842 if (!err)
11843 err = do_one_pass(journal, &info, PASS_REVOKE);
11844 if (!err)
11845 err = do_one_pass(journal, &info, PASS_REPLAY);
11846
11847 jbd_debug(0, "JBD: recovery, exit status %d, "
11848 "recovered transactions %u to %u\n",
11849 err, info.start_transaction, info.end_transaction);
11850 jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
11851 info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
11852
11853 /* Restart the log at the next transaction ID, thus invalidating
11854 * any existing commit records in the log. */
11855 journal->j_transaction_sequence = ++info.end_transaction;
11856
11857 journal_clear_revoke(journal);
11858 sync_blockdev(journal->j_fs_dev);
11859 return err;
11860}
11861
11862static int do_one_pass(journal_t *journal,
11863 struct recovery_info *info, enum passtype pass)
11864{
11865 unsigned int first_commit_ID, next_commit_ID;
11866 unsigned long next_log_block;
11867 int err, success = 0;
11868 journal_superblock_t * sb;
11869 journal_header_t * tmp;
11870 struct buffer_head * bh;
11871 unsigned int sequence;
11872 int blocktype;
11873
11874 /* Precompute the maximum metadata descriptors in a descriptor block */
11875 int MAX_BLOCKS_PER_DESC;
11876 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
11877 / sizeof(journal_block_tag_t));
11878
11879 /*
11880 * First thing is to establish what we expect to find in the log
11881 * (in terms of transaction IDs), and where (in terms of log
11882 * block offsets): query the superblock.
11883 */
11884
11885 sb = journal->j_superblock;
11886 next_commit_ID = ntohl(sb->s_sequence);
11887 next_log_block = ntohl(sb->s_start);
11888
11889 first_commit_ID = next_commit_ID;
11890 if (pass == PASS_SCAN)
11891 info->start_transaction = first_commit_ID;
11892
11893 jbd_debug(1, "Starting recovery pass %d\n", pass);
11894
11895 /*
11896 * Now we walk through the log, transaction by transaction,
11897 * making sure that each transaction has a commit block in the
11898 * expected place. Each complete transaction gets replayed back
11899 * into the main filesystem.
11900 */
11901
11902 while (1) {
11903 int flags;
11904 char * tagp;
11905 journal_block_tag_t * tag;
11906 struct buffer_head * obh;
11907 struct buffer_head * nbh;
11908
11909 /* If we already know where to stop the log traversal,
11910 * check right now that we haven't gone past the end of
11911 * the log. */
11912
11913 if (pass != PASS_SCAN)
11914 if (tid_geq(next_commit_ID, info->end_transaction))
11915 break;
11916
11917 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
11918 next_commit_ID, next_log_block, journal->j_last);
11919
11920 /* Skip over each chunk of the transaction looking
11921 * either the next descriptor block or the final commit
11922 * record. */
11923
11924 jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
11925 err = jread(&bh, journal, next_log_block);
11926 if (err)
11927 goto failed;
11928
11929 next_log_block++;
11930 wrap(journal, next_log_block);
11931
11932 /* What kind of buffer is it?
11933 *
11934 * If it is a descriptor block, check that it has the
11935 * expected sequence number. Otherwise, we're all done
11936 * here. */
11937
11938 tmp = (journal_header_t *)bh->b_data;
11939
11940 if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
11941 brelse(bh);
11942 break;
11943 }
11944
11945 blocktype = ntohl(tmp->h_blocktype);
11946 sequence = ntohl(tmp->h_sequence);
11947 jbd_debug(3, "Found magic %d, sequence %d\n",
11948 blocktype, sequence);
11949
11950 if (sequence != next_commit_ID) {
11951 brelse(bh);
11952 break;
11953 }
11954
11955 /* OK, we have a valid descriptor block which matches
11956 * all of the sequence number checks. What are we going
11957 * to do with it? That depends on the pass... */
11958
11959 switch(blocktype) {
11960 case JFS_DESCRIPTOR_BLOCK:
11961 /* If it is a valid descriptor block, replay it
11962 * in pass REPLAY; otherwise, just skip over the
11963 * blocks it describes. */
11964 if (pass != PASS_REPLAY) {
11965 next_log_block +=
11966 count_tags(bh, journal->j_blocksize);
11967 wrap(journal, next_log_block);
11968 brelse(bh);
11969 continue;
11970 }
11971
11972 /* A descriptor block: we can now write all of
11973 * the data blocks. Yay, useful work is finally
11974 * getting done here! */
11975
11976 tagp = &bh->b_data[sizeof(journal_header_t)];
11977 while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
11978 <= journal->j_blocksize) {
11979 unsigned long io_block;
11980
11981 tag = (journal_block_tag_t *) tagp;
11982 flags = ntohl(tag->t_flags);
11983
11984 io_block = next_log_block++;
11985 wrap(journal, next_log_block);
11986 err = jread(&obh, journal, io_block);
11987 if (err) {
11988 /* Recover what we can, but
11989 * report failure at the end. */
11990 success = err;
11991 printk (KERN_ERR
11992 "JBD: IO error %d recovering "
11993 "block %ld in log\n",
11994 err, io_block);
11995 } else {
11996 unsigned long blocknr;
11997
11998 J_ASSERT(obh != NULL);
11999 blocknr = ntohl(tag->t_blocknr);
12000
12001 /* If the block has been
12002 * revoked, then we're all done
12003 * here. */
12004 if (journal_test_revoke
12005 (journal, blocknr,
12006 next_commit_ID)) {
12007 brelse(obh);
12008 ++info->nr_revoke_hits;
12009 goto skip_write;
12010 }
12011
12012 /* Find a buffer for the new
12013 * data being restored */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012014 nbh = getblk(journal->j_fs_dev,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012015 blocknr,
12016 journal->j_blocksize);
12017 if (nbh == NULL) {
12018 printk(KERN_ERR
12019 "JBD: Out of memory "
12020 "during recovery.\n");
12021 err = -ENOMEM;
12022 brelse(bh);
12023 brelse(obh);
12024 goto failed;
12025 }
12026
12027 lock_buffer(nbh);
12028 memcpy(nbh->b_data, obh->b_data,
12029 journal->j_blocksize);
12030 if (flags & JFS_FLAG_ESCAPE) {
12031 *((unsigned int *)bh->b_data) =
12032 htonl(JFS_MAGIC_NUMBER);
12033 }
12034
12035 BUFFER_TRACE(nbh, "marking dirty");
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012036 mark_buffer_uptodate(nbh, 1);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012037 mark_buffer_dirty(nbh);
12038 BUFFER_TRACE(nbh, "marking uptodate");
12039 ++info->nr_replays;
12040 /* ll_rw_block(WRITE, 1, &nbh); */
12041 unlock_buffer(nbh);
12042 brelse(obh);
12043 brelse(nbh);
12044 }
12045
12046 skip_write:
12047 tagp += sizeof(journal_block_tag_t);
12048 if (!(flags & JFS_FLAG_SAME_UUID))
12049 tagp += 16;
12050
12051 if (flags & JFS_FLAG_LAST_TAG)
12052 break;
12053 }
12054
12055 brelse(bh);
12056 continue;
12057
12058 case JFS_COMMIT_BLOCK:
12059 /* Found an expected commit block: not much to
12060 * do other than move on to the next sequence
12061 * number. */
12062 brelse(bh);
12063 next_commit_ID++;
12064 continue;
12065
12066 case JFS_REVOKE_BLOCK:
12067 /* If we aren't in the REVOKE pass, then we can
12068 * just skip over this block. */
12069 if (pass != PASS_REVOKE) {
12070 brelse(bh);
12071 continue;
12072 }
12073
12074 err = scan_revoke_records(journal, bh,
12075 next_commit_ID, info);
12076 brelse(bh);
12077 if (err)
12078 goto failed;
12079 continue;
12080
12081 default:
12082 jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
12083 blocktype);
12084 goto done;
12085 }
12086 }
12087
12088 done:
12089 /*
12090 * We broke out of the log scan loop: either we came to the
12091 * known end of the log or we found an unexpected block in the
12092 * log. If the latter happened, then we know that the "current"
12093 * transaction marks the end of the valid log.
12094 */
12095
12096 if (pass == PASS_SCAN)
12097 info->end_transaction = next_commit_ID;
12098 else {
12099 /* It's really bad news if different passes end up at
12100 * different places (but possible due to IO errors). */
12101 if (info->end_transaction != next_commit_ID) {
12102 printk (KERN_ERR "JBD: recovery pass %d ended at "
12103 "transaction %u, expected %u\n",
12104 pass, next_commit_ID, info->end_transaction);
12105 if (!success)
12106 success = -EIO;
12107 }
12108 }
12109
12110 return success;
12111
12112 failed:
12113 return err;
12114}
12115
12116
12117/* Scan a revoke record, marking all blocks mentioned as revoked. */
12118
12119static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
12120 tid_t sequence, struct recovery_info *info)
12121{
12122 journal_revoke_header_t *header;
12123 int offset, max;
12124
12125 header = (journal_revoke_header_t *) bh->b_data;
12126 offset = sizeof(journal_revoke_header_t);
12127 max = ntohl(header->r_count);
12128
12129 while (offset < max) {
12130 unsigned long blocknr;
12131 int err;
12132
12133 blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
12134 offset += 4;
12135 err = journal_set_revoke(journal, blocknr, sequence);
12136 if (err)
12137 return err;
12138 ++info->nr_revokes;
12139 }
12140 return 0;
12141}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012142
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012143
12144/*
12145 * rehash.c --- rebuild hash tree directories
12146 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012147 * This algorithm is designed for simplicity of implementation and to
12148 * pack the directory as much as possible. It however requires twice
12149 * as much memory as the size of the directory. The maximum size
12150 * directory supported using a 4k blocksize is roughly a gigabyte, and
12151 * so there may very well be problems with machines that don't have
12152 * virtual memory, and obscenely large directories.
12153 *
12154 * An alternate algorithm which is much more disk intensive could be
12155 * written, and probably will need to be written in the future. The
12156 * design goals of such an algorithm are: (a) use (roughly) constant
12157 * amounts of memory, no matter how large the directory, (b) the
12158 * directory must be safe at all times, even if e2fsck is interrupted
12159 * in the middle, (c) we must use minimal amounts of extra disk
12160 * blocks. This pretty much requires an incremental approach, where
12161 * we are reading from one part of the directory, and inserting into
12162 * the front half. So the algorithm will have to keep track of a
12163 * moving block boundary between the new tree and the old tree, and
12164 * files will need to be moved from the old directory and inserted
12165 * into the new tree. If the new directory requires space which isn't
12166 * yet available, blocks from the beginning part of the old directory
12167 * may need to be moved to the end of the directory to make room for
12168 * the new tree:
12169 *
12170 * --------------------------------------------------------
12171 * | new tree | | old tree |
12172 * --------------------------------------------------------
12173 * ^ ptr ^ptr
12174 * tail new head old
12175 *
12176 * This is going to be a pain in the tuckus to implement, and will
12177 * require a lot more disk accesses. So I'm going to skip it for now;
12178 * it's only really going to be an issue for really, really big
12179 * filesystems (when we reach the level of tens of millions of files
12180 * in a single directory). It will probably be easier to simply
12181 * require that e2fsck use VM first.
12182 */
12183
12184struct fill_dir_struct {
12185 char *buf;
12186 struct ext2_inode *inode;
12187 int err;
12188 e2fsck_t ctx;
12189 struct hash_entry *harray;
12190 int max_array, num_array;
12191 int dir_size;
12192 int compress;
12193 ino_t parent;
12194};
12195
12196struct hash_entry {
12197 ext2_dirhash_t hash;
12198 ext2_dirhash_t minor_hash;
12199 struct ext2_dir_entry *dir;
12200};
12201
12202struct out_dir {
12203 int num;
12204 int max;
12205 char *buf;
12206 ext2_dirhash_t *hashes;
12207};
12208
12209static int fill_dir_block(ext2_filsys fs,
12210 blk_t *block_nr,
12211 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000012212 blk_t ref_block FSCK_ATTR((unused)),
12213 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012214 void *priv_data)
12215{
12216 struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
12217 struct hash_entry *new_array, *ent;
12218 struct ext2_dir_entry *dirent;
12219 char *dir;
12220 unsigned int offset, dir_offset;
12221
12222 if (blockcnt < 0)
12223 return 0;
12224
12225 offset = blockcnt * fs->blocksize;
12226 if (offset + fs->blocksize > fd->inode->i_size) {
12227 fd->err = EXT2_ET_DIR_CORRUPTED;
12228 return BLOCK_ABORT;
12229 }
12230 dir = (fd->buf+offset);
12231 if (HOLE_BLKADDR(*block_nr)) {
12232 memset(dir, 0, fs->blocksize);
12233 dirent = (struct ext2_dir_entry *) dir;
12234 dirent->rec_len = fs->blocksize;
12235 } else {
12236 fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
12237 if (fd->err)
12238 return BLOCK_ABORT;
12239 }
12240 /* While the directory block is "hot", index it. */
12241 dir_offset = 0;
12242 while (dir_offset < fs->blocksize) {
12243 dirent = (struct ext2_dir_entry *) (dir + dir_offset);
12244 if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
12245 (dirent->rec_len < 8) ||
12246 ((dirent->rec_len % 4) != 0) ||
12247 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
12248 fd->err = EXT2_ET_DIR_CORRUPTED;
12249 return BLOCK_ABORT;
12250 }
12251 dir_offset += dirent->rec_len;
12252 if (dirent->inode == 0)
12253 continue;
12254 if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
12255 (dirent->name[0] == '.'))
12256 continue;
12257 if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
12258 (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
12259 fd->parent = dirent->inode;
12260 continue;
12261 }
12262 if (fd->num_array >= fd->max_array) {
12263 new_array = realloc(fd->harray,
12264 sizeof(struct hash_entry) * (fd->max_array+500));
12265 if (!new_array) {
12266 fd->err = ENOMEM;
12267 return BLOCK_ABORT;
12268 }
12269 fd->harray = new_array;
12270 fd->max_array += 500;
12271 }
12272 ent = fd->harray + fd->num_array++;
12273 ent->dir = dirent;
12274 fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
12275 if (fd->compress)
12276 ent->hash = ent->minor_hash = 0;
12277 else {
12278 fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
12279 dirent->name,
12280 dirent->name_len & 0xFF,
12281 fs->super->s_hash_seed,
12282 &ent->hash, &ent->minor_hash);
12283 if (fd->err)
12284 return BLOCK_ABORT;
12285 }
12286 }
12287
12288 return 0;
12289}
12290
12291/* Used for sorting the hash entry */
12292static EXT2_QSORT_TYPE name_cmp(const void *a, const void *b)
12293{
12294 const struct hash_entry *he_a = (const struct hash_entry *) a;
12295 const struct hash_entry *he_b = (const struct hash_entry *) b;
12296 int ret;
12297 int min_len;
12298
12299 min_len = he_a->dir->name_len;
12300 if (min_len > he_b->dir->name_len)
12301 min_len = he_b->dir->name_len;
12302
12303 ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
12304 if (ret == 0) {
12305 if (he_a->dir->name_len > he_b->dir->name_len)
12306 ret = 1;
12307 else if (he_a->dir->name_len < he_b->dir->name_len)
12308 ret = -1;
12309 else
12310 ret = he_b->dir->inode - he_a->dir->inode;
12311 }
12312 return ret;
12313}
12314
12315/* Used for sorting the hash entry */
12316static EXT2_QSORT_TYPE hash_cmp(const void *a, const void *b)
12317{
12318 const struct hash_entry *he_a = (const struct hash_entry *) a;
12319 const struct hash_entry *he_b = (const struct hash_entry *) b;
12320 int ret;
12321
12322 if (he_a->hash > he_b->hash)
12323 ret = 1;
12324 else if (he_a->hash < he_b->hash)
12325 ret = -1;
12326 else {
12327 if (he_a->minor_hash > he_b->minor_hash)
12328 ret = 1;
12329 else if (he_a->minor_hash < he_b->minor_hash)
12330 ret = -1;
12331 else
12332 ret = name_cmp(a, b);
12333 }
12334 return ret;
12335}
12336
12337static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
12338 int blocks)
12339{
12340 void *new_mem;
12341
12342 if (outdir->max) {
12343 new_mem = realloc(outdir->buf, blocks * fs->blocksize);
12344 if (!new_mem)
12345 return ENOMEM;
12346 outdir->buf = new_mem;
12347 new_mem = realloc(outdir->hashes,
12348 blocks * sizeof(ext2_dirhash_t));
12349 if (!new_mem)
12350 return ENOMEM;
12351 outdir->hashes = new_mem;
12352 } else {
12353 outdir->buf = malloc(blocks * fs->blocksize);
12354 outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
12355 outdir->num = 0;
12356 }
12357 outdir->max = blocks;
12358 return 0;
12359}
12360
12361static void free_out_dir(struct out_dir *outdir)
12362{
12363 if (outdir->buf)
12364 free(outdir->buf);
12365 if (outdir->hashes)
12366 free(outdir->hashes);
12367 outdir->max = 0;
12368 outdir->num =0;
12369}
12370
12371static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
12372 char ** ret)
12373{
12374 errcode_t retval;
12375
12376 if (outdir->num >= outdir->max) {
12377 retval = alloc_size_dir(fs, outdir, outdir->max + 50);
12378 if (retval)
12379 return retval;
12380 }
12381 *ret = outdir->buf + (outdir->num++ * fs->blocksize);
12382 memset(*ret, 0, fs->blocksize);
12383 return 0;
12384}
12385
12386/*
12387 * This function is used to make a unique filename. We do this by
12388 * appending ~0, and then incrementing the number. However, we cannot
12389 * expand the length of the filename beyond the padding available in
12390 * the directory entry.
12391 */
12392static void mutate_name(char *str, __u16 *len)
12393{
12394 int i;
12395 __u16 l = *len & 0xFF, h = *len & 0xff00;
12396
12397 /*
12398 * First check to see if it looks the name has been mutated
12399 * already
12400 */
12401 for (i = l-1; i > 0; i--) {
12402 if (!isdigit(str[i]))
12403 break;
12404 }
12405 if ((i == l-1) || (str[i] != '~')) {
12406 if (((l-1) & 3) < 2)
12407 l += 2;
12408 else
12409 l = (l+3) & ~3;
12410 str[l-2] = '~';
12411 str[l-1] = '0';
12412 *len = l | h;
12413 return;
12414 }
12415 for (i = l-1; i >= 0; i--) {
12416 if (isdigit(str[i])) {
12417 if (str[i] == '9')
12418 str[i] = '0';
12419 else {
12420 str[i]++;
12421 return;
12422 }
12423 continue;
12424 }
12425 if (i == 1) {
12426 if (str[0] == 'z')
12427 str[0] = 'A';
12428 else if (str[0] == 'Z') {
12429 str[0] = '~';
12430 str[1] = '0';
12431 } else
12432 str[0]++;
12433 } else if (i > 0) {
12434 str[i] = '1';
12435 str[i-1] = '~';
12436 } else {
12437 if (str[0] == '~')
12438 str[0] = 'a';
12439 else
12440 str[0]++;
12441 }
12442 break;
12443 }
12444}
12445
12446static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
12447 ext2_ino_t ino,
12448 struct fill_dir_struct *fd)
12449{
12450 struct problem_context pctx;
12451 struct hash_entry *ent, *prev;
12452 int i, j;
12453 int fixed = 0;
12454 char new_name[256];
12455 __u16 new_len;
12456
12457 clear_problem_context(&pctx);
12458 pctx.ino = ino;
12459
12460 for (i=1; i < fd->num_array; i++) {
12461 ent = fd->harray + i;
12462 prev = ent - 1;
12463 if (!ent->dir->inode ||
12464 ((ent->dir->name_len & 0xFF) !=
12465 (prev->dir->name_len & 0xFF)) ||
12466 (strncmp(ent->dir->name, prev->dir->name,
12467 ent->dir->name_len & 0xFF)))
12468 continue;
12469 pctx.dirent = ent->dir;
12470 if ((ent->dir->inode == prev->dir->inode) &&
12471 fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
12472 e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
12473 ent->dir->inode = 0;
12474 fixed++;
12475 continue;
12476 }
12477 memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
12478 new_len = ent->dir->name_len;
12479 mutate_name(new_name, &new_len);
12480 for (j=0; j < fd->num_array; j++) {
12481 if ((i==j) ||
12482 ((ent->dir->name_len & 0xFF) !=
12483 (fd->harray[j].dir->name_len & 0xFF)) ||
12484 (strncmp(new_name, fd->harray[j].dir->name,
12485 new_len & 0xFF)))
12486 continue;
12487 mutate_name(new_name, &new_len);
12488
12489 j = -1;
12490 }
12491 new_name[new_len & 0xFF] = 0;
12492 pctx.str = new_name;
12493 if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
12494 memcpy(ent->dir->name, new_name, new_len & 0xFF);
12495 ent->dir->name_len = new_len;
12496 ext2fs_dirhash(fs->super->s_def_hash_version,
12497 ent->dir->name,
12498 ent->dir->name_len & 0xFF,
12499 fs->super->s_hash_seed,
12500 &ent->hash, &ent->minor_hash);
12501 fixed++;
12502 }
12503 }
12504 return fixed;
12505}
12506
12507
12508static errcode_t copy_dir_entries(ext2_filsys fs,
12509 struct fill_dir_struct *fd,
12510 struct out_dir *outdir)
12511{
12512 errcode_t retval;
12513 char *block_start;
12514 struct hash_entry *ent;
12515 struct ext2_dir_entry *dirent;
12516 int i, rec_len, left;
12517 ext2_dirhash_t prev_hash;
12518 int offset;
12519
12520 outdir->max = 0;
12521 retval = alloc_size_dir(fs, outdir,
12522 (fd->dir_size / fs->blocksize) + 2);
12523 if (retval)
12524 return retval;
12525 outdir->num = fd->compress ? 0 : 1;
12526 offset = 0;
12527 outdir->hashes[0] = 0;
12528 prev_hash = 1;
12529 if ((retval = get_next_block(fs, outdir, &block_start)))
12530 return retval;
12531 dirent = (struct ext2_dir_entry *) block_start;
12532 left = fs->blocksize;
12533 for (i=0; i < fd->num_array; i++) {
12534 ent = fd->harray + i;
12535 if (ent->dir->inode == 0)
12536 continue;
12537 rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
12538 if (rec_len > left) {
12539 if (left)
12540 dirent->rec_len += left;
12541 if ((retval = get_next_block(fs, outdir,
12542 &block_start)))
12543 return retval;
12544 offset = 0;
12545 }
12546 left = fs->blocksize - offset;
12547 dirent = (struct ext2_dir_entry *) (block_start + offset);
12548 if (offset == 0) {
12549 if (ent->hash == prev_hash)
12550 outdir->hashes[outdir->num-1] = ent->hash | 1;
12551 else
12552 outdir->hashes[outdir->num-1] = ent->hash;
12553 }
12554 dirent->inode = ent->dir->inode;
12555 dirent->name_len = ent->dir->name_len;
12556 dirent->rec_len = rec_len;
12557 memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
12558 offset += rec_len;
12559 left -= rec_len;
12560 if (left < 12) {
12561 dirent->rec_len += left;
12562 offset += left;
12563 left = 0;
12564 }
12565 prev_hash = ent->hash;
12566 }
12567 if (left)
12568 dirent->rec_len += left;
12569
12570 return 0;
12571}
12572
12573
12574static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
12575 ext2_ino_t ino, ext2_ino_t parent)
12576{
12577 struct ext2_dir_entry *dir;
12578 struct ext2_dx_root_info *root;
12579 struct ext2_dx_countlimit *limits;
12580 int filetype = 0;
12581
12582 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
12583 filetype = EXT2_FT_DIR << 8;
12584
12585 memset(buf, 0, fs->blocksize);
12586 dir = (struct ext2_dir_entry *) buf;
12587 dir->inode = ino;
12588 dir->name[0] = '.';
12589 dir->name_len = 1 | filetype;
12590 dir->rec_len = 12;
12591 dir = (struct ext2_dir_entry *) (buf + 12);
12592 dir->inode = parent;
12593 dir->name[0] = '.';
12594 dir->name[1] = '.';
12595 dir->name_len = 2 | filetype;
12596 dir->rec_len = fs->blocksize - 12;
12597
12598 root = (struct ext2_dx_root_info *) (buf+24);
12599 root->reserved_zero = 0;
12600 root->hash_version = fs->super->s_def_hash_version;
12601 root->info_length = 8;
12602 root->indirect_levels = 0;
12603 root->unused_flags = 0;
12604
12605 limits = (struct ext2_dx_countlimit *) (buf+32);
12606 limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
12607 limits->count = 0;
12608
12609 return root;
12610}
12611
12612
12613static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
12614{
12615 struct ext2_dir_entry *dir;
12616 struct ext2_dx_countlimit *limits;
12617
12618 memset(buf, 0, fs->blocksize);
12619 dir = (struct ext2_dir_entry *) buf;
12620 dir->inode = 0;
12621 dir->rec_len = fs->blocksize;
12622
12623 limits = (struct ext2_dx_countlimit *) (buf+8);
12624 limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
12625 limits->count = 0;
12626
12627 return (struct ext2_dx_entry *) limits;
12628}
12629
12630/*
12631 * This function takes the leaf nodes which have been written in
12632 * outdir, and populates the root node and any necessary interior nodes.
12633 */
12634static errcode_t calculate_tree(ext2_filsys fs,
12635 struct out_dir *outdir,
12636 ext2_ino_t ino,
12637 ext2_ino_t parent)
12638{
12639 struct ext2_dx_root_info *root_info;
12640 struct ext2_dx_entry *root, *dx_ent = 0;
12641 struct ext2_dx_countlimit *root_limit, *limit;
12642 errcode_t retval;
12643 char * block_start;
12644 int i, c1, c2, nblks;
12645 int limit_offset, root_offset;
12646
12647 root_info = set_root_node(fs, outdir->buf, ino, parent);
12648 root_offset = limit_offset = ((char *) root_info - outdir->buf) +
12649 root_info->info_length;
12650 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
12651 c1 = root_limit->limit;
12652 nblks = outdir->num;
12653
12654 /* Write out the pointer blocks */
12655 if (nblks-1 <= c1) {
12656 /* Just write out the root block, and we're done */
12657 root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
12658 for (i=1; i < nblks; i++) {
12659 root->block = ext2fs_cpu_to_le32(i);
12660 if (i != 1)
12661 root->hash =
12662 ext2fs_cpu_to_le32(outdir->hashes[i]);
12663 root++;
12664 c1--;
12665 }
12666 } else {
12667 c2 = 0;
12668 limit = 0;
12669 root_info->indirect_levels = 1;
12670 for (i=1; i < nblks; i++) {
12671 if (c1 == 0)
12672 return ENOSPC;
12673 if (c2 == 0) {
12674 if (limit)
12675 limit->limit = limit->count =
12676 ext2fs_cpu_to_le16(limit->limit);
12677 root = (struct ext2_dx_entry *)
12678 (outdir->buf + root_offset);
12679 root->block = ext2fs_cpu_to_le32(outdir->num);
12680 if (i != 1)
12681 root->hash =
12682 ext2fs_cpu_to_le32(outdir->hashes[i]);
12683 if ((retval = get_next_block(fs, outdir,
12684 &block_start)))
12685 return retval;
12686 dx_ent = set_int_node(fs, block_start);
12687 limit = (struct ext2_dx_countlimit *) dx_ent;
12688 c2 = limit->limit;
12689 root_offset += sizeof(struct ext2_dx_entry);
12690 c1--;
12691 }
12692 dx_ent->block = ext2fs_cpu_to_le32(i);
12693 if (c2 != limit->limit)
12694 dx_ent->hash =
12695 ext2fs_cpu_to_le32(outdir->hashes[i]);
12696 dx_ent++;
12697 c2--;
12698 }
12699 limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
12700 limit->limit = ext2fs_cpu_to_le16(limit->limit);
12701 }
12702 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
12703 root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
12704 root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
12705
12706 return 0;
12707}
12708
12709struct write_dir_struct {
12710 struct out_dir *outdir;
12711 errcode_t err;
12712 e2fsck_t ctx;
12713 int cleared;
12714};
12715
12716/*
12717 * Helper function which writes out a directory block.
12718 */
12719static int write_dir_block(ext2_filsys fs,
12720 blk_t *block_nr,
12721 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000012722 blk_t ref_block FSCK_ATTR((unused)),
12723 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012724 void *priv_data)
12725{
12726 struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
12727 blk_t blk;
12728 char *dir;
12729
12730 if (*block_nr == 0)
12731 return 0;
12732 if (blockcnt >= wd->outdir->num) {
12733 e2fsck_read_bitmaps(wd->ctx);
12734 blk = *block_nr;
12735 ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
12736 ext2fs_block_alloc_stats(fs, blk, -1);
12737 *block_nr = 0;
12738 wd->cleared++;
12739 return BLOCK_CHANGED;
12740 }
12741 if (blockcnt < 0)
12742 return 0;
12743
12744 dir = wd->outdir->buf + (blockcnt * fs->blocksize);
12745 wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
12746 if (wd->err)
12747 return BLOCK_ABORT;
12748 return 0;
12749}
12750
12751static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
12752 struct out_dir *outdir,
12753 ext2_ino_t ino, int compress)
12754{
12755 struct write_dir_struct wd;
12756 errcode_t retval;
12757 struct ext2_inode inode;
12758
12759 retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
12760 if (retval)
12761 return retval;
12762
12763 wd.outdir = outdir;
12764 wd.err = 0;
12765 wd.ctx = ctx;
12766 wd.cleared = 0;
12767
12768 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
12769 write_dir_block, &wd);
12770 if (retval)
12771 return retval;
12772 if (wd.err)
12773 return wd.err;
12774
12775 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
12776 if (compress)
12777 inode.i_flags &= ~EXT2_INDEX_FL;
12778 else
12779 inode.i_flags |= EXT2_INDEX_FL;
12780 inode.i_size = outdir->num * fs->blocksize;
12781 inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
12782 e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
12783
12784 return 0;
12785}
12786
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012787static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012788{
12789 ext2_filsys fs = ctx->fs;
12790 errcode_t retval;
12791 struct ext2_inode inode;
12792 char *dir_buf = 0;
12793 struct fill_dir_struct fd;
12794 struct out_dir outdir;
12795
12796 outdir.max = outdir.num = 0;
12797 outdir.buf = 0;
12798 outdir.hashes = 0;
12799 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
12800
12801 retval = ENOMEM;
12802 fd.harray = 0;
12803 dir_buf = malloc(inode.i_size);
12804 if (!dir_buf)
12805 goto errout;
12806
12807 fd.max_array = inode.i_size / 32;
12808 fd.num_array = 0;
12809 fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
12810 if (!fd.harray)
12811 goto errout;
12812
12813 fd.ctx = ctx;
12814 fd.buf = dir_buf;
12815 fd.inode = &inode;
12816 fd.err = 0;
12817 fd.dir_size = 0;
12818 fd.compress = 0;
12819 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
12820 (inode.i_size / fs->blocksize) < 2)
12821 fd.compress = 1;
12822 fd.parent = 0;
12823
12824 /* Read in the entire directory into memory */
12825 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
12826 fill_dir_block, &fd);
12827 if (fd.err) {
12828 retval = fd.err;
12829 goto errout;
12830 }
12831
12832#if 0
12833 printf("%d entries (%d bytes) found in inode %d\n",
12834 fd.num_array, fd.dir_size, ino);
12835#endif
12836
12837 /* Sort the list */
12838resort:
12839 if (fd.compress)
12840 qsort(fd.harray+2, fd.num_array-2,
12841 sizeof(struct hash_entry), name_cmp);
12842 else
12843 qsort(fd.harray, fd.num_array,
12844 sizeof(struct hash_entry), hash_cmp);
12845
12846 /*
12847 * Look for duplicates
12848 */
12849 if (duplicate_search_and_fix(ctx, fs, ino, &fd))
12850 goto resort;
12851
12852 if (ctx->options & E2F_OPT_NO) {
12853 retval = 0;
12854 goto errout;
12855 }
12856
12857 /*
12858 * Copy the directory entries. In a htree directory these
12859 * will become the leaf nodes.
12860 */
12861 retval = copy_dir_entries(fs, &fd, &outdir);
12862 if (retval)
12863 goto errout;
12864
12865 free(dir_buf); dir_buf = 0;
12866
12867 if (!fd.compress) {
12868 /* Calculate the interior nodes */
12869 retval = calculate_tree(fs, &outdir, ino, fd.parent);
12870 if (retval)
12871 goto errout;
12872 }
12873
12874 retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
12875 if (retval)
12876 goto errout;
12877
12878errout:
12879 if (dir_buf)
12880 free(dir_buf);
12881 if (fd.harray)
12882 free(fd.harray);
12883
12884 free_out_dir(&outdir);
12885 return retval;
12886}
12887
12888void e2fsck_rehash_directories(e2fsck_t ctx)
12889{
12890 struct problem_context pctx;
12891#ifdef RESOURCE_TRACK
12892 struct resource_track rtrack;
12893#endif
12894 struct dir_info *dir;
12895 ext2_u32_iterate iter;
12896 ext2_ino_t ino;
12897 errcode_t retval;
12898 int i, cur, max, all_dirs, dir_index, first = 1;
12899
12900#ifdef RESOURCE_TRACK
12901 init_resource_track(&rtrack);
12902#endif
12903
12904 all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
12905
12906 if (!ctx->dirs_to_hash && !all_dirs)
12907 return;
12908
12909 e2fsck_get_lost_and_found(ctx, 0);
12910
12911 clear_problem_context(&pctx);
12912
12913 dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
12914 cur = 0;
12915 if (all_dirs) {
12916 i = 0;
12917 max = e2fsck_get_num_dirinfo(ctx);
12918 } else {
12919 retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
12920 &iter);
12921 if (retval) {
12922 pctx.errcode = retval;
12923 fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
12924 return;
12925 }
12926 max = ext2fs_u32_list_count(ctx->dirs_to_hash);
12927 }
12928 while (1) {
12929 if (all_dirs) {
12930 if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
12931 break;
12932 ino = dir->ino;
12933 } else {
12934 if (!ext2fs_u32_list_iterate(iter, &ino))
12935 break;
12936 }
12937 if (ino == ctx->lost_and_found)
12938 continue;
12939 pctx.dir = ino;
12940 if (first) {
12941 fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
12942 first = 0;
12943 }
12944#if 0
12945 fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx);
12946#endif
12947 pctx.errcode = e2fsck_rehash_dir(ctx, ino);
12948 if (pctx.errcode) {
12949 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
12950 fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
12951 }
12952 if (ctx->progress && !ctx->progress_fd)
12953 e2fsck_simple_progress(ctx, "Rebuilding directory",
12954 100.0 * (float) (++cur) / (float) max, ino);
12955 }
12956 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
12957 if (!all_dirs)
12958 ext2fs_u32_list_iterate_end(iter);
12959
12960 if (ctx->dirs_to_hash)
12961 ext2fs_u32_list_free(ctx->dirs_to_hash);
12962 ctx->dirs_to_hash = 0;
12963
12964#ifdef RESOURCE_TRACK
12965 if (ctx->options & E2F_OPT_TIME2) {
12966 e2fsck_clear_progbar(ctx);
12967 print_resource_track("Pass 3A", &rtrack);
12968 }
12969#endif
12970}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012971
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012972/*
12973 * linux/fs/revoke.c
12974 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012975 * Journal revoke routines for the generic filesystem journaling code;
12976 * part of the ext2fs journaling system.
12977 *
12978 * Revoke is the mechanism used to prevent old log records for deleted
12979 * metadata from being replayed on top of newer data using the same
12980 * blocks. The revoke mechanism is used in two separate places:
12981 *
12982 * + Commit: during commit we write the entire list of the current
12983 * transaction's revoked blocks to the journal
12984 *
12985 * + Recovery: during recovery we record the transaction ID of all
12986 * revoked blocks. If there are multiple revoke records in the log
12987 * for a single block, only the last one counts, and if there is a log
12988 * entry for a block beyond the last revoke, then that log entry still
12989 * gets replayed.
12990 *
12991 * We can get interactions between revokes and new log data within a
12992 * single transaction:
12993 *
12994 * Block is revoked and then journaled:
12995 * The desired end result is the journaling of the new block, so we
12996 * cancel the revoke before the transaction commits.
12997 *
12998 * Block is journaled and then revoked:
12999 * The revoke must take precedence over the write of the block, so we
13000 * need either to cancel the journal entry or to write the revoke
13001 * later in the log than the log block. In this case, we choose the
13002 * latter: journaling a block cancels any revoke record for that block
13003 * in the current transaction, so any revoke for that block in the
13004 * transaction must have happened after the block was journaled and so
13005 * the revoke must take precedence.
13006 *
13007 * Block is revoked and then written as data:
13008 * The data write is allowed to succeed, but the revoke is _not_
13009 * cancelled. We still need to prevent old log records from
13010 * overwriting the new data. We don't even need to clear the revoke
13011 * bit here.
13012 *
13013 * Revoke information on buffers is a tri-state value:
13014 *
13015 * RevokeValid clear: no cached revoke status, need to look it up
13016 * RevokeValid set, Revoked clear:
13017 * buffer has not been revoked, and cancel_revoke
13018 * need do nothing.
13019 * RevokeValid set, Revoked set:
13020 * buffer has been revoked.
13021 */
13022
13023static kmem_cache_t *revoke_record_cache;
13024static kmem_cache_t *revoke_table_cache;
13025
13026/* Each revoke record represents one single revoked block. During
13027 journal replay, this involves recording the transaction ID of the
13028 last transaction to revoke this block. */
13029
13030struct jbd_revoke_record_s
13031{
13032 struct list_head hash;
13033 tid_t sequence; /* Used for recovery only */
13034 unsigned long blocknr;
13035};
13036
13037
13038/* The revoke table is just a simple hash table of revoke records. */
13039struct jbd_revoke_table_s
13040{
13041 /* It is conceivable that we might want a larger hash table
13042 * for recovery. Must be a power of two. */
13043 int hash_size;
13044 int hash_shift;
13045 struct list_head *hash_table;
13046};
13047
13048
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013049/* Utility functions to maintain the revoke table */
13050
13051/* Borrowed from buffer.c: this is a tried and tested block hash function */
13052static inline int hash(journal_t *journal, unsigned long block)
13053{
13054 struct jbd_revoke_table_s *table = journal->j_revoke;
13055 int hash_shift = table->hash_shift;
13056
13057 return ((block << (hash_shift - 6)) ^
13058 (block >> 13) ^
13059 (block << (hash_shift - 12))) & (table->hash_size - 1);
13060}
13061
13062static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
13063 tid_t seq)
13064{
13065 struct list_head *hash_list;
13066 struct jbd_revoke_record_s *record;
13067
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013068 record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
13069 if (!record)
13070 goto oom;
13071
13072 record->sequence = seq;
13073 record->blocknr = blocknr;
13074 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13075 list_add(&record->hash, hash_list);
13076 return 0;
13077
13078oom:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013079 return -ENOMEM;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013080}
13081
13082/* Find a revoke record in the journal's hash table. */
13083
13084static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
13085 unsigned long blocknr)
13086{
13087 struct list_head *hash_list;
13088 struct jbd_revoke_record_s *record;
13089
13090 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13091
13092 record = (struct jbd_revoke_record_s *) hash_list->next;
13093 while (&(record->hash) != hash_list) {
13094 if (record->blocknr == blocknr)
13095 return record;
13096 record = (struct jbd_revoke_record_s *) record->hash.next;
13097 }
13098 return NULL;
13099}
13100
13101int journal_init_revoke_caches(void)
13102{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013103 revoke_record_cache = do_cache_create(sizeof(struct jbd_revoke_record_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013104 if (revoke_record_cache == 0)
13105 return -ENOMEM;
13106
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013107 revoke_table_cache = do_cache_create(sizeof(struct jbd_revoke_table_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013108 if (revoke_table_cache == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013109 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013110 revoke_record_cache = NULL;
13111 return -ENOMEM;
13112 }
13113 return 0;
13114}
13115
13116void journal_destroy_revoke_caches(void)
13117{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013118 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013119 revoke_record_cache = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013120 do_cache_destroy(revoke_table_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013121 revoke_table_cache = 0;
13122}
13123
13124/* Initialise the revoke table for a given journal to a given size. */
13125
13126int journal_init_revoke(journal_t *journal, int hash_size)
13127{
13128 int shift, tmp;
13129
13130 J_ASSERT (journal->j_revoke == NULL);
13131
13132 journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
13133 if (!journal->j_revoke)
13134 return -ENOMEM;
13135
13136 /* Check that the hash_size is a power of two */
13137 J_ASSERT ((hash_size & (hash_size-1)) == 0);
13138
13139 journal->j_revoke->hash_size = hash_size;
13140
13141 shift = 0;
13142 tmp = hash_size;
13143 while((tmp >>= 1UL) != 0UL)
13144 shift++;
13145 journal->j_revoke->hash_shift = shift;
13146
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013147 journal->j_revoke->hash_table = malloc(hash_size * sizeof(struct list_head));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013148 if (!journal->j_revoke->hash_table) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013149 free(journal->j_revoke);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013150 journal->j_revoke = NULL;
13151 return -ENOMEM;
13152 }
13153
13154 for (tmp = 0; tmp < hash_size; tmp++)
13155 INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
13156
13157 return 0;
13158}
13159
13160/* Destoy a journal's revoke table. The table must already be empty! */
13161
13162void journal_destroy_revoke(journal_t *journal)
13163{
13164 struct jbd_revoke_table_s *table;
13165 struct list_head *hash_list;
13166 int i;
13167
13168 table = journal->j_revoke;
13169 if (!table)
13170 return;
13171
13172 for (i=0; i<table->hash_size; i++) {
13173 hash_list = &table->hash_table[i];
13174 J_ASSERT (list_empty(hash_list));
13175 }
13176
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013177 free(table->hash_table);
13178 free(table);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013179 journal->j_revoke = NULL;
13180}
13181
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013182/*
13183 * Revoke support for recovery.
13184 *
13185 * Recovery needs to be able to:
13186 *
13187 * record all revoke records, including the tid of the latest instance
13188 * of each revoke in the journal
13189 *
13190 * check whether a given block in a given transaction should be replayed
13191 * (ie. has not been revoked by a revoke record in that or a subsequent
13192 * transaction)
13193 *
13194 * empty the revoke table after recovery.
13195 */
13196
13197/*
13198 * First, setting revoke records. We create a new revoke record for
13199 * every block ever revoked in the log as we scan it for recovery, and
13200 * we update the existing records if we find multiple revokes for a
13201 * single block.
13202 */
13203
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013204int journal_set_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013205 tid_t sequence)
13206{
13207 struct jbd_revoke_record_s *record;
13208
13209 record = find_revoke_record(journal, blocknr);
13210 if (record) {
13211 /* If we have multiple occurences, only record the
13212 * latest sequence number in the hashed record */
13213 if (tid_gt(sequence, record->sequence))
13214 record->sequence = sequence;
13215 return 0;
13216 }
13217 return insert_revoke_hash(journal, blocknr, sequence);
13218}
13219
13220/*
13221 * Test revoke records. For a given block referenced in the log, has
13222 * that block been revoked? A revoke record with a given transaction
13223 * sequence number revokes all blocks in that transaction and earlier
13224 * ones, but later transactions still need replayed.
13225 */
13226
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013227int journal_test_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013228 tid_t sequence)
13229{
13230 struct jbd_revoke_record_s *record;
13231
13232 record = find_revoke_record(journal, blocknr);
13233 if (!record)
13234 return 0;
13235 if (tid_gt(sequence, record->sequence))
13236 return 0;
13237 return 1;
13238}
13239
13240/*
13241 * Finally, once recovery is over, we need to clear the revoke table so
13242 * that it can be reused by the running filesystem.
13243 */
13244
13245void journal_clear_revoke(journal_t *journal)
13246{
13247 int i;
13248 struct list_head *hash_list;
13249 struct jbd_revoke_record_s *record;
13250 struct jbd_revoke_table_s *revoke_var;
13251
13252 revoke_var = journal->j_revoke;
13253
13254 for (i = 0; i < revoke_var->hash_size; i++) {
13255 hash_list = &revoke_var->hash_table[i];
13256 while (!list_empty(hash_list)) {
13257 record = (struct jbd_revoke_record_s*) hash_list->next;
13258 list_del(&record->hash);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013259 free(record);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013260 }
13261 }
13262}
13263
13264/*
13265 * e2fsck.c - superblock checks
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013266 */
13267
13268#define MIN_CHECK 1
13269#define MAX_CHECK 2
13270
13271static void check_super_value(e2fsck_t ctx, const char *descr,
13272 unsigned long value, int flags,
13273 unsigned long min_val, unsigned long max_val)
13274{
13275 struct problem_context pctx;
13276
13277 if (((flags & MIN_CHECK) && (value < min_val)) ||
13278 ((flags & MAX_CHECK) && (value > max_val))) {
13279 clear_problem_context(&pctx);
13280 pctx.num = value;
13281 pctx.str = descr;
13282 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
13283 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
13284 }
13285}
13286
13287/*
13288 * This routine may get stubbed out in special compilations of the
13289 * e2fsck code..
13290 */
13291#ifndef EXT2_SPECIAL_DEVICE_SIZE
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013292static errcode_t e2fsck_get_device_size(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013293{
13294 return (ext2fs_get_device_size(ctx->filesystem_name,
13295 EXT2_BLOCK_SIZE(ctx->fs->super),
13296 &ctx->num_blocks));
13297}
13298#endif
13299
13300/*
13301 * helper function to release an inode
13302 */
13303struct process_block_struct {
13304 e2fsck_t ctx;
13305 char *buf;
13306 struct problem_context *pctx;
13307 int truncating;
13308 int truncate_offset;
13309 e2_blkcnt_t truncate_block;
13310 int truncated_blocks;
13311 int abort;
13312 errcode_t errcode;
13313};
13314
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013315static int release_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013316 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000013317 blk_t ref_blk FSCK_ATTR((unused)),
13318 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013319 void *priv_data)
13320{
13321 struct process_block_struct *pb;
13322 e2fsck_t ctx;
13323 struct problem_context *pctx;
13324 blk_t blk = *block_nr;
13325 int retval = 0;
13326
13327 pb = (struct process_block_struct *) priv_data;
13328 ctx = pb->ctx;
13329 pctx = pb->pctx;
13330
13331 pctx->blk = blk;
13332 pctx->blkcount = blockcnt;
13333
13334 if (HOLE_BLKADDR(blk))
13335 return 0;
13336
13337 if ((blk < fs->super->s_first_data_block) ||
13338 (blk >= fs->super->s_blocks_count)) {
13339 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
13340 return_abort:
13341 pb->abort = 1;
13342 return BLOCK_ABORT;
13343 }
13344
13345 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
13346 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
13347 goto return_abort;
13348 }
13349
13350 /*
13351 * If we are deleting an orphan, then we leave the fields alone.
13352 * If we are truncating an orphan, then update the inode fields
13353 * and clean up any partial block data.
13354 */
13355 if (pb->truncating) {
13356 /*
13357 * We only remove indirect blocks if they are
13358 * completely empty.
13359 */
13360 if (blockcnt < 0) {
13361 int i, limit;
13362 blk_t *bp;
13363
13364 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
13365 pb->buf);
13366 if (pb->errcode)
13367 goto return_abort;
13368
13369 limit = fs->blocksize >> 2;
13370 for (i = 0, bp = (blk_t *) pb->buf;
13371 i < limit; i++, bp++)
13372 if (*bp)
13373 return 0;
13374 }
13375 /*
13376 * We don't remove direct blocks until we've reached
13377 * the truncation block.
13378 */
13379 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
13380 return 0;
13381 /*
13382 * If part of the last block needs truncating, we do
13383 * it here.
13384 */
13385 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
13386 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
13387 pb->buf);
13388 if (pb->errcode)
13389 goto return_abort;
13390 memset(pb->buf + pb->truncate_offset, 0,
13391 fs->blocksize - pb->truncate_offset);
13392 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
13393 pb->buf);
13394 if (pb->errcode)
13395 goto return_abort;
13396 }
13397 pb->truncated_blocks++;
13398 *block_nr = 0;
13399 retval |= BLOCK_CHANGED;
13400 }
13401
13402 ext2fs_block_alloc_stats(fs, blk, -1);
13403 return retval;
13404}
13405
13406/*
13407 * This function releases an inode. Returns 1 if an inconsistency was
13408 * found. If the inode has a link count, then it is being truncated and
13409 * not deleted.
13410 */
13411static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
13412 struct ext2_inode *inode, char *block_buf,
13413 struct problem_context *pctx)
13414{
13415 struct process_block_struct pb;
13416 ext2_filsys fs = ctx->fs;
13417 errcode_t retval;
13418 __u32 count;
13419
13420 if (!ext2fs_inode_has_valid_blocks(inode))
13421 return 0;
13422
13423 pb.buf = block_buf + 3 * ctx->fs->blocksize;
13424 pb.ctx = ctx;
13425 pb.abort = 0;
13426 pb.errcode = 0;
13427 pb.pctx = pctx;
13428 if (inode->i_links_count) {
13429 pb.truncating = 1;
13430 pb.truncate_block = (e2_blkcnt_t)
13431 ((((long long)inode->i_size_high << 32) +
13432 inode->i_size + fs->blocksize - 1) /
13433 fs->blocksize);
13434 pb.truncate_offset = inode->i_size % fs->blocksize;
13435 } else {
13436 pb.truncating = 0;
13437 pb.truncate_block = 0;
13438 pb.truncate_offset = 0;
13439 }
13440 pb.truncated_blocks = 0;
13441 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
13442 block_buf, release_inode_block, &pb);
13443 if (retval) {
13444 com_err("release_inode_blocks", retval,
13445 _("while calling ext2fs_block_iterate for inode %d"),
13446 ino);
13447 return 1;
13448 }
13449 if (pb.abort)
13450 return 1;
13451
13452 /* Refresh the inode since ext2fs_block_iterate may have changed it */
13453 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
13454
13455 if (pb.truncated_blocks)
13456 inode->i_blocks -= pb.truncated_blocks *
13457 (fs->blocksize / 512);
13458
13459 if (inode->i_file_acl) {
13460 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
13461 block_buf, -1, &count);
13462 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
13463 retval = 0;
13464 count = 1;
13465 }
13466 if (retval) {
13467 com_err("release_inode_blocks", retval,
13468 _("while calling ext2fs_adjust_ea_refocunt for inode %d"),
13469 ino);
13470 return 1;
13471 }
13472 if (count == 0)
13473 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
13474 inode->i_file_acl = 0;
13475 }
13476 return 0;
13477}
13478
13479/*
13480 * This function releases all of the orphan inodes. It returns 1 if
13481 * it hit some error, and 0 on success.
13482 */
13483static int release_orphan_inodes(e2fsck_t ctx)
13484{
13485 ext2_filsys fs = ctx->fs;
13486 ext2_ino_t ino, next_ino;
13487 struct ext2_inode inode;
13488 struct problem_context pctx;
13489 char *block_buf;
13490
13491 if ((ino = fs->super->s_last_orphan) == 0)
13492 return 0;
13493
13494 /*
13495 * Win or lose, we won't be using the head of the orphan inode
13496 * list again.
13497 */
13498 fs->super->s_last_orphan = 0;
13499 ext2fs_mark_super_dirty(fs);
13500
13501 /*
13502 * If the filesystem contains errors, don't run the orphan
13503 * list, since the orphan list can't be trusted; and we're
13504 * going to be running a full e2fsck run anyway...
13505 */
13506 if (fs->super->s_state & EXT2_ERROR_FS)
13507 return 0;
13508
13509 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
13510 (ino > fs->super->s_inodes_count)) {
13511 clear_problem_context(&pctx);
13512 pctx.ino = ino;
13513 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
13514 return 1;
13515 }
13516
13517 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
13518 "block iterate buffer");
13519 e2fsck_read_bitmaps(ctx);
13520
13521 while (ino) {
13522 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
13523 clear_problem_context(&pctx);
13524 pctx.ino = ino;
13525 pctx.inode = &inode;
13526 pctx.str = inode.i_links_count ? _("Truncating") :
13527 _("Clearing");
13528
13529 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
13530
13531 next_ino = inode.i_dtime;
13532 if (next_ino &&
13533 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
13534 (next_ino > fs->super->s_inodes_count))) {
13535 pctx.ino = next_ino;
13536 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
13537 goto return_abort;
13538 }
13539
13540 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
13541 goto return_abort;
13542
13543 if (!inode.i_links_count) {
13544 ext2fs_inode_alloc_stats2(fs, ino, -1,
13545 LINUX_S_ISDIR(inode.i_mode));
13546 inode.i_dtime = time(0);
13547 } else {
13548 inode.i_dtime = 0;
13549 }
13550 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
13551 ino = next_ino;
13552 }
13553 ext2fs_free_mem(&block_buf);
13554 return 0;
13555return_abort:
13556 ext2fs_free_mem(&block_buf);
13557 return 1;
13558}
13559
13560/*
13561 * Check the resize inode to make sure it is sane. We check both for
13562 * the case where on-line resizing is not enabled (in which case the
13563 * resize inode should be cleared) as well as the case where on-line
13564 * resizing is enabled.
13565 */
13566static void check_resize_inode(e2fsck_t ctx)
13567{
13568 ext2_filsys fs = ctx->fs;
13569 struct ext2_inode inode;
13570 struct problem_context pctx;
13571 int i, j, gdt_off, ind_off;
13572 blk_t blk, pblk, expect;
13573 __u32 *dind_buf = 0, *ind_buf;
13574 errcode_t retval;
13575
13576 clear_problem_context(&pctx);
13577
13578 /*
13579 * If the resize inode feature isn't set, then
13580 * s_reserved_gdt_blocks must be zero.
13581 */
13582 if (!(fs->super->s_feature_compat &
13583 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
13584 if (fs->super->s_reserved_gdt_blocks) {
13585 pctx.num = fs->super->s_reserved_gdt_blocks;
13586 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
13587 &pctx)) {
13588 fs->super->s_reserved_gdt_blocks = 0;
13589 ext2fs_mark_super_dirty(fs);
13590 }
13591 }
13592 }
13593
13594 /* Read the resizde inode */
13595 pctx.ino = EXT2_RESIZE_INO;
13596 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
13597 if (retval) {
13598 if (fs->super->s_feature_compat &
13599 EXT2_FEATURE_COMPAT_RESIZE_INODE)
13600 ctx->flags |= E2F_FLAG_RESIZE_INODE;
13601 return;
13602 }
13603
13604 /*
13605 * If the resize inode feature isn't set, check to make sure
13606 * the resize inode is cleared; then we're done.
13607 */
13608 if (!(fs->super->s_feature_compat &
13609 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
13610 for (i=0; i < EXT2_N_BLOCKS; i++) {
13611 if (inode.i_block[i])
13612 break;
13613 }
13614 if ((i < EXT2_N_BLOCKS) &&
13615 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
13616 memset(&inode, 0, sizeof(inode));
13617 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
13618 "clear_resize");
13619 }
13620 return;
13621 }
13622
13623 /*
13624 * The resize inode feature is enabled; check to make sure the
13625 * only block in use is the double indirect block
13626 */
13627 blk = inode.i_block[EXT2_DIND_BLOCK];
13628 for (i=0; i < EXT2_N_BLOCKS; i++) {
13629 if (i != EXT2_DIND_BLOCK && inode.i_block[i])
13630 break;
13631 }
13632 if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
13633 !(inode.i_mode & LINUX_S_IFREG) ||
13634 (blk < fs->super->s_first_data_block ||
13635 blk >= fs->super->s_blocks_count)) {
13636 resize_inode_invalid:
13637 if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
13638 memset(&inode, 0, sizeof(inode));
13639 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
13640 "clear_resize");
13641 ctx->flags |= E2F_FLAG_RESIZE_INODE;
13642 }
13643 if (!(ctx->options & E2F_OPT_READONLY)) {
13644 fs->super->s_state &= ~EXT2_VALID_FS;
13645 ext2fs_mark_super_dirty(fs);
13646 }
13647 goto cleanup;
13648 }
13649 dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
13650 "resize dind buffer");
13651 ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
13652
13653 retval = ext2fs_read_ind_block(fs, blk, dind_buf);
13654 if (retval)
13655 goto resize_inode_invalid;
13656
13657 gdt_off = fs->desc_blocks;
13658 pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
13659 for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
13660 i++, gdt_off++, pblk++) {
13661 gdt_off %= fs->blocksize/4;
13662 if (dind_buf[gdt_off] != pblk)
13663 goto resize_inode_invalid;
13664 retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
13665 if (retval)
13666 goto resize_inode_invalid;
13667 ind_off = 0;
13668 for (j = 1; j < fs->group_desc_count; j++) {
13669 if (!ext2fs_bg_has_super(fs, j))
13670 continue;
13671 expect = pblk + (j * fs->super->s_blocks_per_group);
13672 if (ind_buf[ind_off] != expect)
13673 goto resize_inode_invalid;
13674 ind_off++;
13675 }
13676 }
13677
13678cleanup:
13679 if (dind_buf)
13680 ext2fs_free_mem(&dind_buf);
13681
13682 }
13683
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013684static void check_super_block(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013685{
13686 ext2_filsys fs = ctx->fs;
13687 blk_t first_block, last_block;
13688 struct ext2_super_block *sb = fs->super;
13689 struct ext2_group_desc *gd;
13690 blk_t blocks_per_group = fs->super->s_blocks_per_group;
13691 blk_t bpg_max;
13692 int inodes_per_block;
13693 int ipg_max;
13694 int inode_size;
13695 dgrp_t i;
13696 blk_t should_be;
13697 struct problem_context pctx;
13698 __u32 free_blocks = 0, free_inodes = 0;
13699
13700 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
13701 ipg_max = inodes_per_block * (blocks_per_group - 4);
13702 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
13703 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
13704 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
13705 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
13706 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
13707
13708 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
13709 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
13710 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
13711 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
13712 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
13713 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
13714
13715 clear_problem_context(&pctx);
13716
13717 /*
13718 * Verify the super block constants...
13719 */
13720 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
13721 MIN_CHECK, 1, 0);
13722 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
13723 MIN_CHECK, 1, 0);
13724 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
13725 MAX_CHECK, 0, sb->s_blocks_count);
13726 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
13727 MIN_CHECK | MAX_CHECK, 0,
13728 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
13729 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
13730 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
13731 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
13732 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
13733 bpg_max);
13734 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
13735 MIN_CHECK | MAX_CHECK, 8, bpg_max);
13736 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
13737 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
13738 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
13739 MAX_CHECK, 0, sb->s_blocks_count / 2);
13740 check_super_value(ctx, "reserved_gdt_blocks",
13741 sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
13742 fs->blocksize/4);
13743 inode_size = EXT2_INODE_SIZE(sb);
13744 check_super_value(ctx, "inode_size",
13745 inode_size, MIN_CHECK | MAX_CHECK,
13746 EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
13747 if (inode_size & (inode_size - 1)) {
13748 pctx.num = inode_size;
13749 pctx.str = "inode_size";
13750 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
13751 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
13752 return;
13753 }
13754
13755 if (!ctx->num_blocks) {
13756 pctx.errcode = e2fsck_get_device_size(ctx);
13757 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
13758 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
13759 ctx->flags |= E2F_FLAG_ABORT;
13760 return;
13761 }
13762 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
13763 (ctx->num_blocks < sb->s_blocks_count)) {
13764 pctx.blk = sb->s_blocks_count;
13765 pctx.blk2 = ctx->num_blocks;
13766 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
13767 ctx->flags |= E2F_FLAG_ABORT;
13768 return;
13769 }
13770 }
13771 }
13772
13773 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
13774 pctx.blk = EXT2_BLOCK_SIZE(sb);
13775 pctx.blk2 = EXT2_FRAG_SIZE(sb);
13776 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
13777 ctx->flags |= E2F_FLAG_ABORT;
13778 return;
13779 }
13780
13781 should_be = sb->s_frags_per_group >>
13782 (sb->s_log_block_size - sb->s_log_frag_size);
13783 if (sb->s_blocks_per_group != should_be) {
13784 pctx.blk = sb->s_blocks_per_group;
13785 pctx.blk2 = should_be;
13786 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
13787 ctx->flags |= E2F_FLAG_ABORT;
13788 return;
13789 }
13790
13791 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
13792 if (sb->s_first_data_block != should_be) {
13793 pctx.blk = sb->s_first_data_block;
13794 pctx.blk2 = should_be;
13795 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
13796 ctx->flags |= E2F_FLAG_ABORT;
13797 return;
13798 }
13799
13800 should_be = sb->s_inodes_per_group * fs->group_desc_count;
13801 if (sb->s_inodes_count != should_be) {
13802 pctx.ino = sb->s_inodes_count;
13803 pctx.ino2 = should_be;
13804 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
13805 sb->s_inodes_count = should_be;
13806 ext2fs_mark_super_dirty(fs);
13807 }
13808 }
13809
13810 /*
13811 * Verify the group descriptors....
13812 */
13813 first_block = sb->s_first_data_block;
13814 last_block = first_block + blocks_per_group;
13815
13816 for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
13817 pctx.group = i;
13818
13819 if (i == fs->group_desc_count - 1)
13820 last_block = sb->s_blocks_count;
13821 if ((gd->bg_block_bitmap < first_block) ||
13822 (gd->bg_block_bitmap >= last_block)) {
13823 pctx.blk = gd->bg_block_bitmap;
13824 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
13825 gd->bg_block_bitmap = 0;
13826 }
13827 if (gd->bg_block_bitmap == 0) {
13828 ctx->invalid_block_bitmap_flag[i]++;
13829 ctx->invalid_bitmaps++;
13830 }
13831 if ((gd->bg_inode_bitmap < first_block) ||
13832 (gd->bg_inode_bitmap >= last_block)) {
13833 pctx.blk = gd->bg_inode_bitmap;
13834 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
13835 gd->bg_inode_bitmap = 0;
13836 }
13837 if (gd->bg_inode_bitmap == 0) {
13838 ctx->invalid_inode_bitmap_flag[i]++;
13839 ctx->invalid_bitmaps++;
13840 }
13841 if ((gd->bg_inode_table < first_block) ||
13842 ((gd->bg_inode_table +
13843 fs->inode_blocks_per_group - 1) >= last_block)) {
13844 pctx.blk = gd->bg_inode_table;
13845 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
13846 gd->bg_inode_table = 0;
13847 }
13848 if (gd->bg_inode_table == 0) {
13849 ctx->invalid_inode_table_flag[i]++;
13850 ctx->invalid_bitmaps++;
13851 }
13852 free_blocks += gd->bg_free_blocks_count;
13853 free_inodes += gd->bg_free_inodes_count;
13854 first_block += sb->s_blocks_per_group;
13855 last_block += sb->s_blocks_per_group;
13856
13857 if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
13858 (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
13859 (gd->bg_used_dirs_count > sb->s_inodes_per_group))
13860 ext2fs_unmark_valid(fs);
13861
13862 }
13863
13864 /*
13865 * Update the global counts from the block group counts. This
13866 * is needed for an experimental patch which eliminates
13867 * locking the entire filesystem when allocating blocks or
13868 * inodes; if the filesystem is not unmounted cleanly, the
13869 * global counts may not be accurate.
13870 */
13871 if ((free_blocks != sb->s_free_blocks_count) ||
13872 (free_inodes != sb->s_free_inodes_count)) {
13873 if (ctx->options & E2F_OPT_READONLY)
13874 ext2fs_unmark_valid(fs);
13875 else {
13876 sb->s_free_blocks_count = free_blocks;
13877 sb->s_free_inodes_count = free_inodes;
13878 ext2fs_mark_super_dirty(fs);
13879 }
13880 }
13881
13882 if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
13883 (sb->s_free_inodes_count > sb->s_inodes_count))
13884 ext2fs_unmark_valid(fs);
13885
13886
13887 /*
13888 * If we have invalid bitmaps, set the error state of the
13889 * filesystem.
13890 */
13891 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
13892 sb->s_state &= ~EXT2_VALID_FS;
13893 ext2fs_mark_super_dirty(fs);
13894 }
13895
13896 clear_problem_context(&pctx);
13897
13898#ifndef EXT2_SKIP_UUID
13899 /*
13900 * If the UUID field isn't assigned, assign it.
13901 */
13902 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
13903 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
13904 uuid_generate(sb->s_uuid);
13905 ext2fs_mark_super_dirty(fs);
13906 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
13907 }
13908 }
13909#endif
13910
13911 /*
13912 * For the Hurd, check to see if the filetype option is set,
13913 * since it doesn't support it.
13914 */
13915 if (!(ctx->options & E2F_OPT_READONLY) &&
13916 fs->super->s_creator_os == EXT2_OS_HURD &&
13917 (fs->super->s_feature_incompat &
13918 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
13919 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
13920 fs->super->s_feature_incompat &=
13921 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
13922 ext2fs_mark_super_dirty(fs);
13923
13924 }
13925 }
13926
13927 /*
13928 * If we have any of the compatibility flags set, we need to have a
13929 * revision 1 filesystem. Most kernels will not check the flags on
13930 * a rev 0 filesystem and we may have corruption issues because of
13931 * the incompatible changes to the filesystem.
13932 */
13933 if (!(ctx->options & E2F_OPT_READONLY) &&
13934 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
13935 (fs->super->s_feature_compat ||
13936 fs->super->s_feature_ro_compat ||
13937 fs->super->s_feature_incompat) &&
13938 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
13939 ext2fs_update_dynamic_rev(fs);
13940 ext2fs_mark_super_dirty(fs);
13941 }
13942
13943 check_resize_inode(ctx);
13944
13945 /*
13946 * Clean up any orphan inodes, if present.
13947 */
13948 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
13949 fs->super->s_state &= ~EXT2_VALID_FS;
13950 ext2fs_mark_super_dirty(fs);
13951 }
13952
13953 /*
13954 * Move the ext3 journal file, if necessary.
13955 */
13956 e2fsck_move_ext3_journal(ctx);
13957 return;
13958}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013959
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013960/*
13961 * swapfs.c --- byte-swap an ext2 filesystem
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013962 */
13963
13964#ifdef ENABLE_SWAPFS
13965
13966struct swap_block_struct {
13967 ext2_ino_t ino;
13968 int isdir;
13969 errcode_t errcode;
13970 char *dir_buf;
13971 struct ext2_inode *inode;
13972};
13973
13974/*
13975 * This is a helper function for block_iterate. We mark all of the
13976 * indirect and direct blocks as changed, so that block_iterate will
13977 * write them out.
13978 */
13979static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
13980 void *priv_data)
13981{
13982 errcode_t retval;
13983
13984 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
13985
13986 if (sb->isdir && (blockcnt >= 0) && *block_nr) {
13987 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
13988 if (retval) {
13989 sb->errcode = retval;
13990 return BLOCK_ABORT;
13991 }
13992 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
13993 if (retval) {
13994 sb->errcode = retval;
13995 return BLOCK_ABORT;
13996 }
13997 }
13998 if (blockcnt >= 0) {
13999 if (blockcnt < EXT2_NDIR_BLOCKS)
14000 return 0;
14001 return BLOCK_CHANGED;
14002 }
14003 if (blockcnt == BLOCK_COUNT_IND) {
14004 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
14005 return 0;
14006 return BLOCK_CHANGED;
14007 }
14008 if (blockcnt == BLOCK_COUNT_DIND) {
14009 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
14010 return 0;
14011 return BLOCK_CHANGED;
14012 }
14013 if (blockcnt == BLOCK_COUNT_TIND) {
14014 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
14015 return 0;
14016 return BLOCK_CHANGED;
14017 }
14018 return BLOCK_CHANGED;
14019}
14020
14021/*
14022 * This function is responsible for byte-swapping all of the indirect,
14023 * block pointers. It is also responsible for byte-swapping directories.
14024 */
14025static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
14026 struct ext2_inode *inode)
14027{
14028 errcode_t retval;
14029 struct swap_block_struct sb;
14030
14031 sb.ino = ino;
14032 sb.inode = inode;
14033 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
14034 sb.errcode = 0;
14035 sb.isdir = 0;
14036 if (LINUX_S_ISDIR(inode->i_mode))
14037 sb.isdir = 1;
14038
14039 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
14040 swap_block, &sb);
14041 if (retval) {
14042 com_err("swap_inode_blocks", retval,
14043 _("while calling ext2fs_block_iterate"));
14044 ctx->flags |= E2F_FLAG_ABORT;
14045 return;
14046 }
14047 if (sb.errcode) {
14048 com_err("swap_inode_blocks", sb.errcode,
14049 _("while calling iterator function"));
14050 ctx->flags |= E2F_FLAG_ABORT;
14051 return;
14052 }
14053}
14054
14055static void swap_inodes(e2fsck_t ctx)
14056{
14057 ext2_filsys fs = ctx->fs;
14058 dgrp_t group;
14059 unsigned int i;
14060 ext2_ino_t ino = 1;
14061 char *buf, *block_buf;
14062 errcode_t retval;
14063 struct ext2_inode * inode;
14064
14065 e2fsck_use_inode_shortcuts(ctx, 1);
14066
14067 retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
14068 &buf);
14069 if (retval) {
14070 com_err("swap_inodes", retval,
14071 _("while allocating inode buffer"));
14072 ctx->flags |= E2F_FLAG_ABORT;
14073 return;
14074 }
14075 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
14076 "block interate buffer");
14077 for (group = 0; group < fs->group_desc_count; group++) {
14078 retval = io_channel_read_blk(fs->io,
14079 fs->group_desc[group].bg_inode_table,
14080 fs->inode_blocks_per_group, buf);
14081 if (retval) {
14082 com_err("swap_inodes", retval,
14083 _("while reading inode table (group %d)"),
14084 group);
14085 ctx->flags |= E2F_FLAG_ABORT;
14086 return;
14087 }
14088 inode = (struct ext2_inode *) buf;
14089 for (i=0; i < fs->super->s_inodes_per_group;
14090 i++, ino++, inode++) {
14091 ctx->stashed_ino = ino;
14092 ctx->stashed_inode = inode;
14093
14094 if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
14095 ext2fs_swap_inode(fs, inode, inode, 0);
14096
14097 /*
14098 * Skip deleted files.
14099 */
14100 if (inode->i_links_count == 0)
14101 continue;
14102
14103 if (LINUX_S_ISDIR(inode->i_mode) ||
14104 ((inode->i_block[EXT2_IND_BLOCK] ||
14105 inode->i_block[EXT2_DIND_BLOCK] ||
14106 inode->i_block[EXT2_TIND_BLOCK]) &&
14107 ext2fs_inode_has_valid_blocks(inode)))
14108 swap_inode_blocks(ctx, ino, block_buf, inode);
14109
14110 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14111 return;
14112
14113 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14114 ext2fs_swap_inode(fs, inode, inode, 1);
14115 }
14116 retval = io_channel_write_blk(fs->io,
14117 fs->group_desc[group].bg_inode_table,
14118 fs->inode_blocks_per_group, buf);
14119 if (retval) {
14120 com_err("swap_inodes", retval,
14121 _("while writing inode table (group %d)"),
14122 group);
14123 ctx->flags |= E2F_FLAG_ABORT;
14124 return;
14125 }
14126 }
14127 ext2fs_free_mem(&buf);
14128 ext2fs_free_mem(&block_buf);
14129 e2fsck_use_inode_shortcuts(ctx, 0);
14130 ext2fs_flush_icache(fs);
14131}
14132
14133#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
14134/*
14135 * On the PowerPC, the big-endian variant of the ext2 filesystem
14136 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
14137 * of each word. Thus a bitmap with only bit 0 set would be, as
14138 * a string of bytes, 00 00 00 01 00 ...
14139 * To cope with this, we byte-reverse each word of a bitmap if
14140 * we have a big-endian filesystem, that is, if we are *not*
14141 * byte-swapping other word-sized numbers.
14142 */
14143#define EXT2_BIG_ENDIAN_BITMAPS
14144#endif
14145
14146#ifdef EXT2_BIG_ENDIAN_BITMAPS
14147static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
14148{
14149 __u32 *p = (__u32 *) bmap->bitmap;
14150 int n, nbytes = (bmap->end - bmap->start + 7) / 8;
14151
14152 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
14153 *p = ext2fs_swab32(*p);
14154}
14155#endif
14156
14157
14158#ifdef ENABLE_SWAPFS
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014159static void swap_filesys(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014160{
14161 ext2_filsys fs = ctx->fs;
14162#ifdef RESOURCE_TRACK
14163 struct resource_track rtrack;
14164
14165 init_resource_track(&rtrack);
14166#endif
14167
14168 if (!(ctx->options & E2F_OPT_PREEN))
14169 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
14170
14171#ifdef MTRACE
14172 mtrace_print("Byte swap");
14173#endif
14174
14175 if (fs->super->s_mnt_count) {
14176 fprintf(stderr, _("%s: the filesystem must be freshly "
14177 "checked using fsck\n"
14178 "and not mounted before trying to "
14179 "byte-swap it.\n"), ctx->device_name);
14180 ctx->flags |= E2F_FLAG_ABORT;
14181 return;
14182 }
14183 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
14184 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
14185 EXT2_FLAG_SWAP_BYTES_WRITE);
14186 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
14187 } else {
14188 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
14189 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
14190 }
14191 swap_inodes(ctx);
14192 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14193 return;
14194 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14195 fs->flags |= EXT2_FLAG_SWAP_BYTES;
14196 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
14197 EXT2_FLAG_SWAP_BYTES_WRITE);
14198
14199#ifdef EXT2_BIG_ENDIAN_BITMAPS
14200 e2fsck_read_bitmaps(ctx);
14201 ext2fs_swap_bitmap(fs->inode_map);
14202 ext2fs_swap_bitmap(fs->block_map);
14203 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
14204#endif
14205 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
14206 ext2fs_flush(fs);
14207 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
14208
14209#ifdef RESOURCE_TRACK
14210 if (ctx->options & E2F_OPT_TIME2)
14211 print_resource_track(_("Byte swap"), &rtrack);
14212#endif
14213}
14214#endif /* ENABLE_SWAPFS */
14215
14216#endif
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014217
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014218/*
14219 * util.c --- miscellaneous utilities
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014220 */
14221
14222#ifdef HAVE_CONIO_H
14223#undef HAVE_TERMIOS_H
14224#include <conio.h>
14225#define read_a_char() getch()
14226#else
14227#ifdef HAVE_TERMIOS_H
14228#include <termios.h>
14229#endif
14230#endif
14231
14232#if 0
14233void fatal_error(e2fsck_t ctx, const char *msg)
14234{
14235 if (msg)
14236 fprintf (stderr, "e2fsck: %s\n", msg);
14237 if (ctx->fs && ctx->fs->io) {
14238 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
14239 io_channel_flush(ctx->fs->io);
14240 else
14241 fprintf(stderr, "e2fsck: io manager magic bad!\n");
14242 }
14243 ctx->flags |= E2F_FLAG_ABORT;
14244 if (ctx->flags & E2F_FLAG_SETJMP_OK)
14245 longjmp(ctx->abort_loc, 1);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014246 exit(EXIT_ERROR);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014247}
14248#endif
14249
14250void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
14251 const char *description)
14252{
14253 void *ret;
14254 char buf[256];
14255
14256#ifdef DEBUG_ALLOCATE_MEMORY
14257 printf("Allocating %d bytes for %s...\n", size, description);
14258#endif
14259 ret = malloc(size);
14260 if (!ret) {
14261 sprintf(buf, "Can't allocate %s\n", description);
14262 fatal_error(ctx, buf);
14263 }
14264 memset(ret, 0, size);
14265 return ret;
14266}
14267
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014268static char *string_copy(const char *str, int len)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014269{
14270 char *ret;
14271
14272 if (!str)
14273 return NULL;
14274 if (!len)
14275 len = strlen(str);
14276 ret = malloc(len+1);
14277 if (ret) {
14278 strncpy(ret, str, len);
14279 ret[len] = 0;
14280 }
14281 return ret;
14282}
14283
14284#ifndef HAVE_CONIO_H
14285static int read_a_char(void)
14286{
14287 char c;
14288 int r;
14289 int fail = 0;
14290
14291 while(1) {
14292 if (e2fsck_global_ctx &&
14293 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
14294 return 3;
14295 }
14296 r = read(0, &c, 1);
14297 if (r == 1)
14298 return c;
14299 if (fail++ > 100)
14300 break;
14301 }
14302 return EOF;
14303}
14304#endif
14305
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014306static int ask_yn(const char * string, int def)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014307{
14308 int c;
14309 const char *defstr;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014310 static const char short_yes[] = "yY";
14311 static const char short_no[] = "nN";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014312
14313#ifdef HAVE_TERMIOS_H
14314 struct termios termios, tmp;
14315
14316 tcgetattr (0, &termios);
14317 tmp = termios;
14318 tmp.c_lflag &= ~(ICANON | ECHO);
14319 tmp.c_cc[VMIN] = 1;
14320 tmp.c_cc[VTIME] = 0;
14321 tcsetattr (0, TCSANOW, &tmp);
14322#endif
14323
14324 if (def == 1)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014325 defstr = "<y>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014326 else if (def == 0)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014327 defstr = "<n>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014328 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014329 defstr = " (y/n)";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014330 printf("%s%s? ", string, defstr);
14331 while (1) {
14332 fflush (stdout);
14333 if ((c = read_a_char()) == EOF)
14334 break;
14335 if (c == 3) {
14336#ifdef HAVE_TERMIOS_H
14337 tcsetattr (0, TCSANOW, &termios);
14338#endif
14339 if (e2fsck_global_ctx &&
14340 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
14341 puts("\n");
14342 longjmp(e2fsck_global_ctx->abort_loc, 1);
14343 }
14344 puts(_("cancelled!\n"));
14345 return 0;
14346 }
14347 if (strchr(short_yes, (char) c)) {
14348 def = 1;
14349 break;
14350 }
14351 else if (strchr(short_no, (char) c)) {
14352 def = 0;
14353 break;
14354 }
14355 else if ((c == ' ' || c == '\n') && (def != -1))
14356 break;
14357 }
14358 if (def)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014359 puts("yes\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014360 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014361 puts ("no\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014362#ifdef HAVE_TERMIOS_H
14363 tcsetattr (0, TCSANOW, &termios);
14364#endif
14365 return def;
14366}
14367
14368int ask (e2fsck_t ctx, const char * string, int def)
14369{
14370 if (ctx->options & E2F_OPT_NO) {
14371 printf (_("%s? no\n\n"), string);
14372 return 0;
14373 }
14374 if (ctx->options & E2F_OPT_YES) {
14375 printf (_("%s? yes\n\n"), string);
14376 return 1;
14377 }
14378 if (ctx->options & E2F_OPT_PREEN) {
14379 printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
14380 return def;
14381 }
14382 return ask_yn(string, def);
14383}
14384
14385void e2fsck_read_bitmaps(e2fsck_t ctx)
14386{
14387 ext2_filsys fs = ctx->fs;
14388 errcode_t retval;
14389
14390 if (ctx->invalid_bitmaps) {
14391 com_err(ctx->program_name, 0,
14392 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
14393 ctx->device_name);
14394 fatal_error(ctx, 0);
14395 }
14396
14397 ehandler_operation(_("reading inode and block bitmaps"));
14398 retval = ext2fs_read_bitmaps(fs);
14399 ehandler_operation(0);
14400 if (retval) {
14401 com_err(ctx->program_name, retval,
14402 _("while retrying to read bitmaps for %s"),
14403 ctx->device_name);
14404 fatal_error(ctx, 0);
14405 }
14406}
14407
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014408static void e2fsck_write_bitmaps(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014409{
14410 ext2_filsys fs = ctx->fs;
14411 errcode_t retval;
14412
14413 if (ext2fs_test_bb_dirty(fs)) {
14414 ehandler_operation(_("writing block bitmaps"));
14415 retval = ext2fs_write_block_bitmap(fs);
14416 ehandler_operation(0);
14417 if (retval) {
14418 com_err(ctx->program_name, retval,
14419 _("while retrying to write block bitmaps for %s"),
14420 ctx->device_name);
14421 fatal_error(ctx, 0);
14422 }
14423 }
14424
14425 if (ext2fs_test_ib_dirty(fs)) {
14426 ehandler_operation(_("writing inode bitmaps"));
14427 retval = ext2fs_write_inode_bitmap(fs);
14428 ehandler_operation(0);
14429 if (retval) {
14430 com_err(ctx->program_name, retval,
14431 _("while retrying to write inode bitmaps for %s"),
14432 ctx->device_name);
14433 fatal_error(ctx, 0);
14434 }
14435 }
14436}
14437
14438void preenhalt(e2fsck_t ctx)
14439{
14440 ext2_filsys fs = ctx->fs;
14441
14442 if (!(ctx->options & E2F_OPT_PREEN))
14443 return;
14444 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
14445 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
14446 ctx->device_name);
14447 if (fs != NULL) {
14448 fs->super->s_state |= EXT2_ERROR_FS;
14449 ext2fs_mark_super_dirty(fs);
14450 ext2fs_close(fs);
14451 }
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014452 exit(EXIT_UNCORRECTED);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014453}
14454
14455#ifdef RESOURCE_TRACK
14456void init_resource_track(struct resource_track *track)
14457{
14458#ifdef HAVE_GETRUSAGE
14459 struct rusage r;
14460#endif
14461
14462 track->brk_start = sbrk(0);
14463 gettimeofday(&track->time_start, 0);
14464#ifdef HAVE_GETRUSAGE
14465#ifdef sun
14466 memset(&r, 0, sizeof(struct rusage));
14467#endif
14468 getrusage(RUSAGE_SELF, &r);
14469 track->user_start = r.ru_utime;
14470 track->system_start = r.ru_stime;
14471#else
14472 track->user_start.tv_sec = track->user_start.tv_usec = 0;
14473 track->system_start.tv_sec = track->system_start.tv_usec = 0;
14474#endif
14475}
14476
14477static _INLINE_ float timeval_subtract(struct timeval *tv1,
14478 struct timeval *tv2)
14479{
14480 return ((tv1->tv_sec - tv2->tv_sec) +
14481 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
14482}
14483
14484void print_resource_track(const char *desc, struct resource_track *track)
14485{
14486#ifdef HAVE_GETRUSAGE
14487 struct rusage r;
14488#endif
14489#ifdef HAVE_MALLINFO
14490 struct mallinfo malloc_info;
14491#endif
14492 struct timeval time_end;
14493
14494 gettimeofday(&time_end, 0);
14495
14496 if (desc)
14497 printf("%s: ", desc);
14498
14499#ifdef HAVE_MALLINFO
14500#define kbytes(x) (((x) + 1023) / 1024)
14501
14502 malloc_info = mallinfo();
14503 printf(_("Memory used: %dk/%dk (%dk/%dk), "),
14504 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
14505 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
14506#else
14507 printf(_("Memory used: %d, "),
14508 (int) (((char *) sbrk(0)) - ((char *) track->brk_start)));
14509#endif
14510#ifdef HAVE_GETRUSAGE
14511 getrusage(RUSAGE_SELF, &r);
14512
14513 printf(_("time: %5.2f/%5.2f/%5.2f\n"),
14514 timeval_subtract(&time_end, &track->time_start),
14515 timeval_subtract(&r.ru_utime, &track->user_start),
14516 timeval_subtract(&r.ru_stime, &track->system_start));
14517#else
14518 printf(_("elapsed time: %6.3f\n"),
14519 timeval_subtract(&time_end, &track->time_start));
14520#endif
14521}
14522#endif /* RESOURCE_TRACK */
14523
14524void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
14525 struct ext2_inode * inode, const char *proc)
14526{
14527 int retval;
14528
14529 retval = ext2fs_read_inode(ctx->fs, ino, inode);
14530 if (retval) {
14531 com_err("ext2fs_read_inode", retval,
14532 _("while reading inode %ld in %s"), ino, proc);
14533 fatal_error(ctx, 0);
14534 }
14535}
14536
14537extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
14538 struct ext2_inode * inode, int bufsize,
14539 const char *proc)
14540{
14541 int retval;
14542
14543 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
14544 if (retval) {
14545 com_err("ext2fs_write_inode", retval,
14546 _("while writing inode %ld in %s"), ino, proc);
14547 fatal_error(ctx, 0);
14548 }
14549}
14550
14551extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
14552 struct ext2_inode * inode, const char *proc)
14553{
14554 int retval;
14555
14556 retval = ext2fs_write_inode(ctx->fs, ino, inode);
14557 if (retval) {
14558 com_err("ext2fs_write_inode", retval,
14559 _("while writing inode %ld in %s"), ino, proc);
14560 fatal_error(ctx, 0);
14561 }
14562}
14563
14564#ifdef MTRACE
14565void mtrace_print(char *mesg)
14566{
14567 FILE *malloc_get_mallstream();
14568 FILE *f = malloc_get_mallstream();
14569
14570 if (f)
14571 fprintf(f, "============= %s\n", mesg);
14572}
14573#endif
14574
14575blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
14576 io_manager manager)
14577{
14578 struct ext2_super_block *sb;
14579 io_channel io = NULL;
14580 void *buf = NULL;
14581 int blocksize;
14582 blk_t superblock, ret_sb = 8193;
14583
14584 if (fs && fs->super) {
14585 ret_sb = (fs->super->s_blocks_per_group +
14586 fs->super->s_first_data_block);
14587 if (ctx) {
14588 ctx->superblock = ret_sb;
14589 ctx->blocksize = fs->blocksize;
14590 }
14591 return ret_sb;
14592 }
14593
14594 if (ctx) {
14595 if (ctx->blocksize) {
14596 ret_sb = ctx->blocksize * 8;
14597 if (ctx->blocksize == 1024)
14598 ret_sb++;
14599 ctx->superblock = ret_sb;
14600 return ret_sb;
14601 }
14602 ctx->superblock = ret_sb;
14603 ctx->blocksize = 1024;
14604 }
14605
14606 if (!name || !manager)
14607 goto cleanup;
14608
14609 if (manager->open(name, 0, &io) != 0)
14610 goto cleanup;
14611
14612 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
14613 goto cleanup;
14614 sb = (struct ext2_super_block *) buf;
14615
14616 for (blocksize = EXT2_MIN_BLOCK_SIZE;
14617 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
14618 superblock = blocksize*8;
14619 if (blocksize == 1024)
14620 superblock++;
14621 io_channel_set_blksize(io, blocksize);
14622 if (io_channel_read_blk(io, superblock,
14623 -SUPERBLOCK_SIZE, buf))
14624 continue;
14625#ifdef EXT2FS_ENABLE_SWAPFS
14626 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
14627 ext2fs_swap_super(sb);
14628#endif
14629 if (sb->s_magic == EXT2_SUPER_MAGIC) {
14630 ret_sb = superblock;
14631 if (ctx) {
14632 ctx->superblock = superblock;
14633 ctx->blocksize = blocksize;
14634 }
14635 break;
14636 }
14637 }
14638
14639cleanup:
14640 if (io)
14641 io_channel_close(io);
14642 if (buf)
14643 ext2fs_free_mem(&buf);
14644 return (ret_sb);
14645}
14646
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014647
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014648/*
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014649 * This function runs through the e2fsck passes and calls them all,
14650 * returning restart, abort, or cancel as necessary...
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014651 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014652typedef void (*pass_t)(e2fsck_t ctx);
14653
14654static const pass_t e2fsck_passes[] = {
14655 e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
14656 e2fsck_pass5, 0 };
14657
14658#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
14659
14660static int e2fsck_run(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014661{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014662 int i;
14663 pass_t e2fsck_pass;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014664
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014665 if (setjmp(ctx->abort_loc)) {
14666 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
14667 return (ctx->flags & E2F_FLAG_RUN_RETURN);
14668 }
14669 ctx->flags |= E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014670
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014671 for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
14672 if (ctx->flags & E2F_FLAG_RUN_RETURN)
14673 break;
14674 e2fsck_pass(ctx);
14675 if (ctx->progress)
14676 (void) (ctx->progress)(ctx, 0, 0, 0);
14677 }
14678 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014679
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014680 if (ctx->flags & E2F_FLAG_RUN_RETURN)
14681 return (ctx->flags & E2F_FLAG_RUN_RETURN);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014682 return 0;
14683}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014684
14685
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014686/*
14687 * unix.c - The unix-specific code for e2fsck
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014688 */
14689
14690
Mike Frysinger51a43b42005-09-24 07:11:16 +000014691/* Command line options */
14692static int swapfs;
14693#ifdef ENABLE_SWAPFS
14694static int normalize_swapfs;
14695#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014696static int cflag; /* check disk */
Mike Frysinger51a43b42005-09-24 07:11:16 +000014697static int show_version_only;
14698static int verbose;
14699
14700static int replace_bad_blocks;
14701static int keep_bad_blocks;
14702static char *bad_blocks_file;
14703
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014704#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
Mike Frysinger51a43b42005-09-24 07:11:16 +000014705int journal_enable_debug = -1;
14706#endif
14707
14708#if 0
14709static void usage(e2fsck_t ctx)
14710{
14711 fprintf(stderr,
14712 _("Usage: %s [-panyrcdfvstDFSV] [-b superblock] [-B blocksize]\n"
14713 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
14714 "\t\t[-l|-L bad_blocks_file] [-C fd] [-j ext-journal]\n"
14715 "\t\t[-E extended-options] device\n"),
14716 ctx->program_name);
14717
14718 fprintf(stderr, _("\nEmergency help:\n"
14719 " -p Automatic repair (no questions)\n"
14720 " -n Make no changes to the filesystem\n"
14721 " -y Assume \"yes\" to all questions\n"
14722 " -c Check for bad blocks and add them to the badblock list\n"
14723 " -f Force checking even if filesystem is marked clean\n"));
14724 fprintf(stderr, _(""
14725 " -v Be verbose\n"
14726 " -b superblock Use alternative superblock\n"
14727 " -B blocksize Force blocksize when looking for superblock\n"
14728 " -j external-journal Set location of the external journal\n"
14729 " -l bad_blocks_file Add to badblocks list\n"
14730 " -L bad_blocks_file Set badblocks list\n"
14731 ));
14732
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014733 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014734}
14735#endif
14736
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014737#define P_E2(singular, plural, n) n, ((n) == 1 ? singular : plural)
14738
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014739static void show_stats(e2fsck_t ctx)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014740{
14741 ext2_filsys fs = ctx->fs;
14742 int inodes, inodes_used, blocks, blocks_used;
14743 int dir_links;
14744 int num_files, num_links;
14745 int frag_percent;
14746
14747 dir_links = 2 * ctx->fs_directory_count - 1;
14748 num_files = ctx->fs_total_count - dir_links;
14749 num_links = ctx->fs_links_count - dir_links;
14750 inodes = fs->super->s_inodes_count;
14751 inodes_used = (fs->super->s_inodes_count -
14752 fs->super->s_free_inodes_count);
14753 blocks = fs->super->s_blocks_count;
14754 blocks_used = (fs->super->s_blocks_count -
14755 fs->super->s_free_blocks_count);
14756
14757 frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
14758 frag_percent = (frag_percent + 5) / 10;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014759
Mike Frysinger51a43b42005-09-24 07:11:16 +000014760 if (!verbose) {
14761 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
14762 ctx->device_name, inodes_used, inodes,
14763 frag_percent / 10, frag_percent % 10,
14764 blocks_used, blocks);
14765 return;
14766 }
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014767 printf ("\n%8d inode%s used (%d%%)\n", P_E2("", "s", inodes_used),
14768 100 * inodes_used / inodes);
14769 printf ("%8d non-contiguous inode%s (%0d.%d%%)\n",
14770 P_E2("", "s", ctx->fs_fragmented),
14771 frag_percent / 10, frag_percent % 10);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014772 printf (_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"),
14773 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014774 printf ("%8d block%s used (%d%%)\n", P_E2("", "s", blocks_used),
14775 (int) ((long long) 100 * blocks_used / blocks));
14776 printf ("%8d bad block%s\n", P_E2("", "s", ctx->fs_badblocks_count));
14777 printf ("%8d large file%s\n", P_E2("", "s", ctx->large_files));
14778 printf ("\n%8d regular file%s\n", P_E2("", "s", ctx->fs_regular_count));
14779 printf ("%8d director%s\n", P_E2("y", "ies", ctx->fs_directory_count));
14780 printf ("%8d character device file%s\n", P_E2("", "s", ctx->fs_chardev_count));
14781 printf ("%8d block device file%s\n", P_E2("", "s", ctx->fs_blockdev_count));
14782 printf ("%8d fifo%s\n", P_E2("", "s", ctx->fs_fifo_count));
14783 printf ("%8d link%s\n", P_E2("", "s", ctx->fs_links_count - dir_links));
14784 printf ("%8d symbolic link%s", P_E2("", "s", ctx->fs_symlinks_count));
14785 printf (" (%d fast symbolic link%s)\n", P_E2("", "s", ctx->fs_fast_symlinks_count));
14786 printf ("%8d socket%s--------\n\n", P_E2("", "s", ctx->fs_sockets_count));
14787 printf ("%8d file%s\n", P_E2("", "s", ctx->fs_total_count - dir_links));
Mike Frysinger51a43b42005-09-24 07:11:16 +000014788}
14789
14790static void check_mount(e2fsck_t ctx)
14791{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014792 errcode_t retval;
14793 int cont;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014794
14795 retval = ext2fs_check_if_mounted(ctx->filesystem_name,
14796 &ctx->mount_flags);
14797 if (retval) {
14798 com_err("ext2fs_check_if_mount", retval,
14799 _("while determining whether %s is mounted."),
14800 ctx->filesystem_name);
14801 return;
14802 }
14803
14804 /*
14805 * If the filesystem isn't mounted, or it's the root filesystem
14806 * and it's mounted read-only, then everything's fine.
14807 */
14808 if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) ||
14809 ((ctx->mount_flags & EXT2_MF_ISROOT) &&
14810 (ctx->mount_flags & EXT2_MF_READONLY)))
14811 return;
14812
14813 if (ctx->options & E2F_OPT_READONLY) {
14814 printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name);
14815 return;
14816 }
14817
14818 printf(_("%s is mounted. "), ctx->filesystem_name);
14819 if (!ctx->interactive)
14820 fatal_error(ctx, _("Cannot continue, aborting.\n\n"));
14821 printf(_("\n\n\007\007\007\007WARNING!!! "
14822 "Running e2fsck on a mounted filesystem may cause\n"
14823 "SEVERE filesystem damage.\007\007\007\n\n"));
14824 cont = ask_yn(_("Do you really want to continue"), -1);
14825 if (!cont) {
14826 printf (_("check aborted.\n"));
14827 exit (0);
14828 }
14829 return;
14830}
14831
14832static int is_on_batt(void)
14833{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014834 FILE *f;
14835 DIR *d;
14836 char tmp[80], tmp2[80], fname[80];
14837 unsigned int acflag;
14838 struct dirent* de;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014839
14840 f = fopen("/proc/apm", "r");
14841 if (f) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014842 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014843 acflag = 1;
14844 fclose(f);
14845 return (acflag != 1);
14846 }
14847 d = opendir("/proc/acpi/ac_adapter");
14848 if (d) {
14849 while ((de=readdir(d)) != NULL) {
14850 if (!strncmp(".", de->d_name, 1))
14851 continue;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014852 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state",
Mike Frysinger51a43b42005-09-24 07:11:16 +000014853 de->d_name);
14854 f = fopen(fname, "r");
14855 if (!f)
14856 continue;
14857 if (fscanf(f, "%s %s", tmp2, tmp) != 2)
14858 tmp[0] = 0;
14859 fclose(f);
14860 if (strncmp(tmp, "off-line", 8) == 0) {
14861 closedir(d);
14862 return 1;
14863 }
14864 }
14865 closedir(d);
14866 }
14867 return 0;
14868}
14869
14870/*
14871 * This routine checks to see if a filesystem can be skipped; if so,
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014872 * it will exit with EXIT_OK. Under some conditions it will print a
Mike Frysinger51a43b42005-09-24 07:11:16 +000014873 * message explaining why a check is being forced.
14874 */
14875static void check_if_skip(e2fsck_t ctx)
14876{
14877 ext2_filsys fs = ctx->fs;
14878 const char *reason = NULL;
14879 unsigned int reason_arg = 0;
14880 long next_check;
14881 int batt = is_on_batt();
14882 time_t now = time(0);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014883
Mike Frysinger51a43b42005-09-24 07:11:16 +000014884 if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file ||
14885 cflag || swapfs)
14886 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014887
Mike Frysinger51a43b42005-09-24 07:11:16 +000014888 if ((fs->super->s_state & EXT2_ERROR_FS) ||
14889 !ext2fs_test_valid(fs))
14890 reason = _(" contains a file system with errors");
14891 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
14892 reason = _(" was not cleanly unmounted");
14893 else if ((fs->super->s_max_mnt_count > 0) &&
14894 (fs->super->s_mnt_count >=
14895 (unsigned) fs->super->s_max_mnt_count)) {
14896 reason = _(" has been mounted %u times without being checked");
14897 reason_arg = fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014898 if (batt && (fs->super->s_mnt_count <
Mike Frysinger51a43b42005-09-24 07:11:16 +000014899 (unsigned) fs->super->s_max_mnt_count*2))
14900 reason = 0;
14901 } else if (fs->super->s_checkinterval &&
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014902 ((now - fs->super->s_lastcheck) >=
Mike Frysinger51a43b42005-09-24 07:11:16 +000014903 fs->super->s_checkinterval)) {
14904 reason = _(" has gone %u days without being checked");
14905 reason_arg = (now - fs->super->s_lastcheck)/(3600*24);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014906 if (batt && ((now - fs->super->s_lastcheck) <
Mike Frysinger51a43b42005-09-24 07:11:16 +000014907 fs->super->s_checkinterval*2))
14908 reason = 0;
14909 }
14910 if (reason) {
14911 fputs(ctx->device_name, stdout);
14912 printf(reason, reason_arg);
14913 fputs(_(", check forced.\n"), stdout);
14914 return;
14915 }
14916 printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name,
14917 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
14918 fs->super->s_inodes_count,
14919 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
14920 fs->super->s_blocks_count);
14921 next_check = 100000;
14922 if (fs->super->s_max_mnt_count > 0) {
14923 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014924 if (next_check <= 0)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014925 next_check = 1;
14926 }
14927 if (fs->super->s_checkinterval &&
14928 ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval))
14929 next_check = 1;
14930 if (next_check <= 5) {
14931 if (next_check == 1)
14932 fputs(_(" (check after next mount)"), stdout);
14933 else
14934 printf(_(" (check in %ld mounts)"), next_check);
14935 }
14936 fputc('\n', stdout);
14937 ext2fs_close(fs);
14938 ctx->fs = NULL;
14939 e2fsck_free_context(ctx);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014940 exit(EXIT_OK);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014941}
14942
14943/*
14944 * For completion notice
14945 */
14946struct percent_tbl {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014947 int max_pass;
14948 int table[32];
Mike Frysinger51a43b42005-09-24 07:11:16 +000014949};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014950static const struct percent_tbl e2fsck_tbl = {
Mike Frysinger51a43b42005-09-24 07:11:16 +000014951 5, { 0, 70, 90, 92, 95, 100 }
14952};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014953
Mike Frysinger51a43b42005-09-24 07:11:16 +000014954static char bar[128], spaces[128];
14955
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014956static float calc_percent(const struct percent_tbl *tbl, int pass, int curr,
Mike Frysinger51a43b42005-09-24 07:11:16 +000014957 int max)
14958{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014959 float percent;
14960
Mike Frysinger51a43b42005-09-24 07:11:16 +000014961 if (pass <= 0)
14962 return 0.0;
14963 if (pass > tbl->max_pass || max == 0)
14964 return 100.0;
14965 percent = ((float) curr) / ((float) max);
14966 return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
14967 + tbl->table[pass-1]);
14968}
14969
14970extern void e2fsck_clear_progbar(e2fsck_t ctx)
14971{
14972 if (!(ctx->flags & E2F_FLAG_PROG_BAR))
14973 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014974
Mike Frysinger51a43b42005-09-24 07:11:16 +000014975 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80),
14976 ctx->stop_meta);
14977 fflush(stdout);
14978 ctx->flags &= ~E2F_FLAG_PROG_BAR;
14979}
14980
14981int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
14982 unsigned int dpynum)
14983{
14984 static const char spinner[] = "\\|/-";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014985 int i;
14986 unsigned int tick;
14987 struct timeval tv;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014988 int dpywidth;
14989 int fixed_percent;
14990
14991 if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
14992 return 0;
14993
14994 /*
14995 * Calculate the new progress position. If the
14996 * percentage hasn't changed, then we skip out right
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014997 * away.
Mike Frysinger51a43b42005-09-24 07:11:16 +000014998 */
14999 fixed_percent = (int) ((10 * percent) + 0.5);
15000 if (ctx->progress_last_percent == fixed_percent)
15001 return 0;
15002 ctx->progress_last_percent = fixed_percent;
15003
15004 /*
15005 * If we've already updated the spinner once within
15006 * the last 1/8th of a second, no point doing it
15007 * again.
15008 */
15009 gettimeofday(&tv, NULL);
15010 tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8));
15011 if ((tick == ctx->progress_last_time) &&
15012 (fixed_percent != 0) && (fixed_percent != 1000))
15013 return 0;
15014 ctx->progress_last_time = tick;
15015
15016 /*
15017 * Advance the spinner, and note that the progress bar
15018 * will be on the screen
15019 */
15020 ctx->progress_pos = (ctx->progress_pos+1) & 3;
15021 ctx->flags |= E2F_FLAG_PROG_BAR;
15022
15023 dpywidth = 66 - strlen(label);
15024 dpywidth = 8 * (dpywidth / 8);
15025 if (dpynum)
15026 dpywidth -= 8;
15027
15028 i = ((percent * dpywidth) + 50) / 100;
15029 printf("%s%s: |%s%s", ctx->start_meta, label,
15030 bar + (sizeof(bar) - (i+1)),
15031 spaces + (sizeof(spaces) - (dpywidth - i + 1)));
15032 if (fixed_percent == 1000)
15033 fputc('|', stdout);
15034 else
15035 fputc(spinner[ctx->progress_pos & 3], stdout);
15036 printf(" %4.1f%% ", percent);
15037 if (dpynum)
15038 printf("%u\r", dpynum);
15039 else
15040 fputs(" \r", stdout);
15041 fputs(ctx->stop_meta, stdout);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015042
Mike Frysinger51a43b42005-09-24 07:11:16 +000015043 if (fixed_percent == 1000)
15044 e2fsck_clear_progbar(ctx);
15045 fflush(stdout);
15046
15047 return 0;
15048}
15049
15050static int e2fsck_update_progress(e2fsck_t ctx, int pass,
15051 unsigned long cur, unsigned long max)
15052{
15053 char buf[80];
15054 float percent;
15055
15056 if (pass == 0)
15057 return 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015058
Mike Frysinger51a43b42005-09-24 07:11:16 +000015059 if (ctx->progress_fd) {
15060 sprintf(buf, "%d %lu %lu\n", pass, cur, max);
15061 write(ctx->progress_fd, buf, strlen(buf));
15062 } else {
15063 percent = calc_percent(&e2fsck_tbl, pass, cur, max);
15064 e2fsck_simple_progress(ctx, ctx->device_name,
15065 percent, 0);
15066 }
15067 return 0;
15068}
15069
Mike Frysinger51a43b42005-09-24 07:11:16 +000015070static void reserve_stdio_fds(void)
15071{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015072 int fd;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015073
15074 while (1) {
"Vladimir N. Oleynik"6c35c7c2005-10-12 15:34:25 +000015075 fd = open(bb_dev_null, O_RDWR);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015076 if (fd > 2)
15077 break;
15078 if (fd < 0) {
15079 fprintf(stderr, _("ERROR: Couldn't open "
15080 "/dev/null (%s)\n"),
15081 strerror(errno));
15082 break;
15083 }
15084 }
15085 close(fd);
15086}
15087
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000015088static void signal_progress_on(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000015089{
15090 e2fsck_t ctx = e2fsck_global_ctx;
15091
15092 if (!ctx)
15093 return;
15094
15095 ctx->progress = e2fsck_update_progress;
15096 ctx->progress_fd = 0;
15097}
15098
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000015099static void signal_progress_off(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000015100{
15101 e2fsck_t ctx = e2fsck_global_ctx;
15102
15103 if (!ctx)
15104 return;
15105
15106 e2fsck_clear_progbar(ctx);
15107 ctx->progress = 0;
15108}
15109
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000015110static void signal_cancel(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000015111{
15112 e2fsck_t ctx = e2fsck_global_ctx;
15113
15114 if (!ctx)
15115 exit(FSCK_CANCELED);
15116
15117 ctx->flags |= E2F_FLAG_CANCEL;
15118}
Mike Frysinger51a43b42005-09-24 07:11:16 +000015119
15120static void parse_extended_opts(e2fsck_t ctx, const char *opts)
15121{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015122 char *buf, *token, *next, *p, *arg;
15123 int ea_ver;
15124 int extended_usage = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015125
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015126 buf = string_copy(opts, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015127 for (token = buf; token && *token; token = next) {
15128 p = strchr(token, ',');
15129 next = 0;
15130 if (p) {
15131 *p = 0;
15132 next = p+1;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015133 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000015134 arg = strchr(token, '=');
15135 if (arg) {
15136 *arg = 0;
15137 arg++;
15138 }
15139 if (strcmp(token, "ea_ver") == 0) {
15140 if (!arg) {
15141 extended_usage++;
15142 continue;
15143 }
15144 ea_ver = strtoul(arg, &p, 0);
15145 if (*p ||
15146 ((ea_ver != 1) && (ea_ver != 2))) {
15147 fprintf(stderr,
15148 _("Invalid EA version.\n"));
15149 extended_usage++;
15150 continue;
15151 }
15152 ctx->ext_attr_ver = ea_ver;
15153 } else
15154 extended_usage++;
15155 }
15156 if (extended_usage) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015157 bb_error_msg_and_die(
15158 "Extended options are separated by commas, "
Mike Frysinger51a43b42005-09-24 07:11:16 +000015159 "and may take an argument which\n"
15160 "is set off by an equals ('=') sign. "
15161 "Valid raid options are:\n"
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015162 "\tea_ver=<ea_version (1 or 2)\n\n");
Mike Frysinger51a43b42005-09-24 07:11:16 +000015163 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015164}
Mike Frysinger51a43b42005-09-24 07:11:16 +000015165
15166
15167static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
15168{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015169 int flush = 0;
15170 int c, fd;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015171#ifdef MTRACE
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015172 extern void *mallwatch;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015173#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015174 e2fsck_t ctx;
15175 errcode_t retval;
15176 struct sigaction sa;
15177 char *extended_opts = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015178
15179 retval = e2fsck_allocate_context(&ctx);
15180 if (retval)
15181 return retval;
15182
15183 *ret_ctx = ctx;
15184
15185 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
15186 setvbuf(stderr, NULL, _IONBF, BUFSIZ);
15187 if (isatty(0) && isatty(1)) {
15188 ctx->interactive = 1;
15189 } else {
15190 ctx->start_meta[0] = '\001';
15191 ctx->stop_meta[0] = '\002';
15192 }
15193 memset(bar, '=', sizeof(bar)-1);
15194 memset(spaces, ' ', sizeof(spaces)-1);
15195 blkid_get_cache(&ctx->blkid, NULL);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015196
Mike Frysinger51a43b42005-09-24 07:11:16 +000015197 if (argc && *argv)
15198 ctx->program_name = *argv;
15199 else
15200 ctx->program_name = "e2fsck";
15201 while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
15202 switch (c) {
15203 case 'C':
15204 ctx->progress = e2fsck_update_progress;
15205 ctx->progress_fd = atoi(optarg);
15206 if (!ctx->progress_fd)
15207 break;
15208 /* Validate the file descriptor to avoid disasters */
15209 fd = dup(ctx->progress_fd);
15210 if (fd < 0) {
15211 fprintf(stderr,
15212 _("Error validating file descriptor %d: %s\n"),
15213 ctx->progress_fd,
15214 error_message(errno));
15215 fatal_error(ctx,
15216 _("Invalid completion information file descriptor"));
15217 } else
15218 close(fd);
15219 break;
15220 case 'D':
15221 ctx->options |= E2F_OPT_COMPRESS_DIRS;
15222 break;
15223 case 'E':
15224 extended_opts = optarg;
15225 break;
15226 case 'p':
15227 case 'a':
15228 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) {
15229 conflict_opt:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015230 fatal_error(ctx,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015231 _("Only one the options -p/-a, -n or -y may be specified."));
15232 }
15233 ctx->options |= E2F_OPT_PREEN;
15234 break;
15235 case 'n':
15236 if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
15237 goto conflict_opt;
15238 ctx->options |= E2F_OPT_NO;
15239 break;
15240 case 'y':
15241 if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO))
15242 goto conflict_opt;
15243 ctx->options |= E2F_OPT_YES;
15244 break;
15245 case 't':
15246#ifdef RESOURCE_TRACK
15247 if (ctx->options & E2F_OPT_TIME)
15248 ctx->options |= E2F_OPT_TIME2;
15249 else
15250 ctx->options |= E2F_OPT_TIME;
15251#else
15252 fprintf(stderr, _("The -t option is not "
15253 "supported on this version of e2fsck.\n"));
15254#endif
15255 break;
15256 case 'c':
15257 if (cflag++)
15258 ctx->options |= E2F_OPT_WRITECHECK;
15259 ctx->options |= E2F_OPT_CHECKBLOCKS;
15260 break;
15261 case 'r':
15262 /* What we do by default, anyway! */
15263 break;
15264 case 'b':
15265 ctx->use_superblock = atoi(optarg);
15266 ctx->flags |= E2F_FLAG_SB_SPECIFIED;
15267 break;
15268 case 'B':
15269 ctx->blocksize = atoi(optarg);
15270 break;
15271 case 'I':
15272 ctx->inode_buffer_blocks = atoi(optarg);
15273 break;
15274 case 'j':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015275 ctx->journal_name = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015276 break;
15277 case 'P':
15278 ctx->process_inode_size = atoi(optarg);
15279 break;
15280 case 'L':
15281 replace_bad_blocks++;
15282 case 'l':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015283 bad_blocks_file = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015284 break;
15285 case 'd':
15286 ctx->options |= E2F_OPT_DEBUG;
15287 break;
15288 case 'f':
15289 ctx->options |= E2F_OPT_FORCE;
15290 break;
15291 case 'F':
15292 flush = 1;
15293 break;
15294 case 'v':
15295 verbose = 1;
15296 break;
15297 case 'V':
15298 show_version_only = 1;
15299 break;
15300#ifdef MTRACE
15301 case 'M':
15302 mallwatch = (void *) strtol(optarg, NULL, 0);
15303 break;
15304#endif
15305 case 'N':
15306 ctx->device_name = optarg;
15307 break;
15308#ifdef ENABLE_SWAPFS
15309 case 's':
15310 normalize_swapfs = 1;
15311 case 'S':
15312 swapfs = 1;
15313 break;
15314#else
15315 case 's':
15316 case 'S':
15317 fprintf(stderr, _("Byte-swapping filesystems "
15318 "not compiled in this version "
15319 "of e2fsck\n"));
15320 exit(1);
15321#endif
15322 case 'k':
15323 keep_bad_blocks++;
15324 break;
15325 default:
15326 usage();
15327 }
15328 if (show_version_only)
15329 return 0;
15330 if (optind != argc - 1)
15331 usage();
15332 if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
15333 !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
15334 ctx->options |= E2F_OPT_READONLY;
15335 ctx->io_options = strchr(argv[optind], '?');
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015336 if (ctx->io_options)
Mike Frysinger51a43b42005-09-24 07:11:16 +000015337 *ctx->io_options++ = 0;
15338 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
15339 if (!ctx->filesystem_name) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015340 com_err(ctx->program_name, 0, _("Unable to resolve '%s'"),
Mike Frysinger51a43b42005-09-24 07:11:16 +000015341 argv[optind]);
15342 fatal_error(ctx, 0);
15343 }
15344 if (extended_opts)
15345 parse_extended_opts(ctx, extended_opts);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015346
Mike Frysinger51a43b42005-09-24 07:11:16 +000015347 if (flush) {
15348 fd = open(ctx->filesystem_name, O_RDONLY, 0);
15349 if (fd < 0) {
15350 com_err("open", errno,
15351 _("while opening %s for flushing"),
15352 ctx->filesystem_name);
15353 fatal_error(ctx, 0);
15354 }
15355 if ((retval = ext2fs_sync_device(fd, 1))) {
15356 com_err("ext2fs_sync_device", retval,
15357 _("while trying to flush %s"),
15358 ctx->filesystem_name);
15359 fatal_error(ctx, 0);
15360 }
15361 close(fd);
15362 }
15363#ifdef ENABLE_SWAPFS
15364 if (swapfs) {
15365 if (cflag || bad_blocks_file) {
15366 fprintf(stderr, _("Incompatible options not "
15367 "allowed when byte-swapping.\n"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015368 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015369 }
15370 }
15371#endif
15372 if (cflag && bad_blocks_file) {
15373 fprintf(stderr, _("The -c and the -l/-L options may "
15374 "not be both used at the same time.\n"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015375 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015376 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000015377 /*
15378 * Set up signal action
15379 */
15380 memset(&sa, 0, sizeof(struct sigaction));
15381 sa.sa_handler = signal_cancel;
15382 sigaction(SIGINT, &sa, 0);
15383 sigaction(SIGTERM, &sa, 0);
15384#ifdef SA_RESTART
15385 sa.sa_flags = SA_RESTART;
15386#endif
15387 e2fsck_global_ctx = ctx;
15388 sa.sa_handler = signal_progress_on;
15389 sigaction(SIGUSR1, &sa, 0);
15390 sa.sa_handler = signal_progress_off;
15391 sigaction(SIGUSR2, &sa, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015392
15393 /* Update our PATH to include /sbin if we need to run badblocks */
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015394 if (cflag)
15395 e2fs_set_sbin_path();
Mike Frysinger51a43b42005-09-24 07:11:16 +000015396#ifdef __CONFIG_JBD_DEBUG__E2FS
15397 if (getenv("E2FSCK_JBD_DEBUG"))
15398 journal_enable_debug = atoi(getenv("E2FSCK_JBD_DEBUG"));
15399#endif
15400 return 0;
15401}
15402
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015403static const char my_ver_string[] = E2FSPROGS_VERSION;
15404static const char my_ver_date[] = E2FSPROGS_DATE;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015405
Mike Frysinger51a43b42005-09-24 07:11:16 +000015406int e2fsck_main (int argc, char *argv[])
15407{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015408 errcode_t retval;
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015409 int exit_value = EXIT_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015410 ext2_filsys fs = 0;
15411 io_manager io_ptr;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015412 struct ext2_super_block *sb;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015413 const char *lib_ver_date;
15414 int my_ver, lib_ver;
15415 e2fsck_t ctx;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015416 struct problem_context pctx;
15417 int flags, run_result;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015418
Mike Frysinger51a43b42005-09-24 07:11:16 +000015419 clear_problem_context(&pctx);
15420#ifdef MTRACE
15421 mtrace();
15422#endif
15423#ifdef MCHECK
15424 mcheck(0);
15425#endif
15426#ifdef ENABLE_NLS
15427 setlocale(LC_MESSAGES, "");
15428 setlocale(LC_CTYPE, "");
15429 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
15430 textdomain(NLS_CAT_NAME);
15431#endif
15432 my_ver = ext2fs_parse_version_string(my_ver_string);
15433 lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
15434 if (my_ver > lib_ver) {
15435 fprintf( stderr, _("Error: ext2fs library version "
15436 "out of date!\n"));
15437 show_version_only++;
15438 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015439
Mike Frysinger51a43b42005-09-24 07:11:16 +000015440 retval = PRS(argc, argv, &ctx);
15441 if (retval) {
15442 com_err("e2fsck", retval,
15443 _("while trying to initialize program"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015444 exit(EXIT_ERROR);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015445 }
15446 reserve_stdio_fds();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015447
Mike Frysinger51a43b42005-09-24 07:11:16 +000015448#ifdef RESOURCE_TRACK
15449 init_resource_track(&ctx->global_rtrack);
15450#endif
15451
15452 if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
15453 fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string,
15454 my_ver_date);
15455
15456 if (show_version_only) {
15457 fprintf(stderr, _("\tUsing %s, %s\n"),
15458 error_message(EXT2_ET_BASE), lib_ver_date);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015459 exit(EXIT_OK);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015460 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015461
Mike Frysinger51a43b42005-09-24 07:11:16 +000015462 check_mount(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015463
Mike Frysinger51a43b42005-09-24 07:11:16 +000015464 if (!(ctx->options & E2F_OPT_PREEN) &&
15465 !(ctx->options & E2F_OPT_NO) &&
15466 !(ctx->options & E2F_OPT_YES)) {
15467 if (!ctx->interactive)
15468 fatal_error(ctx,
15469 _("need terminal for interactive repairs"));
15470 }
15471 ctx->superblock = ctx->use_superblock;
15472restart:
15473#ifdef CONFIG_TESTIO_DEBUG
15474 io_ptr = test_io_manager;
15475 test_io_backing_manager = unix_io_manager;
15476#else
15477 io_ptr = unix_io_manager;
15478#endif
15479 flags = 0;
15480 if ((ctx->options & E2F_OPT_READONLY) == 0)
15481 flags |= EXT2_FLAG_RW;
15482
15483 if (ctx->superblock && ctx->blocksize) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015484 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015485 flags, ctx->superblock, ctx->blocksize,
15486 io_ptr, &fs);
15487 } else if (ctx->superblock) {
15488 int blocksize;
15489 for (blocksize = EXT2_MIN_BLOCK_SIZE;
15490 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015491 retval = ext2fs_open2(ctx->filesystem_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015492 ctx->io_options, flags,
15493 ctx->superblock, blocksize,
15494 io_ptr, &fs);
15495 if (!retval)
15496 break;
15497 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015498 } else
15499 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015500 flags, 0, 0, io_ptr, &fs);
15501 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
15502 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
15503 ((retval == EXT2_ET_BAD_MAGIC) ||
15504 ((retval == 0) && ext2fs_check_desc(fs)))) {
15505 if (!fs || (fs->group_desc_count > 1)) {
15506 printf(_("%s trying backup blocks...\n"),
15507 retval ? _("Couldn't find ext2 superblock,") :
15508 _("Group descriptors look bad..."));
15509 get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
15510 if (fs)
15511 ext2fs_close(fs);
15512 goto restart;
15513 }
15514 }
15515 if (retval) {
15516 com_err(ctx->program_name, retval, _("while trying to open %s"),
15517 ctx->filesystem_name);
15518 if (retval == EXT2_ET_REV_TOO_HIGH) {
15519 printf(_("The filesystem revision is apparently "
15520 "too high for this version of e2fsck.\n"
15521 "(Or the filesystem superblock "
15522 "is corrupt)\n\n"));
15523 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
15524 } else if (retval == EXT2_ET_SHORT_READ)
15525 printf(_("Could this be a zero-length partition?\n"));
15526 else if ((retval == EPERM) || (retval == EACCES))
15527 printf(_("You must have %s access to the "
15528 "filesystem or be root\n"),
15529 (ctx->options & E2F_OPT_READONLY) ?
15530 "r/o" : "r/w");
15531 else if (retval == ENXIO)
15532 printf(_("Possibly non-existent or swap device?\n"));
15533#ifdef EROFS
15534 else if (retval == EROFS)
15535 printf(_("Disk write-protected; use the -n option "
15536 "to do a read-only\n"
15537 "check of the device.\n"));
15538#endif
15539 else
15540 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
15541 fatal_error(ctx, 0);
15542 }
15543 ctx->fs = fs;
15544 fs->priv_data = ctx;
15545 sb = fs->super;
15546 if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
15547 com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH,
15548 _("while trying to open %s"),
15549 ctx->filesystem_name);
15550 get_newer:
15551 fatal_error(ctx, _("Get a newer version of e2fsck!"));
15552 }
15553
15554 /*
15555 * Set the device name, which is used whenever we print error
15556 * or informational messages to the user.
15557 */
15558 if (ctx->device_name == 0 &&
15559 (sb->s_volume_name[0] != 0)) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015560 ctx->device_name = string_copy(sb->s_volume_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015561 sizeof(sb->s_volume_name));
15562 }
15563 if (ctx->device_name == 0)
15564 ctx->device_name = ctx->filesystem_name;
15565
15566 /*
15567 * Make sure the ext3 superblock fields are consistent.
15568 */
15569 retval = e2fsck_check_ext3_journal(ctx);
15570 if (retval) {
15571 com_err(ctx->program_name, retval,
15572 _("while checking ext3 journal for %s"),
15573 ctx->device_name);
15574 fatal_error(ctx, 0);
15575 }
15576
15577 /*
15578 * Check to see if we need to do ext3-style recovery. If so,
15579 * do it, and then restart the fsck.
15580 */
15581 if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
15582 if (ctx->options & E2F_OPT_READONLY) {
15583 printf(_("Warning: skipping journal recovery "
15584 "because doing a read-only filesystem "
15585 "check.\n"));
15586 io_channel_flush(ctx->fs->io);
15587 } else {
15588 if (ctx->flags & E2F_FLAG_RESTARTED) {
15589 /*
15590 * Whoops, we attempted to run the
15591 * journal twice. This should never
15592 * happen, unless the hardware or
15593 * device driver is being bogus.
15594 */
15595 com_err(ctx->program_name, 0,
15596 _("unable to set superblock flags on %s\n"), ctx->device_name);
15597 fatal_error(ctx, 0);
15598 }
15599 retval = e2fsck_run_ext3_journal(ctx);
15600 if (retval) {
15601 com_err(ctx->program_name, retval,
15602 _("while recovering ext3 journal of %s"),
15603 ctx->device_name);
15604 fatal_error(ctx, 0);
15605 }
15606 ext2fs_close(ctx->fs);
15607 ctx->fs = 0;
15608 ctx->flags |= E2F_FLAG_RESTARTED;
15609 goto restart;
15610 }
15611 }
15612
15613 /*
15614 * Check for compatibility with the feature sets. We need to
15615 * be more stringent than ext2fs_open().
15616 */
15617 if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
15618 (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
15619 com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
15620 "(%s)", ctx->device_name);
15621 goto get_newer;
15622 }
15623 if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
15624 com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE,
15625 "(%s)", ctx->device_name);
15626 goto get_newer;
15627 }
15628#ifdef ENABLE_COMPRESSION
15629 if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
15630 com_err(ctx->program_name, 0,
15631 _("Warning: compression support is experimental.\n"));
15632#endif
15633#ifndef ENABLE_HTREE
15634 if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
15635 com_err(ctx->program_name, 0,
15636 _("E2fsck not compiled with HTREE support,\n\t"
15637 "but filesystem %s has HTREE directories.\n"),
15638 ctx->device_name);
15639 goto get_newer;
15640 }
15641#endif
15642
15643 /*
15644 * If the user specified a specific superblock, presumably the
15645 * master superblock has been trashed. So we mark the
15646 * superblock as dirty, so it can be written out.
15647 */
15648 if (ctx->superblock &&
15649 !(ctx->options & E2F_OPT_READONLY))
15650 ext2fs_mark_super_dirty(fs);
15651
15652 /*
15653 * We only update the master superblock because (a) paranoia;
15654 * we don't want to corrupt the backup superblocks, and (b) we
15655 * don't need to update the mount count and last checked
15656 * fields in the backup superblock (the kernel doesn't
15657 * update the backup superblocks anyway).
15658 */
15659 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
15660
15661 ehandler_init(fs->io);
15662
15663 if (ctx->superblock)
15664 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
15665 ext2fs_mark_valid(fs);
15666 check_super_block(ctx);
15667 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15668 fatal_error(ctx, 0);
15669 check_if_skip(ctx);
15670 if (bad_blocks_file)
15671 read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks);
15672 else if (cflag)
15673 read_bad_blocks_file(ctx, 0, !keep_bad_blocks); /* Test disk */
15674 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15675 fatal_error(ctx, 0);
15676#ifdef ENABLE_SWAPFS
Rob Landley391a9042006-01-23 21:38:06 +000015677
15678#ifdef WORDS_BIGENDIAN
Rob Landley8b606342006-01-24 02:38:28 +000015679#define NATIVE_FLAG EXT2_FLAG_SWAP_BYTES
Rob Landley391a9042006-01-23 21:38:06 +000015680#else
Rob Landley8b606342006-01-24 02:38:28 +000015681#define NATIVE_FLAG 0
Rob Landley391a9042006-01-23 21:38:06 +000015682#endif
15683
15684
Mike Frysinger51a43b42005-09-24 07:11:16 +000015685 if (normalize_swapfs) {
Rob Landley391a9042006-01-23 21:38:06 +000015686 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == NATIVE_FLAG) {
Mike Frysinger51a43b42005-09-24 07:11:16 +000015687 fprintf(stderr, _("%s: Filesystem byte order "
15688 "already normalized.\n"), ctx->device_name);
15689 fatal_error(ctx, 0);
15690 }
15691 }
15692 if (swapfs) {
15693 swap_filesys(ctx);
15694 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15695 fatal_error(ctx, 0);
15696 }
15697#endif
15698
15699 /*
15700 * Mark the system as valid, 'til proven otherwise
15701 */
15702 ext2fs_mark_valid(fs);
15703
15704 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
15705 if (retval) {
15706 com_err(ctx->program_name, retval,
15707 _("while reading bad blocks inode"));
15708 preenhalt(ctx);
15709 printf(_("This doesn't bode well,"
15710 " but we'll try to go on...\n"));
15711 }
15712
15713 run_result = e2fsck_run(ctx);
15714 e2fsck_clear_progbar(ctx);
15715 if (run_result == E2F_FLAG_RESTART) {
15716 printf(_("Restarting e2fsck from the beginning...\n"));
15717 retval = e2fsck_reset_context(ctx);
15718 if (retval) {
15719 com_err(ctx->program_name, retval,
15720 _("while resetting context"));
15721 fatal_error(ctx, 0);
15722 }
15723 ext2fs_close(fs);
15724 goto restart;
15725 }
15726 if (run_result & E2F_FLAG_CANCEL) {
15727 printf(_("%s: e2fsck canceled.\n"), ctx->device_name ?
15728 ctx->device_name : ctx->filesystem_name);
15729 exit_value |= FSCK_CANCELED;
15730 }
15731 if (run_result & E2F_FLAG_ABORT)
15732 fatal_error(ctx, _("aborted"));
15733
15734#ifdef MTRACE
15735 mtrace_print("Cleanup");
15736#endif
15737 if (ext2fs_test_changed(fs)) {
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015738 exit_value |= EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015739 if (!(ctx->options & E2F_OPT_PREEN))
15740 printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
15741 ctx->device_name);
15742 if (ctx->mount_flags & EXT2_MF_ISROOT) {
15743 printf(_("%s: ***** REBOOT LINUX *****\n"),
15744 ctx->device_name);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015745 exit_value |= EXIT_DESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015746 }
15747 }
15748 if (!ext2fs_test_valid(fs)) {
15749 printf(_("\n%s: ********** WARNING: Filesystem still has "
15750 "errors **********\n\n"), ctx->device_name);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015751 exit_value |= EXIT_UNCORRECTED;
15752 exit_value &= ~EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015753 }
15754 if (exit_value & FSCK_CANCELED)
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015755 exit_value &= ~EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015756 else {
15757 show_stats(ctx);
15758 if (!(ctx->options & E2F_OPT_READONLY)) {
15759 if (ext2fs_test_valid(fs)) {
15760 if (!(sb->s_state & EXT2_VALID_FS))
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015761 exit_value |= EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015762 sb->s_state = EXT2_VALID_FS;
15763 } else
15764 sb->s_state &= ~EXT2_VALID_FS;
15765 sb->s_mnt_count = 0;
15766 sb->s_lastcheck = time(NULL);
15767 ext2fs_mark_super_dirty(fs);
15768 }
15769 }
15770
15771 e2fsck_write_bitmaps(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015772
Mike Frysinger51a43b42005-09-24 07:11:16 +000015773 ext2fs_close(fs);
15774 ctx->fs = NULL;
15775 free(ctx->filesystem_name);
15776 free(ctx->journal_name);
15777 e2fsck_free_context(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015778
Mike Frysinger51a43b42005-09-24 07:11:16 +000015779#ifdef RESOURCE_TRACK
15780 if (ctx->options & E2F_OPT_TIME)
15781 print_resource_track(NULL, &ctx->global_rtrack);
15782#endif
15783
15784 return exit_value;
15785}