blob: 489d2a81860d60fe73c57669738158c0f7e2d775 [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{
Rob Landleye7c43b62006-03-01 16:39:45 +00002039 ext2fs_free_mem(&ctx->dir_info);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002040 ctx->dir_info_size = 0;
2041 ctx->dir_info_count = 0;
2042}
2043
2044/*
2045 * Return the count of number of directories in the dir_info structure
2046 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002047static inline int e2fsck_get_num_dirinfo(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002048{
2049 return ctx->dir_info_count;
2050}
2051
2052/*
2053 * A simple interator function
2054 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002055static struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002056{
2057 if (*control >= ctx->dir_info_count)
2058 return 0;
2059
2060 return(ctx->dir_info + (*control)++);
2061}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002062
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002063/*
2064 * dirinfo.c --- maintains the directory information table for e2fsck.
2065 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002066 */
2067
2068#ifdef ENABLE_HTREE
2069
2070/*
2071 * This subroutine is called during pass1 to create a directory info
2072 * entry. During pass1, the passed-in parent is 0; it will get filled
2073 * in during pass2.
2074 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002075static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002076{
2077 struct dx_dir_info *dir;
2078 int i, j;
2079 errcode_t retval;
2080 unsigned long old_size;
2081
2082#if 0
2083 printf("add_dx_dir_info for inode %lu...\n", ino);
2084#endif
2085 if (!ctx->dx_dir_info) {
2086 ctx->dx_dir_info_count = 0;
2087 ctx->dx_dir_info_size = 100; /* Guess */
2088 ctx->dx_dir_info = (struct dx_dir_info *)
2089 e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
2090 * sizeof (struct dx_dir_info),
2091 "directory map");
2092 }
2093
2094 if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
2095 old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
2096 ctx->dx_dir_info_size += 10;
2097 retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
2098 sizeof(struct dx_dir_info),
2099 &ctx->dx_dir_info);
2100 if (retval) {
2101 ctx->dx_dir_info_size -= 10;
2102 return;
2103 }
2104 }
2105
2106 /*
2107 * Normally, add_dx_dir_info is called with each inode in
2108 * sequential order; but once in a while (like when pass 3
2109 * needs to recreate the root directory or lost+found
2110 * directory) it is called out of order. In those cases, we
2111 * need to move the dx_dir_info entries down to make room, since
2112 * the dx_dir_info array needs to be sorted by inode number for
2113 * get_dx_dir_info()'s sake.
2114 */
2115 if (ctx->dx_dir_info_count &&
2116 ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
2117 for (i = ctx->dx_dir_info_count-1; i > 0; i--)
2118 if (ctx->dx_dir_info[i-1].ino < ino)
2119 break;
2120 dir = &ctx->dx_dir_info[i];
2121 if (dir->ino != ino)
2122 for (j = ctx->dx_dir_info_count++; j > i; j--)
2123 ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
2124 } else
2125 dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
2126
2127 dir->ino = ino;
2128 dir->numblocks = num_blocks;
2129 dir->hashversion = 0;
2130 dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
2131 * sizeof (struct dx_dirblock_info),
2132 "dx_block info array");
2133
2134}
2135
2136/*
2137 * get_dx_dir_info() --- given an inode number, try to find the directory
2138 * information entry for it.
2139 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002140static 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 +00002141{
2142 int low, high, mid;
2143
2144 low = 0;
2145 high = ctx->dx_dir_info_count-1;
2146 if (!ctx->dx_dir_info)
2147 return 0;
2148 if (ino == ctx->dx_dir_info[low].ino)
2149 return &ctx->dx_dir_info[low];
2150 if (ino == ctx->dx_dir_info[high].ino)
2151 return &ctx->dx_dir_info[high];
2152
2153 while (low < high) {
2154 mid = (low+high)/2;
2155 if (mid == low || mid == high)
2156 break;
2157 if (ino == ctx->dx_dir_info[mid].ino)
2158 return &ctx->dx_dir_info[mid];
2159 if (ino < ctx->dx_dir_info[mid].ino)
2160 high = mid;
2161 else
2162 low = mid;
2163 }
2164 return 0;
2165}
2166
2167/*
2168 * Free the dx_dir_info structure when it isn't needed any more.
2169 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002170static void e2fsck_free_dx_dir_info(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002171{
2172 int i;
2173 struct dx_dir_info *dir;
2174
2175 if (ctx->dx_dir_info) {
2176 dir = ctx->dx_dir_info;
2177 for (i=0; i < ctx->dx_dir_info_count; i++) {
Rob Landleye7c43b62006-03-01 16:39:45 +00002178 ext2fs_free_mem(&dir->dx_block);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002179 }
2180 ext2fs_free_mem(&ctx->dx_dir_info);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002181 }
2182 ctx->dx_dir_info_size = 0;
2183 ctx->dx_dir_info_count = 0;
2184}
2185
2186/*
2187 * A simple interator function
2188 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002189static struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002190{
2191 if (*control >= ctx->dx_dir_info_count)
2192 return 0;
2193
2194 return(ctx->dx_dir_info + (*control)++);
2195}
2196
2197#endif /* ENABLE_HTREE */
2198/*
2199 * e2fsck.c - a consistency checker for the new extended file system.
2200 *
Mike Frysinger51a43b42005-09-24 07:11:16 +00002201 */
2202
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002203/*
2204 * This function allocates an e2fsck context
2205 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002206static errcode_t e2fsck_allocate_context(e2fsck_t *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002207{
2208 e2fsck_t context;
2209 errcode_t retval;
2210
2211 retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
2212 if (retval)
2213 return retval;
2214
2215 memset(context, 0, sizeof(struct e2fsck_struct));
2216
2217 context->process_inode_size = 256;
2218 context->ext_attr_ver = 2;
2219
2220 *ret = context;
2221 return 0;
2222}
2223
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002224struct ea_refcount_el {
2225 blk_t ea_blk;
2226 int ea_count;
2227};
2228
2229struct ea_refcount {
2230 blk_t count;
2231 blk_t size;
2232 blk_t cursor;
2233 struct ea_refcount_el *list;
2234};
2235
2236static void ea_refcount_free(ext2_refcount_t refcount)
2237{
2238 if (!refcount)
2239 return;
2240
Rob Landleye7c43b62006-03-01 16:39:45 +00002241 ext2fs_free_mem(&refcount->list);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002242 ext2fs_free_mem(&refcount);
2243}
2244
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002245/*
2246 * This function resets an e2fsck context; it is called when e2fsck
2247 * needs to be restarted.
2248 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002249static errcode_t e2fsck_reset_context(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002250{
2251 ctx->flags = 0;
2252 ctx->lost_and_found = 0;
2253 ctx->bad_lost_and_found = 0;
Rob Landleye7c43b62006-03-01 16:39:45 +00002254 ext2fs_free_inode_bitmap(ctx->inode_used_map);
2255 ctx->inode_used_map = 0;
2256 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
2257 ctx->inode_dir_map = 0;
2258 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
2259 ctx->inode_reg_map = 0;
2260 ext2fs_free_block_bitmap(ctx->block_found_map);
2261 ctx->block_found_map = 0;
2262 ext2fs_free_icount(ctx->inode_link_info);
2263 ctx->inode_link_info = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002264 if (ctx->journal_io) {
2265 if (ctx->fs && ctx->fs->io != ctx->journal_io)
2266 io_channel_close(ctx->journal_io);
2267 ctx->journal_io = 0;
2268 }
Rob Landleye7c43b62006-03-01 16:39:45 +00002269 if (ctx->fs) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002270 ext2fs_free_dblist(ctx->fs->dblist);
2271 ctx->fs->dblist = 0;
2272 }
2273 e2fsck_free_dir_info(ctx);
2274#ifdef ENABLE_HTREE
2275 e2fsck_free_dx_dir_info(ctx);
Mike Frysinger51a43b42005-09-24 07:11:16 +00002276#endif
Rob Landleye7c43b62006-03-01 16:39:45 +00002277 ea_refcount_free(ctx->refcount);
2278 ctx->refcount = 0;
2279 ea_refcount_free(ctx->refcount_extra);
2280 ctx->refcount_extra = 0;
2281 ext2fs_free_block_bitmap(ctx->block_dup_map);
2282 ctx->block_dup_map = 0;
2283 ext2fs_free_block_bitmap(ctx->block_ea_map);
2284 ctx->block_ea_map = 0;
2285 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
2286 ctx->inode_bb_map = 0;
2287 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
2288 ctx->inode_bad_map = 0;
2289 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
2290 ctx->inode_imagic_map = 0;
2291 ext2fs_u32_list_free(ctx->dirs_to_hash);
2292 ctx->dirs_to_hash = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002293
2294 /*
2295 * Clear the array of invalid meta-data flags
2296 */
Rob Landleye7c43b62006-03-01 16:39:45 +00002297 ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
2298 ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
2299 ext2fs_free_mem(&ctx->invalid_inode_table_flag);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002300
2301 /* Clear statistic counters */
2302 ctx->fs_directory_count = 0;
2303 ctx->fs_regular_count = 0;
2304 ctx->fs_blockdev_count = 0;
2305 ctx->fs_chardev_count = 0;
2306 ctx->fs_links_count = 0;
2307 ctx->fs_symlinks_count = 0;
2308 ctx->fs_fast_symlinks_count = 0;
2309 ctx->fs_fifo_count = 0;
2310 ctx->fs_total_count = 0;
2311 ctx->fs_badblocks_count = 0;
2312 ctx->fs_sockets_count = 0;
2313 ctx->fs_ind_count = 0;
2314 ctx->fs_dind_count = 0;
2315 ctx->fs_tind_count = 0;
2316 ctx->fs_fragmented = 0;
2317 ctx->large_files = 0;
2318
2319 /* Reset the superblock to the user's requested value */
2320 ctx->superblock = ctx->use_superblock;
2321
2322 return 0;
2323}
2324
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002325static void e2fsck_free_context(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002326{
2327 if (!ctx)
2328 return;
2329
2330 e2fsck_reset_context(ctx);
2331 if (ctx->blkid)
2332 blkid_put_cache(ctx->blkid);
2333
2334 ext2fs_free_mem(&ctx);
2335}
2336
2337/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002338 * ea_refcount.c
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002339 */
2340
2341/*
2342 * The strategy we use for keeping track of EA refcounts is as
2343 * follows. We keep a sorted array of first EA blocks and its
2344 * reference counts. Once the refcount has dropped to zero, it is
2345 * removed from the array to save memory space. Once the EA block is
2346 * checked, its bit is set in the block_ea_map bitmap.
2347 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002348
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002349
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002350static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002351{
2352 ext2_refcount_t refcount;
2353 errcode_t retval;
2354 size_t bytes;
2355
2356 retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount);
2357 if (retval)
2358 return retval;
2359 memset(refcount, 0, sizeof(struct ea_refcount));
2360
2361 if (!size)
2362 size = 500;
2363 refcount->size = size;
2364 bytes = (size_t) (size * sizeof(struct ea_refcount_el));
2365#ifdef DEBUG
2366 printf("Refcount allocated %d entries, %d bytes.\n",
2367 refcount->size, bytes);
2368#endif
2369 retval = ext2fs_get_mem(bytes, &refcount->list);
2370 if (retval)
2371 goto errout;
2372 memset(refcount->list, 0, bytes);
2373
2374 refcount->count = 0;
2375 refcount->cursor = 0;
2376
2377 *ret = refcount;
2378 return 0;
2379
2380errout:
2381 ea_refcount_free(refcount);
2382 return(retval);
2383}
2384
2385/*
2386 * collapse_refcount() --- go through the refcount array, and get rid
2387 * of any count == zero entries
2388 */
2389static void refcount_collapse(ext2_refcount_t refcount)
2390{
2391 unsigned int i, j;
2392 struct ea_refcount_el *list;
2393
2394 list = refcount->list;
2395 for (i = 0, j = 0; i < refcount->count; i++) {
2396 if (list[i].ea_count) {
2397 if (i != j)
2398 list[j] = list[i];
2399 j++;
2400 }
2401 }
2402#if defined(DEBUG) || defined(TEST_PROGRAM)
2403 printf("Refcount_collapse: size was %d, now %d\n",
2404 refcount->count, j);
2405#endif
2406 refcount->count = j;
2407}
2408
2409
2410/*
2411 * insert_refcount_el() --- Insert a new entry into the sorted list at a
2412 * specified position.
2413 */
2414static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
2415 blk_t blk, int pos)
2416{
2417 struct ea_refcount_el *el;
2418 errcode_t retval;
2419 blk_t new_size = 0;
2420 int num;
2421
2422 if (refcount->count >= refcount->size) {
2423 new_size = refcount->size + 100;
2424#ifdef DEBUG
2425 printf("Reallocating refcount %d entries...\n", new_size);
2426#endif
2427 retval = ext2fs_resize_mem((size_t) refcount->size *
2428 sizeof(struct ea_refcount_el),
2429 (size_t) new_size *
2430 sizeof(struct ea_refcount_el),
2431 &refcount->list);
2432 if (retval)
2433 return 0;
2434 refcount->size = new_size;
2435 }
2436 num = (int) refcount->count - pos;
2437 if (num < 0)
2438 return 0; /* should never happen */
2439 if (num) {
2440 memmove(&refcount->list[pos+1], &refcount->list[pos],
2441 sizeof(struct ea_refcount_el) * num);
2442 }
2443 refcount->count++;
2444 el = &refcount->list[pos];
2445 el->ea_count = 0;
2446 el->ea_blk = blk;
2447 return el;
2448}
2449
2450
2451/*
2452 * get_refcount_el() --- given an block number, try to find refcount
2453 * information in the sorted list. If the create flag is set,
2454 * and we can't find an entry, create one in the sorted list.
2455 */
2456static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
2457 blk_t blk, int create)
2458{
2459 float range;
2460 int low, high, mid;
2461 blk_t lowval, highval;
2462
2463 if (!refcount || !refcount->list)
2464 return 0;
2465retry:
2466 low = 0;
2467 high = (int) refcount->count-1;
2468 if (create && ((refcount->count == 0) ||
2469 (blk > refcount->list[high].ea_blk))) {
2470 if (refcount->count >= refcount->size)
2471 refcount_collapse(refcount);
2472
2473 return insert_refcount_el(refcount, blk,
2474 (unsigned) refcount->count);
2475 }
2476 if (refcount->count == 0)
2477 return 0;
2478
2479 if (refcount->cursor >= refcount->count)
2480 refcount->cursor = 0;
2481 if (blk == refcount->list[refcount->cursor].ea_blk)
2482 return &refcount->list[refcount->cursor++];
2483#ifdef DEBUG
2484 printf("Non-cursor get_refcount_el: %u\n", blk);
2485#endif
2486 while (low <= high) {
2487#if 0
2488 mid = (low+high)/2;
Mike Frysinger51a43b42005-09-24 07:11:16 +00002489#else
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002490 if (low == high)
2491 mid = low;
2492 else {
2493 /* Interpolate for efficiency */
2494 lowval = refcount->list[low].ea_blk;
2495 highval = refcount->list[high].ea_blk;
2496
2497 if (blk < lowval)
2498 range = 0;
2499 else if (blk > highval)
2500 range = 1;
2501 else
2502 range = ((float) (blk - lowval)) /
2503 (highval - lowval);
2504 mid = low + ((int) (range * (high-low)));
2505 }
Mike Frysinger51a43b42005-09-24 07:11:16 +00002506#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002507 if (blk == refcount->list[mid].ea_blk) {
2508 refcount->cursor = mid+1;
2509 return &refcount->list[mid];
2510 }
2511 if (blk < refcount->list[mid].ea_blk)
2512 high = mid-1;
2513 else
2514 low = mid+1;
2515 }
2516 /*
2517 * If we need to create a new entry, it should be right at
2518 * low (where high will be left at low-1).
2519 */
2520 if (create) {
2521 if (refcount->count >= refcount->size) {
2522 refcount_collapse(refcount);
2523 if (refcount->count < refcount->size)
2524 goto retry;
2525 }
2526 return insert_refcount_el(refcount, blk, low);
2527 }
2528 return 0;
2529}
2530
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002531static errcode_t
2532ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002533{
2534 struct ea_refcount_el *el;
2535
2536 el = get_refcount_el(refcount, blk, 1);
2537 if (!el)
2538 return EXT2_ET_NO_MEMORY;
2539 el->ea_count++;
2540
2541 if (ret)
2542 *ret = el->ea_count;
2543 return 0;
2544}
2545
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002546static errcode_t
2547ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002548{
2549 struct ea_refcount_el *el;
2550
2551 el = get_refcount_el(refcount, blk, 0);
2552 if (!el || el->ea_count == 0)
2553 return EXT2_ET_INVALID_ARGUMENT;
2554
2555 el->ea_count--;
2556
2557 if (ret)
2558 *ret = el->ea_count;
2559 return 0;
2560}
2561
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002562static errcode_t
2563ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002564{
2565 struct ea_refcount_el *el;
2566
2567 /*
2568 * Get the refcount element
2569 */
2570 el = get_refcount_el(refcount, blk, count ? 1 : 0);
2571 if (!el)
2572 return count ? EXT2_ET_NO_MEMORY : 0;
2573 el->ea_count = count;
2574 return 0;
2575}
2576
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002577static inline void ea_refcount_intr_begin(ext2_refcount_t refcount)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002578{
2579 refcount->cursor = 0;
2580}
2581
2582
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002583static blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002584{
2585 struct ea_refcount_el *list;
2586
2587 while (1) {
2588 if (refcount->cursor >= refcount->count)
2589 return 0;
2590 list = refcount->list;
2591 if (list[refcount->cursor].ea_count) {
2592 if (ret)
2593 *ret = list[refcount->cursor].ea_count;
2594 return list[refcount->cursor++].ea_blk;
2595 }
2596 refcount->cursor++;
2597 }
2598}
2599
2600
2601/*
2602 * ehandler.c --- handle bad block errors which come up during the
2603 * course of an e2fsck session.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002604 */
2605
2606
2607static const char *operation;
2608
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002609static errcode_t
2610e2fsck_handle_read_error(io_channel channel, unsigned long block, int count,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00002611 void *data, size_t size FSCK_ATTR((unused)),
2612 int actual FSCK_ATTR((unused)), errcode_t error)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002613{
2614 int i;
2615 char *p;
2616 ext2_filsys fs = (ext2_filsys) channel->app_data;
2617 e2fsck_t ctx;
2618
2619 ctx = (e2fsck_t) fs->priv_data;
2620
2621 /*
2622 * If more than one block was read, try reading each block
2623 * separately. We could use the actual bytes read to figure
2624 * out where to start, but we don't bother.
2625 */
2626 if (count > 1) {
2627 p = (char *) data;
2628 for (i=0; i < count; i++, p += channel->block_size, block++) {
2629 error = io_channel_read_blk(channel, block,
2630 1, p);
2631 if (error)
2632 return error;
2633 }
2634 return 0;
2635 }
2636 if (operation)
2637 printf(_("Error reading block %lu (%s) while %s. "), block,
2638 error_message(error), operation);
2639 else
2640 printf(_("Error reading block %lu (%s). "), block,
2641 error_message(error));
2642 preenhalt(ctx);
2643 if (ask(ctx, _("Ignore error"), 1)) {
2644 if (ask(ctx, _("Force rewrite"), 1))
2645 io_channel_write_blk(channel, block, 1, data);
2646 return 0;
2647 }
2648
2649 return error;
2650}
2651
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002652static errcode_t
2653e2fsck_handle_write_error(io_channel channel, unsigned long block, int count,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00002654 const 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 const 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 written, try writing 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 = (const char *) data;
2671 for (i=0; i < count; i++, p += channel->block_size, block++) {
2672 error = io_channel_write_blk(channel, block,
2673 1, p);
2674 if (error)
2675 return error;
2676 }
2677 return 0;
2678 }
2679
2680 if (operation)
2681 printf(_("Error writing block %lu (%s) while %s. "), block,
2682 error_message(error), operation);
2683 else
2684 printf(_("Error writing block %lu (%s). "), block,
2685 error_message(error));
2686 preenhalt(ctx);
2687 if (ask(ctx, _("Ignore error"), 1))
2688 return 0;
2689
2690 return error;
2691}
2692
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002693static inline const char *ehandler_operation(const char *op)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002694{
2695 const char *ret = operation;
2696
2697 operation = op;
2698 return ret;
2699}
2700
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002701static void ehandler_init(io_channel channel)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002702{
2703 channel->read_error = e2fsck_handle_read_error;
2704 channel->write_error = e2fsck_handle_write_error;
2705}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002706
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002707/*
2708 * journal.c --- code for handling the "ext3" journal
2709 *
2710 * Copyright (C) 2000 Andreas Dilger
2711 * Copyright (C) 2000 Theodore Ts'o
2712 *
2713 * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie
2714 * Copyright (C) 1999 Red Hat Software
2715 *
2716 * This file may be redistributed under the terms of the
2717 * GNU General Public License version 2 or at your discretion
2718 * any later version.
2719 */
2720
2721#define MNT_FL (MS_MGC_VAL | MS_RDONLY)
2722
2723
2724#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
2725static int bh_count = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +00002726#endif
2727
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002728/*
2729 * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
2730 * This creates a larger static binary, and a smaller binary using
2731 * shared libraries. It's also probably slightly less CPU-efficient,
2732 * which is why it's not on by default. But, it's a good way of
2733 * testing the functions in inode_io.c and fileio.c.
2734 */
2735#undef USE_INODE_IO
2736
2737/* Kernel compatibility functions for handling the journal. These allow us
2738 * to use the recovery.c file virtually unchanged from the kernel, so we
2739 * don't have to do much to keep kernel and user recovery in sync.
2740 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002741static int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002742{
2743#ifdef USE_INODE_IO
2744 *phys = block;
2745 return 0;
2746#else
2747 struct inode *inode = journal->j_inode;
2748 errcode_t retval;
2749 blk_t pblk;
2750
2751 if (!inode) {
2752 *phys = block;
2753 return 0;
2754 }
2755
2756 retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino,
2757 &inode->i_ext2, NULL, 0, block, &pblk);
2758 *phys = pblk;
2759 return (retval);
2760#endif
2761}
2762
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002763static struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002764{
2765 struct buffer_head *bh;
2766
2767 bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer");
2768 if (!bh)
2769 return NULL;
2770
2771 jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n",
2772 (unsigned long) blocknr, blocksize, ++bh_count);
2773
2774 bh->b_ctx = kdev->k_ctx;
2775 if (kdev->k_dev == K_DEV_FS)
2776 bh->b_io = kdev->k_ctx->fs->io;
2777 else
2778 bh->b_io = kdev->k_ctx->journal_io;
2779 bh->b_size = blocksize;
2780 bh->b_blocknr = blocknr;
2781
2782 return bh;
2783}
2784
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002785static void sync_blockdev(kdev_t kdev)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002786{
2787 io_channel io;
2788
2789 if (kdev->k_dev == K_DEV_FS)
2790 io = kdev->k_ctx->fs->io;
2791 else
2792 io = kdev->k_ctx->journal_io;
2793
2794 io_channel_flush(io);
2795}
2796
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002797static void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002798{
2799 int retval;
2800 struct buffer_head *bh;
2801
2802 for (; nr > 0; --nr) {
2803 bh = *bhp++;
2804 if (rw == READ && !bh->b_uptodate) {
2805 jfs_debug(3, "reading block %lu/%p\n",
2806 (unsigned long) bh->b_blocknr, (void *) bh);
2807 retval = io_channel_read_blk(bh->b_io,
2808 bh->b_blocknr,
2809 1, bh->b_data);
2810 if (retval) {
2811 com_err(bh->b_ctx->device_name, retval,
2812 "while reading block %lu\n",
2813 (unsigned long) bh->b_blocknr);
2814 bh->b_err = retval;
2815 continue;
2816 }
2817 bh->b_uptodate = 1;
2818 } else if (rw == WRITE && bh->b_dirty) {
2819 jfs_debug(3, "writing block %lu/%p\n",
2820 (unsigned long) bh->b_blocknr, (void *) bh);
2821 retval = io_channel_write_blk(bh->b_io,
2822 bh->b_blocknr,
2823 1, bh->b_data);
2824 if (retval) {
2825 com_err(bh->b_ctx->device_name, retval,
2826 "while writing block %lu\n",
2827 (unsigned long) bh->b_blocknr);
2828 bh->b_err = retval;
2829 continue;
2830 }
2831 bh->b_dirty = 0;
2832 bh->b_uptodate = 1;
2833 } else {
2834 jfs_debug(3, "no-op %s for block %lu\n",
2835 rw == READ ? "read" : "write",
2836 (unsigned long) bh->b_blocknr);
2837 }
2838 }
2839}
2840
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002841static inline void mark_buffer_dirty(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002842{
2843 bh->b_dirty = 1;
2844}
2845
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002846static inline void mark_buffer_clean(struct buffer_head * bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002847{
2848 bh->b_dirty = 0;
2849}
2850
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002851static void brelse(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002852{
2853 if (bh->b_dirty)
2854 ll_rw_block(WRITE, 1, &bh);
2855 jfs_debug(3, "freeing block %lu/%p (total %d)\n",
2856 (unsigned long) bh->b_blocknr, (void *) bh, --bh_count);
2857 ext2fs_free_mem(&bh);
2858}
2859
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002860static inline int buffer_uptodate(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002861{
2862 return bh->b_uptodate;
2863}
2864
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002865static inline void mark_buffer_uptodate(struct buffer_head *bh, int val)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002866{
2867 bh->b_uptodate = val;
2868}
2869
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002870static void wait_on_buffer(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002871{
2872 if (!bh->b_uptodate)
2873 ll_rw_block(READ, 1, &bh);
2874}
2875
2876
2877static void e2fsck_clear_recover(e2fsck_t ctx, int error)
2878{
2879 ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
2880
2881 /* if we had an error doing journal recovery, we need a full fsck */
2882 if (error)
2883 ctx->fs->super->s_state &= ~EXT2_VALID_FS;
2884 ext2fs_mark_super_dirty(ctx->fs);
2885}
2886
2887static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
2888{
2889 struct ext2_super_block *sb = ctx->fs->super;
2890 struct ext2_super_block jsuper;
2891 struct problem_context pctx;
2892 struct buffer_head *bh;
2893 struct inode *j_inode = NULL;
2894 struct kdev_s *dev_fs = NULL, *dev_journal;
2895 const char *journal_name = 0;
2896 journal_t *journal = NULL;
2897 errcode_t retval = 0;
2898 io_manager io_ptr = 0;
2899 unsigned long start = 0;
2900 blk_t blk;
2901 int ext_journal = 0;
2902 int tried_backup_jnl = 0;
2903 int i;
2904
2905 clear_problem_context(&pctx);
2906
2907 journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
2908 if (!journal) {
2909 return EXT2_ET_NO_MEMORY;
2910 }
2911
2912 dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
2913 if (!dev_fs) {
2914 retval = EXT2_ET_NO_MEMORY;
2915 goto errout;
2916 }
2917 dev_journal = dev_fs+1;
2918
2919 dev_fs->k_ctx = dev_journal->k_ctx = ctx;
2920 dev_fs->k_dev = K_DEV_FS;
2921 dev_journal->k_dev = K_DEV_JOURNAL;
2922
2923 journal->j_dev = dev_journal;
2924 journal->j_fs_dev = dev_fs;
2925 journal->j_inode = NULL;
2926 journal->j_blocksize = ctx->fs->blocksize;
2927
2928 if (uuid_is_null(sb->s_journal_uuid)) {
2929 if (!sb->s_journal_inum)
2930 return EXT2_ET_BAD_INODE_NUM;
2931 j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
2932 "journal inode");
2933 if (!j_inode) {
2934 retval = EXT2_ET_NO_MEMORY;
2935 goto errout;
2936 }
2937
2938 j_inode->i_ctx = ctx;
2939 j_inode->i_ino = sb->s_journal_inum;
2940
2941 if ((retval = ext2fs_read_inode(ctx->fs,
2942 sb->s_journal_inum,
2943 &j_inode->i_ext2))) {
2944 try_backup_journal:
2945 if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
2946 tried_backup_jnl)
2947 goto errout;
2948 memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
2949 memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
2950 EXT2_N_BLOCKS*4);
2951 j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
2952 j_inode->i_ext2.i_links_count = 1;
2953 j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
2954 tried_backup_jnl++;
2955 }
2956 if (!j_inode->i_ext2.i_links_count ||
2957 !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
2958 retval = EXT2_ET_NO_JOURNAL;
2959 goto try_backup_journal;
2960 }
2961 if (j_inode->i_ext2.i_size / journal->j_blocksize <
2962 JFS_MIN_JOURNAL_BLOCKS) {
2963 retval = EXT2_ET_JOURNAL_TOO_SMALL;
2964 goto try_backup_journal;
2965 }
2966 for (i=0; i < EXT2_N_BLOCKS; i++) {
2967 blk = j_inode->i_ext2.i_block[i];
2968 if (!blk) {
2969 if (i < EXT2_NDIR_BLOCKS) {
2970 retval = EXT2_ET_JOURNAL_TOO_SMALL;
2971 goto try_backup_journal;
2972 }
2973 continue;
2974 }
2975 if (blk < sb->s_first_data_block ||
2976 blk >= sb->s_blocks_count) {
2977 retval = EXT2_ET_BAD_BLOCK_NUM;
2978 goto try_backup_journal;
2979 }
2980 }
2981 journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;
2982
2983#ifdef USE_INODE_IO
2984 retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
2985 &j_inode->i_ext2,
2986 &journal_name);
2987 if (retval)
2988 goto errout;
2989
2990 io_ptr = inode_io_manager;
2991#else
2992 journal->j_inode = j_inode;
2993 ctx->journal_io = ctx->fs->io;
2994 if ((retval = journal_bmap(journal, 0, &start)) != 0)
2995 goto errout;
2996#endif
2997 } else {
2998 ext_journal = 1;
2999 if (!ctx->journal_name) {
3000 char uuid[37];
3001
3002 uuid_unparse(sb->s_journal_uuid, uuid);
3003 ctx->journal_name = blkid_get_devname(ctx->blkid,
3004 "UUID", uuid);
3005 if (!ctx->journal_name)
3006 ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
3007 }
3008 journal_name = ctx->journal_name;
3009
3010 if (!journal_name) {
3011 fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
3012 return EXT2_ET_LOAD_EXT_JOURNAL;
3013 }
3014
3015 jfs_debug(1, "Using journal file %s\n", journal_name);
3016 io_ptr = unix_io_manager;
3017 }
3018
3019#if 0
3020 test_io_backing_manager = io_ptr;
3021 io_ptr = test_io_manager;
3022#endif
3023#ifndef USE_INODE_IO
3024 if (ext_journal)
3025#endif
3026 retval = io_ptr->open(journal_name, IO_FLAG_RW,
3027 &ctx->journal_io);
3028 if (retval)
3029 goto errout;
3030
3031 io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
3032
3033 if (ext_journal) {
3034 if (ctx->fs->blocksize == 1024)
3035 start = 1;
3036 bh = getblk(dev_journal, start, ctx->fs->blocksize);
3037 if (!bh) {
3038 retval = EXT2_ET_NO_MEMORY;
3039 goto errout;
3040 }
3041 ll_rw_block(READ, 1, &bh);
3042 if ((retval = bh->b_err) != 0)
3043 goto errout;
3044 memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
3045 sizeof(jsuper));
3046 brelse(bh);
3047#ifdef EXT2FS_ENABLE_SWAPFS
3048 if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
3049 ext2fs_swap_super(&jsuper);
3050#endif
3051 if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
3052 !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
3053 fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
3054 retval = EXT2_ET_LOAD_EXT_JOURNAL;
3055 goto errout;
3056 }
3057 /* Make sure the journal UUID is correct */
3058 if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
3059 sizeof(jsuper.s_uuid))) {
3060 fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
3061 retval = EXT2_ET_LOAD_EXT_JOURNAL;
3062 goto errout;
3063 }
3064
3065 journal->j_maxlen = jsuper.s_blocks_count;
3066 start++;
3067 }
3068
3069 if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
3070 retval = EXT2_ET_NO_MEMORY;
3071 goto errout;
3072 }
3073
3074 journal->j_sb_buffer = bh;
3075 journal->j_superblock = (journal_superblock_t *)bh->b_data;
3076
3077#ifdef USE_INODE_IO
Rob Landleye7c43b62006-03-01 16:39:45 +00003078 ext2fs_free_mem(&j_inode);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003079#endif
3080
3081 *ret_journal = journal;
3082 return 0;
3083
3084errout:
Rob Landleye7c43b62006-03-01 16:39:45 +00003085 ext2fs_free_mem(&dev_fs);
3086 ext2fs_free_mem(&j_inode);
3087 ext2fs_free_mem(&journal);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003088 return retval;
3089
3090}
3091
3092static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
3093 struct problem_context *pctx)
3094{
3095 struct ext2_super_block *sb = ctx->fs->super;
3096 int recover = ctx->fs->super->s_feature_incompat &
3097 EXT3_FEATURE_INCOMPAT_RECOVER;
3098 int has_journal = ctx->fs->super->s_feature_compat &
3099 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3100
3101 if (has_journal || sb->s_journal_inum) {
3102 /* The journal inode is bogus, remove and force full fsck */
3103 pctx->ino = sb->s_journal_inum;
3104 if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
3105 if (has_journal && sb->s_journal_inum)
3106 printf("*** ext3 journal has been deleted - "
3107 "filesystem is now ext2 only ***\n\n");
3108 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3109 sb->s_journal_inum = 0;
3110 ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */
3111 e2fsck_clear_recover(ctx, 1);
3112 return 0;
3113 }
3114 return EXT2_ET_BAD_INODE_NUM;
3115 } else if (recover) {
3116 if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
3117 e2fsck_clear_recover(ctx, 1);
3118 return 0;
3119 }
3120 return EXT2_ET_UNSUPP_FEATURE;
3121 }
3122 return 0;
3123}
3124
3125#define V1_SB_SIZE 0x0024
3126static void clear_v2_journal_fields(journal_t *journal)
3127{
3128 e2fsck_t ctx = journal->j_dev->k_ctx;
3129 struct problem_context pctx;
3130
3131 clear_problem_context(&pctx);
3132
3133 if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
3134 return;
3135
3136 memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
3137 ctx->fs->blocksize-V1_SB_SIZE);
3138 mark_buffer_dirty(journal->j_sb_buffer);
3139}
3140
3141
3142static errcode_t e2fsck_journal_load(journal_t *journal)
3143{
3144 e2fsck_t ctx = journal->j_dev->k_ctx;
3145 journal_superblock_t *jsb;
3146 struct buffer_head *jbh = journal->j_sb_buffer;
3147 struct problem_context pctx;
3148
3149 clear_problem_context(&pctx);
3150
3151 ll_rw_block(READ, 1, &jbh);
3152 if (jbh->b_err) {
3153 com_err(ctx->device_name, jbh->b_err,
3154 _("reading journal superblock\n"));
3155 return jbh->b_err;
3156 }
3157
3158 jsb = journal->j_superblock;
3159 /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
3160 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
3161 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
3162
3163 switch (ntohl(jsb->s_header.h_blocktype)) {
3164 case JFS_SUPERBLOCK_V1:
3165 journal->j_format_version = 1;
3166 if (jsb->s_feature_compat ||
3167 jsb->s_feature_incompat ||
3168 jsb->s_feature_ro_compat ||
3169 jsb->s_nr_users)
3170 clear_v2_journal_fields(journal);
3171 break;
3172
3173 case JFS_SUPERBLOCK_V2:
3174 journal->j_format_version = 2;
3175 if (ntohl(jsb->s_nr_users) > 1 &&
3176 uuid_is_null(ctx->fs->super->s_journal_uuid))
3177 clear_v2_journal_fields(journal);
3178 if (ntohl(jsb->s_nr_users) > 1) {
3179 fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
3180 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
3181 }
3182 break;
3183
3184 /*
3185 * These should never appear in a journal super block, so if
3186 * they do, the journal is badly corrupted.
3187 */
3188 case JFS_DESCRIPTOR_BLOCK:
3189 case JFS_COMMIT_BLOCK:
3190 case JFS_REVOKE_BLOCK:
3191 return EXT2_ET_CORRUPT_SUPERBLOCK;
3192
3193 /* If we don't understand the superblock major type, but there
3194 * is a magic number, then it is likely to be a new format we
3195 * just don't understand, so leave it alone. */
3196 default:
3197 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
3198 }
3199
3200 if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
3201 return EXT2_ET_UNSUPP_FEATURE;
3202
3203 if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
3204 return EXT2_ET_RO_UNSUPP_FEATURE;
3205
3206 /* We have now checked whether we know enough about the journal
3207 * format to be able to proceed safely, so any other checks that
3208 * fail we should attempt to recover from. */
3209 if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
3210 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
3211 _("%s: no valid journal superblock found\n"),
3212 ctx->device_name);
3213 return EXT2_ET_CORRUPT_SUPERBLOCK;
3214 }
3215
3216 if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
3217 journal->j_maxlen = ntohl(jsb->s_maxlen);
3218 else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
3219 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
3220 _("%s: journal too short\n"),
3221 ctx->device_name);
3222 return EXT2_ET_CORRUPT_SUPERBLOCK;
3223 }
3224
3225 journal->j_tail_sequence = ntohl(jsb->s_sequence);
3226 journal->j_transaction_sequence = journal->j_tail_sequence;
3227 journal->j_tail = ntohl(jsb->s_start);
3228 journal->j_first = ntohl(jsb->s_first);
3229 journal->j_last = ntohl(jsb->s_maxlen);
3230
3231 return 0;
3232}
3233
3234static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
3235 journal_t *journal)
3236{
3237 char *p;
3238 union {
3239 uuid_t uuid;
3240 __u32 val[4];
3241 } u;
3242 __u32 new_seq = 0;
3243 int i;
3244
3245 /* Leave a valid existing V1 superblock signature alone.
3246 * Anything unrecognisable we overwrite with a new V2
3247 * signature. */
3248
3249 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
3250 jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
3251 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
3252 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
3253 }
3254
3255 /* Zero out everything else beyond the superblock header */
3256
3257 p = ((char *) jsb) + sizeof(journal_header_t);
3258 memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
3259
3260 jsb->s_blocksize = htonl(ctx->fs->blocksize);
3261 jsb->s_maxlen = htonl(journal->j_maxlen);
3262 jsb->s_first = htonl(1);
3263
3264 /* Initialize the journal sequence number so that there is "no"
3265 * chance we will find old "valid" transactions in the journal.
3266 * This avoids the need to zero the whole journal (slow to do,
3267 * and risky when we are just recovering the filesystem).
3268 */
3269 uuid_generate(u.uuid);
3270 for (i = 0; i < 4; i ++)
3271 new_seq ^= u.val[i];
3272 jsb->s_sequence = htonl(new_seq);
3273
3274 mark_buffer_dirty(journal->j_sb_buffer);
3275 ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
3276}
3277
3278static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
3279 journal_t *journal,
3280 struct problem_context *pctx)
3281{
3282 struct ext2_super_block *sb = ctx->fs->super;
3283 int recover = ctx->fs->super->s_feature_incompat &
3284 EXT3_FEATURE_INCOMPAT_RECOVER;
3285
3286 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
3287 if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
3288 e2fsck_journal_reset_super(ctx, journal->j_superblock,
3289 journal);
3290 journal->j_transaction_sequence = 1;
3291 e2fsck_clear_recover(ctx, recover);
3292 return 0;
3293 }
3294 return EXT2_ET_CORRUPT_SUPERBLOCK;
3295 } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
3296 return EXT2_ET_CORRUPT_SUPERBLOCK;
3297
3298 return 0;
3299}
3300
3301static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
3302 int reset, int drop)
3303{
3304 journal_superblock_t *jsb;
3305
3306 if (drop)
3307 mark_buffer_clean(journal->j_sb_buffer);
3308 else if (!(ctx->options & E2F_OPT_READONLY)) {
3309 jsb = journal->j_superblock;
3310 jsb->s_sequence = htonl(journal->j_transaction_sequence);
3311 if (reset)
3312 jsb->s_start = 0; /* this marks the journal as empty */
3313 mark_buffer_dirty(journal->j_sb_buffer);
3314 }
3315 brelse(journal->j_sb_buffer);
3316
3317 if (ctx->journal_io) {
3318 if (ctx->fs && ctx->fs->io != ctx->journal_io)
3319 io_channel_close(ctx->journal_io);
3320 ctx->journal_io = 0;
3321 }
3322
3323#ifndef USE_INODE_IO
Rob Landleye7c43b62006-03-01 16:39:45 +00003324 ext2fs_free_mem(&journal->j_inode);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003325#endif
Rob Landleye7c43b62006-03-01 16:39:45 +00003326 ext2fs_free_mem(&journal->j_fs_dev);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003327 ext2fs_free_mem(&journal);
3328}
3329
3330/*
3331 * This function makes sure that the superblock fields regarding the
3332 * journal are consistent.
3333 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003334static int e2fsck_check_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003335{
3336 struct ext2_super_block *sb = ctx->fs->super;
3337 journal_t *journal;
3338 int recover = ctx->fs->super->s_feature_incompat &
3339 EXT3_FEATURE_INCOMPAT_RECOVER;
3340 struct problem_context pctx;
3341 problem_t problem;
3342 int reset = 0, force_fsck = 0;
3343 int retval;
3344
3345 /* If we don't have any journal features, don't do anything more */
3346 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
3347 !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
3348 uuid_is_null(sb->s_journal_uuid))
3349 return 0;
3350
3351 clear_problem_context(&pctx);
3352 pctx.num = sb->s_journal_inum;
3353
3354 retval = e2fsck_get_journal(ctx, &journal);
3355 if (retval) {
3356 if ((retval == EXT2_ET_BAD_INODE_NUM) ||
3357 (retval == EXT2_ET_BAD_BLOCK_NUM) ||
3358 (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
3359 (retval == EXT2_ET_NO_JOURNAL))
3360 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
3361 return retval;
3362 }
3363
3364 retval = e2fsck_journal_load(journal);
3365 if (retval) {
3366 if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
3367 ((retval == EXT2_ET_UNSUPP_FEATURE) &&
3368 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
3369 &pctx))) ||
3370 ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
3371 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
3372 &pctx))) ||
3373 ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
3374 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
3375 retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
3376 &pctx);
3377 e2fsck_journal_release(ctx, journal, 0, 1);
3378 return retval;
3379 }
3380
3381 /*
3382 * We want to make the flags consistent here. We will not leave with
3383 * needs_recovery set but has_journal clear. We can't get in a loop
3384 * with -y, -n, or -p, only if a user isn't making up their mind.
3385 */
3386no_has_journal:
3387 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
3388 recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
3389 pctx.str = "inode";
3390 if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
3391 if (recover &&
3392 !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
3393 goto no_has_journal;
3394 /*
3395 * Need a full fsck if we are releasing a
3396 * journal stored on a reserved inode.
3397 */
3398 force_fsck = recover ||
3399 (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
3400 /* Clear all of the journal fields */
3401 sb->s_journal_inum = 0;
3402 sb->s_journal_dev = 0;
3403 memset(sb->s_journal_uuid, 0,
3404 sizeof(sb->s_journal_uuid));
3405 e2fsck_clear_recover(ctx, force_fsck);
3406 } else if (!(ctx->options & E2F_OPT_READONLY)) {
3407 sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3408 ext2fs_mark_super_dirty(ctx->fs);
3409 }
3410 }
3411
3412 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
3413 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
3414 journal->j_superblock->s_start != 0) {
3415 /* Print status information */
3416 fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
3417 if (ctx->superblock)
3418 problem = PR_0_JOURNAL_RUN_DEFAULT;
3419 else
3420 problem = PR_0_JOURNAL_RUN;
3421 if (fix_problem(ctx, problem, &pctx)) {
3422 ctx->options |= E2F_OPT_FORCE;
3423 sb->s_feature_incompat |=
3424 EXT3_FEATURE_INCOMPAT_RECOVER;
3425 ext2fs_mark_super_dirty(ctx->fs);
3426 } else if (fix_problem(ctx,
3427 PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
3428 reset = 1;
3429 sb->s_state &= ~EXT2_VALID_FS;
3430 ext2fs_mark_super_dirty(ctx->fs);
3431 }
3432 /*
3433 * If the user answers no to the above question, we
3434 * ignore the fact that journal apparently has data;
3435 * accidentally replaying over valid data would be far
3436 * worse than skipping a questionable recovery.
3437 *
3438 * XXX should we abort with a fatal error here? What
3439 * will the ext3 kernel code do if a filesystem with
3440 * !NEEDS_RECOVERY but with a non-zero
3441 * journal->j_superblock->s_start is mounted?
3442 */
3443 }
3444
3445 e2fsck_journal_release(ctx, journal, reset, 0);
3446 return retval;
3447}
3448
3449static errcode_t recover_ext3_journal(e2fsck_t ctx)
3450{
3451 journal_t *journal;
3452 int retval;
3453
3454 journal_init_revoke_caches();
3455 retval = e2fsck_get_journal(ctx, &journal);
3456 if (retval)
3457 return retval;
3458
3459 retval = e2fsck_journal_load(journal);
3460 if (retval)
3461 goto errout;
3462
3463 retval = journal_init_revoke(journal, 1024);
3464 if (retval)
3465 goto errout;
3466
3467 retval = -journal_recover(journal);
3468 if (retval)
3469 goto errout;
3470
3471 if (journal->j_superblock->s_errno) {
3472 ctx->fs->super->s_state |= EXT2_ERROR_FS;
3473 ext2fs_mark_super_dirty(ctx->fs);
3474 journal->j_superblock->s_errno = 0;
3475 mark_buffer_dirty(journal->j_sb_buffer);
3476 }
3477
3478errout:
3479 journal_destroy_revoke(journal);
3480 journal_destroy_revoke_caches();
3481 e2fsck_journal_release(ctx, journal, 1, 0);
3482 return retval;
3483}
3484
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003485static int e2fsck_run_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003486{
3487 io_manager io_ptr = ctx->fs->io->manager;
3488 int blocksize = ctx->fs->blocksize;
3489 errcode_t retval, recover_retval;
3490
3491 printf(_("%s: recovering journal\n"), ctx->device_name);
3492 if (ctx->options & E2F_OPT_READONLY) {
3493 printf(_("%s: won't do journal recovery while read-only\n"),
3494 ctx->device_name);
3495 return EXT2_ET_FILE_RO;
3496 }
3497
3498 if (ctx->fs->flags & EXT2_FLAG_DIRTY)
3499 ext2fs_flush(ctx->fs); /* Force out any modifications */
3500
3501 recover_retval = recover_ext3_journal(ctx);
3502
3503 /*
3504 * Reload the filesystem context to get up-to-date data from disk
3505 * because journal recovery will change the filesystem under us.
3506 */
3507 ext2fs_close(ctx->fs);
3508 retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
3509 ctx->superblock, blocksize, io_ptr,
3510 &ctx->fs);
3511
3512 if (retval) {
3513 com_err(ctx->program_name, retval,
3514 _("while trying to re-open %s"),
3515 ctx->device_name);
3516 fatal_error(ctx, 0);
3517 }
3518 ctx->fs->priv_data = ctx;
3519
3520 /* Set the superblock flags */
3521 e2fsck_clear_recover(ctx, recover_retval);
3522 return recover_retval;
3523}
3524
3525/*
3526 * This function will move the journal inode from a visible file in
3527 * the filesystem directory hierarchy to the reserved inode if necessary.
3528 */
3529static const char * const journal_names[] = {
3530 ".journal", "journal", ".journal.dat", "journal.dat", 0 };
3531
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003532static void e2fsck_move_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003533{
3534 struct ext2_super_block *sb = ctx->fs->super;
3535 struct problem_context pctx;
3536 struct ext2_inode inode;
3537 ext2_filsys fs = ctx->fs;
3538 ext2_ino_t ino;
3539 errcode_t retval;
3540 const char * const * cpp;
3541 int group, mount_flags;
3542
3543 clear_problem_context(&pctx);
3544
3545 /*
3546 * If the filesystem is opened read-only, or there is no
3547 * journal, then do nothing.
3548 */
3549 if ((ctx->options & E2F_OPT_READONLY) ||
3550 (sb->s_journal_inum == 0) ||
3551 !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
3552 return;
3553
3554 /*
3555 * Read in the journal inode
3556 */
3557 if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
3558 return;
3559
3560 /*
3561 * If it's necessary to backup the journal inode, do so.
3562 */
3563 if ((sb->s_jnl_backup_type == 0) ||
3564 ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
3565 memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
3566 if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
3567 memcpy(sb->s_jnl_blocks, inode.i_block,
3568 EXT2_N_BLOCKS*4);
3569 sb->s_jnl_blocks[16] = inode.i_size;
3570 sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
3571 ext2fs_mark_super_dirty(fs);
3572 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3573 }
3574 }
3575
3576 /*
3577 * If the journal is already the hidden inode, then do nothing
3578 */
3579 if (sb->s_journal_inum == EXT2_JOURNAL_INO)
3580 return;
3581
3582 /*
3583 * The journal inode had better have only one link and not be readable.
3584 */
3585 if (inode.i_links_count != 1)
3586 return;
3587
3588 /*
3589 * If the filesystem is mounted, or we can't tell whether
3590 * or not it's mounted, do nothing.
3591 */
3592 retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
3593 if (retval || (mount_flags & EXT2_MF_MOUNTED))
3594 return;
3595
3596 /*
3597 * If we can't find the name of the journal inode, then do
3598 * nothing.
3599 */
3600 for (cpp = journal_names; *cpp; cpp++) {
3601 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
3602 strlen(*cpp), 0, &ino);
3603 if ((retval == 0) && (ino == sb->s_journal_inum))
3604 break;
3605 }
3606 if (*cpp == 0)
3607 return;
3608
3609 /* We need the inode bitmap to be loaded */
3610 retval = ext2fs_read_bitmaps(fs);
3611 if (retval)
3612 return;
3613
3614 pctx.str = *cpp;
3615 if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
3616 return;
3617
3618 /*
3619 * OK, we've done all the checks, let's actually move the
3620 * journal inode. Errors at this point mean we need to force
3621 * an ext2 filesystem check.
3622 */
3623 if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
3624 goto err_out;
3625 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
3626 goto err_out;
3627 sb->s_journal_inum = EXT2_JOURNAL_INO;
3628 ext2fs_mark_super_dirty(fs);
3629 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3630 inode.i_links_count = 0;
3631 inode.i_dtime = time(0);
3632 if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
3633 goto err_out;
3634
3635 group = ext2fs_group_of_ino(fs, ino);
3636 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
3637 ext2fs_mark_ib_dirty(fs);
3638 fs->group_desc[group].bg_free_inodes_count++;
3639 fs->super->s_free_inodes_count++;
3640 return;
3641
3642err_out:
3643 pctx.errcode = retval;
3644 fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
3645 fs->super->s_state &= ~EXT2_VALID_FS;
3646 ext2fs_mark_super_dirty(fs);
3647 return;
3648}
3649
3650/*
3651 * message.c --- print e2fsck messages (with compression)
3652 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003653 * print_e2fsck_message() prints a message to the user, using
3654 * compression techniques and expansions of abbreviations.
3655 *
3656 * The following % expansions are supported:
3657 *
3658 * %b <blk> block number
3659 * %B <blkcount> integer
3660 * %c <blk2> block number
3661 * %Di <dirent>->ino inode number
3662 * %Dn <dirent>->name string
3663 * %Dr <dirent>->rec_len
3664 * %Dl <dirent>->name_len
3665 * %Dt <dirent>->filetype
3666 * %d <dir> inode number
3667 * %g <group> integer
3668 * %i <ino> inode number
3669 * %Is <inode> -> i_size
3670 * %IS <inode> -> i_extra_isize
3671 * %Ib <inode> -> i_blocks
3672 * %Il <inode> -> i_links_count
3673 * %Im <inode> -> i_mode
3674 * %IM <inode> -> i_mtime
3675 * %IF <inode> -> i_faddr
3676 * %If <inode> -> i_file_acl
3677 * %Id <inode> -> i_dir_acl
3678 * %Iu <inode> -> i_uid
3679 * %Ig <inode> -> i_gid
3680 * %j <ino2> inode number
3681 * %m <com_err error message>
3682 * %N <num>
3683 * %p ext2fs_get_pathname of directory <ino>
3684 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
3685 * the containing directory. (If dirent is NULL
3686 * then return the pathname of directory <ino2>)
3687 * %q ext2fs_get_pathname of directory <dir>
3688 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
3689 * the containing directory.
3690 * %s <str> miscellaneous string
3691 * %S backup superblock
3692 * %X <num> hexadecimal format
3693 *
3694 * The following '@' expansions are supported:
3695 *
3696 * @a extended attribute
3697 * @A error allocating
3698 * @b block
3699 * @B bitmap
3700 * @c compress
3701 * @C conflicts with some other fs block
3702 * @D deleted
3703 * @d directory
3704 * @e entry
3705 * @E Entry '%Dn' in %p (%i)
3706 * @f filesystem
3707 * @F for @i %i (%Q) is
3708 * @g group
3709 * @h HTREE directory inode
3710 * @i inode
3711 * @I illegal
3712 * @j journal
3713 * @l lost+found
3714 * @L is a link
3715 * @o orphaned
3716 * @p problem in
3717 * @r root inode
3718 * @s should be
3719 * @S superblock
3720 * @u unattached
3721 * @v device
3722 * @z zero-length
3723 */
3724
3725
3726/*
3727 * This structure defines the abbreviations used by the text strings
3728 * below. The first character in the string is the index letter. An
3729 * abbreviation of the form '@<i>' is expanded by looking up the index
3730 * letter <i> in the table below.
3731 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003732static const char * const abbrevs[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003733 N_("aextended attribute"),
3734 N_("Aerror allocating"),
3735 N_("bblock"),
3736 N_("Bbitmap"),
3737 N_("ccompress"),
3738 N_("Cconflicts with some other fs @b"),
3739 N_("iinode"),
3740 N_("Iillegal"),
3741 N_("jjournal"),
3742 N_("Ddeleted"),
3743 N_("ddirectory"),
3744 N_("eentry"),
3745 N_("E@e '%Dn' in %p (%i)"),
3746 N_("ffilesystem"),
3747 N_("Ffor @i %i (%Q) is"),
3748 N_("ggroup"),
3749 N_("hHTREE @d @i"),
3750 N_("llost+found"),
3751 N_("Lis a link"),
3752 N_("oorphaned"),
3753 N_("pproblem in"),
3754 N_("rroot @i"),
3755 N_("sshould be"),
3756 N_("Ssuper@b"),
3757 N_("uunattached"),
3758 N_("vdevice"),
3759 N_("zzero-length"),
3760 "@@",
3761 0
3762 };
3763
3764/*
3765 * Give more user friendly names to the "special" inodes.
3766 */
3767#define num_special_inodes 11
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003768static const char * const special_inode_name[] =
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003769{
3770 N_("<The NULL inode>"), /* 0 */
3771 N_("<The bad blocks inode>"), /* 1 */
3772 "/", /* 2 */
3773 N_("<The ACL index inode>"), /* 3 */
3774 N_("<The ACL data inode>"), /* 4 */
3775 N_("<The boot loader inode>"), /* 5 */
3776 N_("<The undelete directory inode>"), /* 6 */
3777 N_("<The group descriptor inode>"), /* 7 */
3778 N_("<The journal inode>"), /* 8 */
3779 N_("<Reserved inode 9>"), /* 9 */
3780 N_("<Reserved inode 10>"), /* 10 */
3781};
3782
3783/*
3784 * This function does "safe" printing. It will convert non-printable
3785 * ASCII characters using '^' and M- notation.
3786 */
3787static void safe_print(const char *cp, int len)
3788{
3789 unsigned char ch;
3790
3791 if (len < 0)
3792 len = strlen(cp);
3793
3794 while (len--) {
3795 ch = *cp++;
3796 if (ch > 128) {
3797 fputs("M-", stdout);
3798 ch -= 128;
3799 }
3800 if ((ch < 32) || (ch == 0x7f)) {
3801 fputc('^', stdout);
3802 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
3803 }
3804 fputc(ch, stdout);
3805 }
3806}
3807
3808
3809/*
3810 * This function prints a pathname, using the ext2fs_get_pathname
3811 * function
3812 */
3813static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
3814{
3815 errcode_t retval;
3816 char *path;
3817
3818 if (!dir && (ino < num_special_inodes)) {
3819 fputs(_(special_inode_name[ino]), stdout);
3820 return;
3821 }
3822
3823 retval = ext2fs_get_pathname(fs, dir, ino, &path);
3824 if (retval)
3825 fputs("???", stdout);
3826 else {
3827 safe_print(path, -1);
3828 ext2fs_free_mem(&path);
3829 }
3830}
3831
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003832static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
3833 struct problem_context *pctx, int first);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003834/*
3835 * This function handles the '@' expansion. We allow recursive
3836 * expansion; an @ expression can contain further '@' and '%'
3837 * expressions.
3838 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003839static void expand_at_expression(e2fsck_t ctx, char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003840 struct problem_context *pctx,
3841 int *first)
3842{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003843 const char * const *cpp;
3844 const char *str;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003845
3846 /* Search for the abbreviation */
3847 for (cpp = abbrevs; *cpp; cpp++) {
3848 if (ch == *cpp[0])
3849 break;
3850 }
3851 if (*cpp) {
3852 str = _(*cpp) + 1;
3853 if (*first && islower(*str)) {
3854 *first = 0;
3855 fputc(toupper(*str++), stdout);
3856 }
3857 print_e2fsck_message(ctx, str, pctx, *first);
3858 } else
3859 printf("@%c", ch);
3860}
3861
3862/*
3863 * This function expands '%IX' expressions
3864 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003865static void expand_inode_expression(char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003866 struct problem_context *ctx)
3867{
3868 struct ext2_inode *inode;
3869 struct ext2_inode_large *large_inode;
3870 char * time_str;
3871 time_t t;
3872 int do_gmt = -1;
3873
3874 if (!ctx || !ctx->inode)
3875 goto no_inode;
3876
3877 inode = ctx->inode;
3878 large_inode = (struct ext2_inode_large *) inode;
3879
3880 switch (ch) {
3881 case 's':
3882 if (LINUX_S_ISDIR(inode->i_mode))
3883 printf("%u", inode->i_size);
3884 else {
3885#ifdef EXT2_NO_64_TYPE
3886 if (inode->i_size_high)
3887 printf("0x%x%08x", inode->i_size_high,
3888 inode->i_size);
3889 else
3890 printf("%u", inode->i_size);
3891#else
3892 printf("%llu", (inode->i_size |
3893 ((__u64) inode->i_size_high << 32)));
3894#endif
3895 }
3896 break;
3897 case 'S':
3898 printf("%u", large_inode->i_extra_isize);
3899 break;
3900 case 'b':
3901 printf("%u", inode->i_blocks);
3902 break;
3903 case 'l':
3904 printf("%d", inode->i_links_count);
3905 break;
3906 case 'm':
3907 printf("0%o", inode->i_mode);
3908 break;
3909 case 'M':
3910 /* The diet libc doesn't respect the TZ environemnt variable */
3911 if (do_gmt == -1) {
3912 time_str = getenv("TZ");
3913 if (!time_str)
3914 time_str = "";
3915 do_gmt = !strcmp(time_str, "GMT");
3916 }
3917 t = inode->i_mtime;
3918 time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
3919 printf("%.24s", time_str);
3920 break;
3921 case 'F':
3922 printf("%u", inode->i_faddr);
3923 break;
3924 case 'f':
3925 printf("%u", inode->i_file_acl);
3926 break;
3927 case 'd':
3928 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
3929 inode->i_dir_acl : 0));
3930 break;
3931 case 'u':
3932 printf("%d", (inode->i_uid |
3933 (inode->osd2.linux2.l_i_uid_high << 16)));
3934 break;
3935 case 'g':
3936 printf("%d", (inode->i_gid |
3937 (inode->osd2.linux2.l_i_gid_high << 16)));
3938 break;
3939 default:
3940 no_inode:
3941 printf("%%I%c", ch);
3942 break;
3943 }
3944}
3945
3946/*
3947 * This function expands '%dX' expressions
3948 */
3949static _INLINE_ void expand_dirent_expression(char ch,
3950 struct problem_context *ctx)
3951{
3952 struct ext2_dir_entry *dirent;
3953 int len;
3954
3955 if (!ctx || !ctx->dirent)
3956 goto no_dirent;
3957
3958 dirent = ctx->dirent;
3959
3960 switch (ch) {
3961 case 'i':
3962 printf("%u", dirent->inode);
3963 break;
3964 case 'n':
3965 len = dirent->name_len & 0xFF;
3966 if (len > EXT2_NAME_LEN)
3967 len = EXT2_NAME_LEN;
3968 if (len > dirent->rec_len)
3969 len = dirent->rec_len;
3970 safe_print(dirent->name, len);
3971 break;
3972 case 'r':
3973 printf("%u", dirent->rec_len);
3974 break;
3975 case 'l':
3976 printf("%u", dirent->name_len & 0xFF);
3977 break;
3978 case 't':
3979 printf("%u", dirent->name_len >> 8);
3980 break;
3981 default:
3982 no_dirent:
3983 printf("%%D%c", ch);
3984 break;
3985 }
3986}
3987
3988static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
3989 struct problem_context *ctx)
3990{
3991 if (!ctx)
3992 goto no_context;
3993
3994 switch (ch) {
3995 case '%':
3996 fputc('%', stdout);
3997 break;
3998 case 'b':
3999 printf("%u", ctx->blk);
4000 break;
4001 case 'B':
4002#ifdef EXT2_NO_64_TYPE
4003 printf("%d", ctx->blkcount);
4004#else
4005 printf("%lld", ctx->blkcount);
4006#endif
4007 break;
4008 case 'c':
4009 printf("%u", ctx->blk2);
4010 break;
4011 case 'd':
4012 printf("%u", ctx->dir);
4013 break;
4014 case 'g':
4015 printf("%d", ctx->group);
4016 break;
4017 case 'i':
4018 printf("%u", ctx->ino);
4019 break;
4020 case 'j':
4021 printf("%u", ctx->ino2);
4022 break;
4023 case 'm':
4024 printf("%s", error_message(ctx->errcode));
4025 break;
4026 case 'N':
4027#ifdef EXT2_NO_64_TYPE
4028 printf("%u", ctx->num);
4029#else
4030 printf("%llu", ctx->num);
4031#endif
4032 break;
4033 case 'p':
4034 print_pathname(fs, ctx->ino, 0);
4035 break;
4036 case 'P':
4037 print_pathname(fs, ctx->ino2,
4038 ctx->dirent ? ctx->dirent->inode : 0);
4039 break;
4040 case 'q':
4041 print_pathname(fs, ctx->dir, 0);
4042 break;
4043 case 'Q':
4044 print_pathname(fs, ctx->dir, ctx->ino);
4045 break;
4046 case 'S':
4047 printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
4048 break;
4049 case 's':
4050 printf("%s", ctx->str ? ctx->str : "NULL");
4051 break;
4052 case 'X':
4053#ifdef EXT2_NO_64_TYPE
4054 printf("0x%x", ctx->num);
4055#else
4056 printf("0x%llx", ctx->num);
4057#endif
4058 break;
4059 default:
4060 no_context:
4061 printf("%%%c", ch);
4062 break;
4063 }
4064}
4065
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004066
4067static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004068 struct problem_context *pctx, int first)
4069{
4070 ext2_filsys fs = ctx->fs;
4071 const char * cp;
4072 int i;
4073
4074 e2fsck_clear_progbar(ctx);
4075 for (cp = msg; *cp; cp++) {
4076 if (cp[0] == '@') {
4077 cp++;
4078 expand_at_expression(ctx, *cp, pctx, &first);
4079 } else if (cp[0] == '%' && cp[1] == 'I') {
4080 cp += 2;
4081 expand_inode_expression(*cp, pctx);
4082 } else if (cp[0] == '%' && cp[1] == 'D') {
4083 cp += 2;
4084 expand_dirent_expression(*cp, pctx);
4085 } else if ((cp[0] == '%')) {
4086 cp++;
4087 expand_percent_expression(fs, *cp, pctx);
4088 } else {
4089 for (i=0; cp[i]; i++)
4090 if ((cp[i] == '@') || cp[i] == '%')
4091 break;
4092 printf("%.*s", i, cp);
4093 cp += i-1;
4094 }
4095 first = 0;
4096 }
4097}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004098
4099
4100/*
4101 * region.c --- code which manages allocations within a region.
4102 */
4103
4104struct region_el {
4105 region_addr_t start;
4106 region_addr_t end;
4107 struct region_el *next;
4108};
4109
4110struct region_struct {
4111 region_addr_t min;
4112 region_addr_t max;
4113 struct region_el *allocated;
4114};
4115
4116static region_t region_create(region_addr_t min, region_addr_t max)
4117{
4118 region_t region;
4119
4120 region = malloc(sizeof(struct region_struct));
4121 if (!region)
4122 return NULL;
4123 memset(region, 0, sizeof(struct region_struct));
4124 region->min = min;
4125 region->max = max;
4126 return region;
4127}
4128
4129static void region_free(region_t region)
4130{
4131 struct region_el *r, *next;
4132
4133 for (r = region->allocated; r; r = next) {
4134 next = r->next;
4135 free(r);
4136 }
4137 memset(region, 0, sizeof(struct region_struct));
4138 free(region);
4139}
4140
4141static int region_allocate(region_t region, region_addr_t start, int n)
4142{
4143 struct region_el *r, *new_region, *prev, *next;
4144 region_addr_t end;
4145
4146 end = start+n;
4147 if ((start < region->min) || (end > region->max))
4148 return -1;
4149 if (n == 0)
4150 return 1;
4151
4152 /*
4153 * Search through the linked list. If we find that it
4154 * conflicts witih something that's already allocated, return
4155 * 1; if we can find an existing region which we can grow, do
4156 * so. Otherwise, stop when we find the appropriate place
4157 * insert a new region element into the linked list.
4158 */
4159 for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
4160 if (((start >= r->start) && (start < r->end)) ||
4161 ((end > r->start) && (end <= r->end)) ||
4162 ((start <= r->start) && (end >= r->end)))
4163 return 1;
4164 if (end == r->start) {
4165 r->start = start;
4166 return 0;
4167 }
4168 if (start == r->end) {
4169 if ((next = r->next)) {
4170 if (end > next->start)
4171 return 1;
4172 if (end == next->start) {
4173 r->end = next->end;
4174 r->next = next->next;
4175 free(next);
4176 return 0;
4177 }
4178 }
4179 r->end = end;
4180 return 0;
4181 }
4182 if (start < r->start)
4183 break;
4184 }
4185 /*
4186 * Insert a new region element structure into the linked list
4187 */
4188 new_region = malloc(sizeof(struct region_el));
4189 if (!new_region)
4190 return -1;
4191 new_region->start = start;
4192 new_region->end = start + n;
4193 new_region->next = r;
4194 if (prev)
4195 prev->next = new_region;
4196 else
4197 region->allocated = new_region;
4198 return 0;
4199}
4200
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004201/*
4202 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
4203 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004204 * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
4205 * and applies the following tests to each inode:
4206 *
4207 * - The mode field of the inode must be legal.
4208 * - The size and block count fields of the inode are correct.
4209 * - A data block must not be used by another inode
4210 *
4211 * Pass 1 also gathers the collects the following information:
4212 *
4213 * - A bitmap of which inodes are in use. (inode_used_map)
4214 * - A bitmap of which inodes are directories. (inode_dir_map)
4215 * - A bitmap of which inodes are regular files. (inode_reg_map)
4216 * - A bitmap of which inodes have bad fields. (inode_bad_map)
4217 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
4218 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
4219 * - A bitmap of which blocks are in use. (block_found_map)
4220 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
4221 * - The data blocks of the directory inodes. (dir_map)
4222 *
4223 * Pass 1 is designed to stash away enough information so that the
4224 * other passes should not need to read in the inode information
4225 * during the normal course of a filesystem check. (Althogh if an
4226 * inconsistency is detected, other passes may need to read in an
4227 * inode to fix it.)
4228 *
4229 * Note that pass 1B will be invoked if there are any duplicate blocks
4230 * found.
4231 */
4232
4233
4234static int process_block(ext2_filsys fs, blk_t *blocknr,
4235 e2_blkcnt_t blockcnt, blk_t ref_blk,
4236 int ref_offset, void *priv_data);
4237static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
4238 e2_blkcnt_t blockcnt, blk_t ref_blk,
4239 int ref_offset, void *priv_data);
4240static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
4241 char *block_buf);
4242static void mark_table_blocks(e2fsck_t ctx);
4243static void alloc_bb_map(e2fsck_t ctx);
4244static void alloc_imagic_map(e2fsck_t ctx);
4245static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
4246static void handle_fs_bad_blocks(e2fsck_t ctx);
4247static void process_inodes(e2fsck_t ctx, char *block_buf);
4248static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
4249static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
4250 dgrp_t group, void * priv_data);
4251static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
4252 char *block_buf, int adjust_sign);
4253/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
4254
4255static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
4256 struct ext2_inode * inode, int bufsize,
4257 const char *proc);
4258
4259struct process_block_struct_1 {
4260 ext2_ino_t ino;
4261 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
4262 fragmented:1, compressed:1, bbcheck:1;
4263 blk_t num_blocks;
4264 blk_t max_blocks;
4265 e2_blkcnt_t last_block;
4266 int num_illegal_blocks;
4267 blk_t previous_block;
4268 struct ext2_inode *inode;
4269 struct problem_context *pctx;
4270 ext2fs_block_bitmap fs_meta_blocks;
4271 e2fsck_t ctx;
4272};
4273
4274struct process_inode_block {
4275 ext2_ino_t ino;
4276 struct ext2_inode inode;
4277};
4278
4279struct scan_callback_struct {
4280 e2fsck_t ctx;
4281 char *block_buf;
4282};
4283
4284/*
4285 * For the inodes to process list.
4286 */
4287static struct process_inode_block *inodes_to_process;
4288static int process_inode_count;
4289
4290static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
4291 EXT2_MIN_BLOCK_LOG_SIZE + 1];
4292
4293/*
4294 * Free all memory allocated by pass1 in preparation for restarting
4295 * things.
4296 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004297static void unwind_pass1(void)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004298{
4299 ext2fs_free_mem(&inodes_to_process);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004300}
4301
4302/*
4303 * Check to make sure a device inode is real. Returns 1 if the device
4304 * checks out, 0 if not.
4305 *
4306 * Note: this routine is now also used to check FIFO's and Sockets,
4307 * since they have the same requirement; the i_block fields should be
4308 * zero.
4309 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004310static int
4311e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004312{
4313 int i;
4314
4315 /*
4316 * If i_blocks is non-zero, or the index flag is set, then
4317 * this is a bogus device/fifo/socket
4318 */
4319 if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
4320 (inode->i_flags & EXT2_INDEX_FL))
4321 return 0;
4322
4323 /*
4324 * We should be able to do the test below all the time, but
4325 * because the kernel doesn't forcibly clear the device
4326 * inode's additional i_block fields, there are some rare
4327 * occasions when a legitimate device inode will have non-zero
4328 * additional i_block fields. So for now, we only complain
4329 * when the immutable flag is set, which should never happen
4330 * for devices. (And that's when the problem is caused, since
4331 * you can't set or clear immutable flags for devices.) Once
4332 * the kernel has been fixed we can change this...
4333 */
4334 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
4335 for (i=4; i < EXT2_N_BLOCKS; i++)
4336 if (inode->i_block[i])
4337 return 0;
4338 }
4339 return 1;
4340}
4341
4342/*
4343 * Check to make sure a symlink inode is real. Returns 1 if the symlink
4344 * checks out, 0 if not.
4345 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004346static int
4347e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, char *buf)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004348{
4349 unsigned int len;
4350 int i;
4351 blk_t blocks;
4352
4353 if ((inode->i_size_high || inode->i_size == 0) ||
4354 (inode->i_flags & EXT2_INDEX_FL))
4355 return 0;
4356
4357 blocks = ext2fs_inode_data_blocks(fs, inode);
4358 if (blocks) {
4359 if ((inode->i_size >= fs->blocksize) ||
4360 (blocks != fs->blocksize >> 9) ||
4361 (inode->i_block[0] < fs->super->s_first_data_block) ||
4362 (inode->i_block[0] >= fs->super->s_blocks_count))
4363 return 0;
4364
4365 for (i = 1; i < EXT2_N_BLOCKS; i++)
4366 if (inode->i_block[i])
4367 return 0;
4368
4369 if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
4370 return 0;
4371
4372 len = strnlen(buf, fs->blocksize);
4373 if (len == fs->blocksize)
4374 return 0;
4375 } else {
4376 if (inode->i_size >= sizeof(inode->i_block))
4377 return 0;
4378
4379 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
4380 if (len == sizeof(inode->i_block))
4381 return 0;
4382 }
4383 if (len != inode->i_size)
4384 return 0;
4385 return 1;
4386}
4387
4388/*
4389 * If the immutable (or append-only) flag is set on the inode, offer
4390 * to clear it.
4391 */
4392#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
4393static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
4394{
4395 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
4396 return;
4397
4398 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
4399 return;
4400
4401 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
4402 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4403}
4404
4405/*
4406 * If device, fifo or socket, check size is zero -- if not offer to
4407 * clear it
4408 */
4409static void check_size(e2fsck_t ctx, struct problem_context *pctx)
4410{
4411 struct ext2_inode *inode = pctx->inode;
4412
4413 if ((inode->i_size == 0) && (inode->i_size_high == 0))
4414 return;
4415
4416 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
4417 return;
4418
4419 inode->i_size = 0;
4420 inode->i_size_high = 0;
4421 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4422}
4423
4424static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
4425{
4426 struct ext2_super_block *sb = ctx->fs->super;
4427 struct ext2_inode_large *inode;
4428 struct ext2_ext_attr_entry *entry;
4429 char *start, *end;
4430 int storage_size, remain, offs;
4431 int problem = 0;
4432
4433 inode = (struct ext2_inode_large *) pctx->inode;
4434 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
4435 inode->i_extra_isize;
4436 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4437 inode->i_extra_isize + sizeof(__u32);
4438 end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
4439 entry = (struct ext2_ext_attr_entry *) start;
4440
4441 /* scan all entry's headers first */
4442
4443 /* take finish entry 0UL into account */
4444 remain = storage_size - sizeof(__u32);
4445 offs = end - start;
4446
4447 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
4448
4449 /* header eats this space */
4450 remain -= sizeof(struct ext2_ext_attr_entry);
4451
4452 /* is attribute name valid? */
4453 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
4454 pctx->num = entry->e_name_len;
4455 problem = PR_1_ATTR_NAME_LEN;
4456 goto fix;
4457 }
4458
4459 /* attribute len eats this space */
4460 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
4461
4462 /* check value size */
4463 if (entry->e_value_size == 0 || entry->e_value_size > remain) {
4464 pctx->num = entry->e_value_size;
4465 problem = PR_1_ATTR_VALUE_SIZE;
4466 goto fix;
4467 }
4468
4469 /* check value placement */
4470 if (entry->e_value_offs +
4471 EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
4472 printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
4473 pctx->num = entry->e_value_offs;
4474 problem = PR_1_ATTR_VALUE_OFFSET;
4475 goto fix;
4476 }
4477
4478 /* e_value_block must be 0 in inode's ea */
4479 if (entry->e_value_block != 0) {
4480 pctx->num = entry->e_value_block;
4481 problem = PR_1_ATTR_VALUE_BLOCK;
4482 goto fix;
4483 }
4484
4485 /* e_hash must be 0 in inode's ea */
4486 if (entry->e_hash != 0) {
4487 pctx->num = entry->e_hash;
4488 problem = PR_1_ATTR_HASH;
4489 goto fix;
4490 }
4491
4492 remain -= entry->e_value_size;
4493 offs -= EXT2_XATTR_SIZE(entry->e_value_size);
4494
4495 entry = EXT2_EXT_ATTR_NEXT(entry);
4496 }
4497fix:
4498 /*
4499 * it seems like a corruption. it's very unlikely we could repair
4500 * EA(s) in automatic fashion -bzzz
4501 */
4502#if 0
4503 problem = PR_1_ATTR_HASH;
4504#endif
4505 if (problem == 0 || !fix_problem(ctx, problem, pctx))
4506 return;
4507
4508 /* simple remove all possible EA(s) */
4509 *((__u32 *)start) = 0UL;
4510 e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
4511 EXT2_INODE_SIZE(sb), "pass1");
4512}
4513
4514static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
4515{
4516 struct ext2_super_block *sb = ctx->fs->super;
4517 struct ext2_inode_large *inode;
4518 __u32 *eamagic;
4519 int min, max;
4520
4521 inode = (struct ext2_inode_large *) pctx->inode;
4522 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
4523 /* this isn't large inode. so, nothing to check */
4524 return;
4525 }
4526
4527#if 0
4528 printf("inode #%u, i_extra_size %d\n", pctx->ino,
4529 inode->i_extra_isize);
4530#endif
4531 /* i_extra_isize must cover i_extra_isize + i_pad1 at least */
4532 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
4533 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
4534 /*
4535 * For now we will allow i_extra_isize to be 0, but really
4536 * implementations should never allow i_extra_isize to be 0
4537 */
4538 if (inode->i_extra_isize &&
4539 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
4540 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
4541 return;
4542 inode->i_extra_isize = min;
4543 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
4544 EXT2_INODE_SIZE(sb), "pass1");
4545 return;
4546 }
4547
4548 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4549 inode->i_extra_isize);
4550 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
4551 /* it seems inode has an extended attribute(s) in body */
4552 check_ea_in_inode(ctx, pctx);
4553 }
4554}
4555
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004556static void e2fsck_pass1(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004557{
4558 int i;
4559 __u64 max_sizes;
4560 ext2_filsys fs = ctx->fs;
4561 ext2_ino_t ino;
4562 struct ext2_inode *inode;
4563 ext2_inode_scan scan;
4564 char *block_buf;
4565#ifdef RESOURCE_TRACK
4566 struct resource_track rtrack;
4567#endif
4568 unsigned char frag, fsize;
4569 struct problem_context pctx;
4570 struct scan_callback_struct scan_struct;
4571 struct ext2_super_block *sb = ctx->fs->super;
4572 int imagic_fs;
4573 int busted_fs_time = 0;
4574 int inode_size;
4575
4576#ifdef RESOURCE_TRACK
4577 init_resource_track(&rtrack);
4578#endif
4579 clear_problem_context(&pctx);
4580
4581 if (!(ctx->options & E2F_OPT_PREEN))
4582 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
4583
4584 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
4585 !(ctx->options & E2F_OPT_NO)) {
4586 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
4587 ctx->dirs_to_hash = 0;
4588 }
4589
4590#ifdef MTRACE
4591 mtrace_print("Pass 1");
4592#endif
4593
4594#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
4595
4596 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
4597 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
4598 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
4599 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
4600 max_sizes = (max_sizes * (1UL << i)) - 1;
4601 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
4602 }
4603#undef EXT2_BPP
4604
4605 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
4606
4607 /*
4608 * Allocate bitmaps structures
4609 */
4610 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
4611 &ctx->inode_used_map);
4612 if (pctx.errcode) {
4613 pctx.num = 1;
4614 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4615 ctx->flags |= E2F_FLAG_ABORT;
4616 return;
4617 }
4618 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4619 _("directory inode map"), &ctx->inode_dir_map);
4620 if (pctx.errcode) {
4621 pctx.num = 2;
4622 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4623 ctx->flags |= E2F_FLAG_ABORT;
4624 return;
4625 }
4626 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4627 _("regular file inode map"), &ctx->inode_reg_map);
4628 if (pctx.errcode) {
4629 pctx.num = 6;
4630 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4631 ctx->flags |= E2F_FLAG_ABORT;
4632 return;
4633 }
4634 pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
4635 &ctx->block_found_map);
4636 if (pctx.errcode) {
4637 pctx.num = 1;
4638 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4639 ctx->flags |= E2F_FLAG_ABORT;
4640 return;
4641 }
4642 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
4643 &ctx->inode_link_info);
4644 if (pctx.errcode) {
4645 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
4646 ctx->flags |= E2F_FLAG_ABORT;
4647 return;
4648 }
4649 inode_size = EXT2_INODE_SIZE(fs->super);
4650 inode = (struct ext2_inode *)
4651 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
4652
4653 inodes_to_process = (struct process_inode_block *)
4654 e2fsck_allocate_memory(ctx,
4655 (ctx->process_inode_size *
4656 sizeof(struct process_inode_block)),
4657 "array of inodes to process");
4658 process_inode_count = 0;
4659
4660 pctx.errcode = ext2fs_init_dblist(fs, 0);
4661 if (pctx.errcode) {
4662 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
4663 ctx->flags |= E2F_FLAG_ABORT;
4664 return;
4665 }
4666
4667 /*
4668 * If the last orphan field is set, clear it, since the pass1
4669 * processing will automatically find and clear the orphans.
4670 * In the future, we may want to try using the last_orphan
4671 * linked list ourselves, but for now, we clear it so that the
4672 * ext3 mount code won't get confused.
4673 */
4674 if (!(ctx->options & E2F_OPT_READONLY)) {
4675 if (fs->super->s_last_orphan) {
4676 fs->super->s_last_orphan = 0;
4677 ext2fs_mark_super_dirty(fs);
4678 }
4679 }
4680
4681 mark_table_blocks(ctx);
4682 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
4683 "block interate buffer");
4684 e2fsck_use_inode_shortcuts(ctx, 1);
4685 ehandler_operation(_("doing inode scan"));
4686 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
4687 &scan);
4688 if (pctx.errcode) {
4689 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4690 ctx->flags |= E2F_FLAG_ABORT;
4691 return;
4692 }
4693 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
4694 ctx->stashed_inode = inode;
4695 scan_struct.ctx = ctx;
4696 scan_struct.block_buf = block_buf;
4697 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
4698 if (ctx->progress)
4699 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
4700 return;
4701 if (fs->super->s_wtime < fs->super->s_inodes_count)
4702 busted_fs_time = 1;
4703
4704 while (1) {
4705 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
4706 inode, inode_size);
4707 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4708 return;
4709 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
4710 if (!ctx->inode_bb_map)
4711 alloc_bb_map(ctx);
4712 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
4713 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4714 continue;
4715 }
4716 if (pctx.errcode) {
4717 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4718 ctx->flags |= E2F_FLAG_ABORT;
4719 return;
4720 }
4721 if (!ino)
4722 break;
4723 pctx.ino = ino;
4724 pctx.inode = inode;
4725 ctx->stashed_ino = ino;
4726 if (inode->i_links_count) {
4727 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
4728 ino, inode->i_links_count);
4729 if (pctx.errcode) {
4730 pctx.num = inode->i_links_count;
4731 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
4732 ctx->flags |= E2F_FLAG_ABORT;
4733 return;
4734 }
4735 }
4736 if (ino == EXT2_BAD_INO) {
4737 struct process_block_struct_1 pb;
4738
4739 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
4740 &pb.fs_meta_blocks);
4741 if (pctx.errcode) {
4742 pctx.num = 4;
4743 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4744 ctx->flags |= E2F_FLAG_ABORT;
4745 return;
4746 }
4747 pb.ino = EXT2_BAD_INO;
4748 pb.num_blocks = pb.last_block = 0;
4749 pb.num_illegal_blocks = 0;
4750 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
4751 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
4752 pb.inode = inode;
4753 pb.pctx = &pctx;
4754 pb.ctx = ctx;
4755 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
4756 block_buf, process_bad_block, &pb);
4757 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
4758 if (pctx.errcode) {
4759 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
4760 ctx->flags |= E2F_FLAG_ABORT;
4761 return;
4762 }
4763 if (pb.bbcheck)
4764 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
4765 ctx->flags |= E2F_FLAG_ABORT;
4766 return;
4767 }
4768 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4769 clear_problem_context(&pctx);
4770 continue;
4771 } else if (ino == EXT2_ROOT_INO) {
4772 /*
4773 * Make sure the root inode is a directory; if
4774 * not, offer to clear it. It will be
4775 * regnerated in pass #3.
4776 */
4777 if (!LINUX_S_ISDIR(inode->i_mode)) {
4778 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
4779 inode->i_dtime = time(0);
4780 inode->i_links_count = 0;
4781 ext2fs_icount_store(ctx->inode_link_info,
4782 ino, 0);
4783 e2fsck_write_inode(ctx, ino, inode,
4784 "pass1");
4785 }
4786
4787 }
4788 /*
4789 * If dtime is set, offer to clear it. mke2fs
4790 * version 0.2b created filesystems with the
4791 * dtime field set for the root and lost+found
4792 * directories. We won't worry about
4793 * /lost+found, since that can be regenerated
4794 * easily. But we will fix the root directory
4795 * as a special case.
4796 */
4797 if (inode->i_dtime && inode->i_links_count) {
4798 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
4799 inode->i_dtime = 0;
4800 e2fsck_write_inode(ctx, ino, inode,
4801 "pass1");
4802 }
4803 }
4804 } else if (ino == EXT2_JOURNAL_INO) {
4805 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4806 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
4807 if (!LINUX_S_ISREG(inode->i_mode) &&
4808 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
4809 &pctx)) {
4810 inode->i_mode = LINUX_S_IFREG;
4811 e2fsck_write_inode(ctx, ino, inode,
4812 "pass1");
4813 }
4814 check_blocks(ctx, &pctx, block_buf);
4815 continue;
4816 }
4817 if ((inode->i_links_count || inode->i_blocks ||
4818 inode->i_blocks || inode->i_block[0]) &&
4819 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
4820 &pctx)) {
4821 memset(inode, 0, inode_size);
4822 ext2fs_icount_store(ctx->inode_link_info,
4823 ino, 0);
4824 e2fsck_write_inode_full(ctx, ino, inode,
4825 inode_size, "pass1");
4826 }
4827 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
4828 int problem = 0;
4829
4830 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4831 if (ino == EXT2_BOOT_LOADER_INO) {
4832 if (LINUX_S_ISDIR(inode->i_mode))
4833 problem = PR_1_RESERVED_BAD_MODE;
4834 } else if (ino == EXT2_RESIZE_INO) {
4835 if (inode->i_mode &&
4836 !LINUX_S_ISREG(inode->i_mode))
4837 problem = PR_1_RESERVED_BAD_MODE;
4838 } else {
4839 if (inode->i_mode != 0)
4840 problem = PR_1_RESERVED_BAD_MODE;
4841 }
4842 if (problem) {
4843 if (fix_problem(ctx, problem, &pctx)) {
4844 inode->i_mode = 0;
4845 e2fsck_write_inode(ctx, ino, inode,
4846 "pass1");
4847 }
4848 }
4849 check_blocks(ctx, &pctx, block_buf);
4850 continue;
4851 }
4852 /*
4853 * Check for inodes who might have been part of the
4854 * orphaned list linked list. They should have gotten
4855 * dealt with by now, unless the list had somehow been
4856 * corrupted.
4857 *
4858 * FIXME: In the future, inodes which are still in use
4859 * (and which are therefore) pending truncation should
4860 * be handled specially. Right now we just clear the
4861 * dtime field, and the normal e2fsck handling of
4862 * inodes where i_size and the inode blocks are
4863 * inconsistent is to fix i_size, instead of releasing
4864 * the extra blocks. This won't catch the inodes that
4865 * was at the end of the orphan list, but it's better
4866 * than nothing. The right answer is that there
4867 * shouldn't be any bugs in the orphan list handling. :-)
4868 */
4869 if (inode->i_dtime && !busted_fs_time &&
4870 inode->i_dtime < ctx->fs->super->s_inodes_count) {
4871 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
4872 inode->i_dtime = inode->i_links_count ?
4873 0 : time(0);
4874 e2fsck_write_inode(ctx, ino, inode,
4875 "pass1");
4876 }
4877 }
4878
4879 /*
4880 * This code assumes that deleted inodes have
4881 * i_links_count set to 0.
4882 */
4883 if (!inode->i_links_count) {
4884 if (!inode->i_dtime && inode->i_mode) {
4885 if (fix_problem(ctx,
4886 PR_1_ZERO_DTIME, &pctx)) {
4887 inode->i_dtime = time(0);
4888 e2fsck_write_inode(ctx, ino, inode,
4889 "pass1");
4890 }
4891 }
4892 continue;
4893 }
4894 /*
4895 * n.b. 0.3c ext2fs code didn't clear i_links_count for
4896 * deleted files. Oops.
4897 *
4898 * Since all new ext2 implementations get this right,
4899 * we now assume that the case of non-zero
4900 * i_links_count and non-zero dtime means that we
4901 * should keep the file, not delete it.
4902 *
4903 */
4904 if (inode->i_dtime) {
4905 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
4906 inode->i_dtime = 0;
4907 e2fsck_write_inode(ctx, ino, inode, "pass1");
4908 }
4909 }
4910
4911 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4912 switch (fs->super->s_creator_os) {
4913 case EXT2_OS_LINUX:
4914 frag = inode->osd2.linux2.l_i_frag;
4915 fsize = inode->osd2.linux2.l_i_fsize;
4916 break;
4917 case EXT2_OS_HURD:
4918 frag = inode->osd2.hurd2.h_i_frag;
4919 fsize = inode->osd2.hurd2.h_i_fsize;
4920 break;
4921 case EXT2_OS_MASIX:
4922 frag = inode->osd2.masix2.m_i_frag;
4923 fsize = inode->osd2.masix2.m_i_fsize;
4924 break;
4925 default:
4926 frag = fsize = 0;
4927 }
4928
4929 if (inode->i_faddr || frag || fsize ||
4930 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
4931 mark_inode_bad(ctx, ino);
4932 if (inode->i_flags & EXT2_IMAGIC_FL) {
4933 if (imagic_fs) {
4934 if (!ctx->inode_imagic_map)
4935 alloc_imagic_map(ctx);
4936 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
4937 ino);
4938 } else {
4939 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
4940 inode->i_flags &= ~EXT2_IMAGIC_FL;
4941 e2fsck_write_inode(ctx, ino,
4942 inode, "pass1");
4943 }
4944 }
4945 }
4946
4947 check_inode_extra_space(ctx, &pctx);
4948
4949 if (LINUX_S_ISDIR(inode->i_mode)) {
4950 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
4951 e2fsck_add_dir_info(ctx, ino, 0);
4952 ctx->fs_directory_count++;
4953 } else if (LINUX_S_ISREG (inode->i_mode)) {
4954 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
4955 ctx->fs_regular_count++;
4956 } else if (LINUX_S_ISCHR (inode->i_mode) &&
4957 e2fsck_pass1_check_device_inode(fs, inode)) {
4958 check_immutable(ctx, &pctx);
4959 check_size(ctx, &pctx);
4960 ctx->fs_chardev_count++;
4961 } else if (LINUX_S_ISBLK (inode->i_mode) &&
4962 e2fsck_pass1_check_device_inode(fs, inode)) {
4963 check_immutable(ctx, &pctx);
4964 check_size(ctx, &pctx);
4965 ctx->fs_blockdev_count++;
4966 } else if (LINUX_S_ISLNK (inode->i_mode) &&
4967 e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
4968 check_immutable(ctx, &pctx);
4969 ctx->fs_symlinks_count++;
4970 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
4971 ctx->fs_fast_symlinks_count++;
4972 check_blocks(ctx, &pctx, block_buf);
4973 continue;
4974 }
4975 }
4976 else if (LINUX_S_ISFIFO (inode->i_mode) &&
4977 e2fsck_pass1_check_device_inode(fs, inode)) {
4978 check_immutable(ctx, &pctx);
4979 check_size(ctx, &pctx);
4980 ctx->fs_fifo_count++;
4981 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
4982 e2fsck_pass1_check_device_inode(fs, inode)) {
4983 check_immutable(ctx, &pctx);
4984 check_size(ctx, &pctx);
4985 ctx->fs_sockets_count++;
4986 } else
4987 mark_inode_bad(ctx, ino);
4988 if (inode->i_block[EXT2_IND_BLOCK])
4989 ctx->fs_ind_count++;
4990 if (inode->i_block[EXT2_DIND_BLOCK])
4991 ctx->fs_dind_count++;
4992 if (inode->i_block[EXT2_TIND_BLOCK])
4993 ctx->fs_tind_count++;
4994 if (inode->i_block[EXT2_IND_BLOCK] ||
4995 inode->i_block[EXT2_DIND_BLOCK] ||
4996 inode->i_block[EXT2_TIND_BLOCK] ||
4997 inode->i_file_acl) {
4998 inodes_to_process[process_inode_count].ino = ino;
4999 inodes_to_process[process_inode_count].inode = *inode;
5000 process_inode_count++;
5001 } else
5002 check_blocks(ctx, &pctx, block_buf);
5003
5004 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5005 return;
5006
5007 if (process_inode_count >= ctx->process_inode_size) {
5008 process_inodes(ctx, block_buf);
5009
5010 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5011 return;
5012 }
5013 }
5014 process_inodes(ctx, block_buf);
5015 ext2fs_close_inode_scan(scan);
5016 ehandler_operation(0);
5017
5018 /*
5019 * If any extended attribute blocks' reference counts need to
5020 * be adjusted, either up (ctx->refcount_extra), or down
5021 * (ctx->refcount), then fix them.
5022 */
5023 if (ctx->refcount) {
5024 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
5025 ea_refcount_free(ctx->refcount);
5026 ctx->refcount = 0;
5027 }
5028 if (ctx->refcount_extra) {
5029 adjust_extattr_refcount(ctx, ctx->refcount_extra,
5030 block_buf, +1);
5031 ea_refcount_free(ctx->refcount_extra);
5032 ctx->refcount_extra = 0;
5033 }
5034
5035 if (ctx->invalid_bitmaps)
5036 handle_fs_bad_blocks(ctx);
5037
5038 /* We don't need the block_ea_map any more */
Rob Landleye7c43b62006-03-01 16:39:45 +00005039 ext2fs_free_block_bitmap(ctx->block_ea_map);
5040 ctx->block_ea_map = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005041
5042 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
5043 ext2fs_block_bitmap save_bmap;
5044
5045 save_bmap = fs->block_map;
5046 fs->block_map = ctx->block_found_map;
5047 clear_problem_context(&pctx);
5048 pctx.errcode = ext2fs_create_resize_inode(fs);
5049 if (pctx.errcode) {
5050 fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
5051 /* Should never get here */
5052 ctx->flags |= E2F_FLAG_ABORT;
5053 return;
5054 }
5055 fs->block_map = save_bmap;
5056 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
5057 }
5058
5059 if (ctx->flags & E2F_FLAG_RESTART) {
5060 /*
5061 * Only the master copy of the superblock and block
5062 * group descriptors are going to be written during a
5063 * restart, so set the superblock to be used to be the
5064 * master superblock.
5065 */
5066 ctx->use_superblock = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00005067 unwind_pass1();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005068 goto endit;
5069 }
5070
5071 if (ctx->block_dup_map) {
5072 if (ctx->options & E2F_OPT_PREEN) {
5073 clear_problem_context(&pctx);
5074 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
5075 }
5076 e2fsck_pass1_dupblocks(ctx, block_buf);
5077 }
5078 ext2fs_free_mem(&inodes_to_process);
5079endit:
5080 e2fsck_use_inode_shortcuts(ctx, 0);
5081
5082 ext2fs_free_mem(&block_buf);
5083 ext2fs_free_mem(&inode);
5084
5085#ifdef RESOURCE_TRACK
5086 if (ctx->options & E2F_OPT_TIME2) {
5087 e2fsck_clear_progbar(ctx);
5088 print_resource_track(_("Pass 1"), &rtrack);
5089 }
5090#endif
5091}
5092
5093/*
5094 * When the inode_scan routines call this callback at the end of the
5095 * glock group, call process_inodes.
5096 */
5097static errcode_t scan_callback(ext2_filsys fs,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005098 ext2_inode_scan scan FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005099 dgrp_t group, void * priv_data)
5100{
5101 struct scan_callback_struct *scan_struct;
5102 e2fsck_t ctx;
5103
5104 scan_struct = (struct scan_callback_struct *) priv_data;
5105 ctx = scan_struct->ctx;
5106
5107 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
5108
5109 if (ctx->progress)
5110 if ((ctx->progress)(ctx, 1, group+1,
5111 ctx->fs->group_desc_count))
5112 return EXT2_ET_CANCEL_REQUESTED;
5113
5114 return 0;
5115}
5116
5117/*
5118 * Process the inodes in the "inodes to process" list.
5119 */
5120static void process_inodes(e2fsck_t ctx, char *block_buf)
5121{
5122 int i;
5123 struct ext2_inode *old_stashed_inode;
5124 ext2_ino_t old_stashed_ino;
5125 const char *old_operation;
5126 char buf[80];
5127 struct problem_context pctx;
5128
5129#if 0
5130 printf("begin process_inodes: ");
5131#endif
5132 if (process_inode_count == 0)
5133 return;
5134 old_operation = ehandler_operation(0);
5135 old_stashed_inode = ctx->stashed_inode;
5136 old_stashed_ino = ctx->stashed_ino;
5137 qsort(inodes_to_process, process_inode_count,
5138 sizeof(struct process_inode_block), process_inode_cmp);
5139 clear_problem_context(&pctx);
5140 for (i=0; i < process_inode_count; i++) {
5141 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
5142 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
5143
5144#if 0
5145 printf("%u ", pctx.ino);
5146#endif
5147 sprintf(buf, _("reading indirect blocks of inode %u"),
5148 pctx.ino);
5149 ehandler_operation(buf);
5150 check_blocks(ctx, &pctx, block_buf);
5151 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5152 break;
5153 }
5154 ctx->stashed_inode = old_stashed_inode;
5155 ctx->stashed_ino = old_stashed_ino;
5156 process_inode_count = 0;
5157#if 0
5158 printf("end process inodes\n");
5159#endif
5160 ehandler_operation(old_operation);
5161}
5162
5163static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
5164{
5165 const struct process_inode_block *ib_a =
5166 (const struct process_inode_block *) a;
5167 const struct process_inode_block *ib_b =
5168 (const struct process_inode_block *) b;
5169 int ret;
5170
5171 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
5172 ib_b->inode.i_block[EXT2_IND_BLOCK]);
5173 if (ret == 0)
5174 ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
5175 return ret;
5176}
5177
5178/*
5179 * Mark an inode as being bad in some what
5180 */
5181static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
5182{
5183 struct problem_context pctx;
5184
5185 if (!ctx->inode_bad_map) {
5186 clear_problem_context(&pctx);
5187
5188 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5189 _("bad inode map"), &ctx->inode_bad_map);
5190 if (pctx.errcode) {
5191 pctx.num = 3;
5192 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5193 /* Should never get here */
5194 ctx->flags |= E2F_FLAG_ABORT;
5195 return;
5196 }
5197 }
5198 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
5199}
5200
5201
5202/*
5203 * This procedure will allocate the inode "bb" (badblock) map table
5204 */
5205static void alloc_bb_map(e2fsck_t ctx)
5206{
5207 struct problem_context pctx;
5208
5209 clear_problem_context(&pctx);
5210 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5211 _("inode in bad block map"),
5212 &ctx->inode_bb_map);
5213 if (pctx.errcode) {
5214 pctx.num = 4;
5215 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5216 /* Should never get here */
5217 ctx->flags |= E2F_FLAG_ABORT;
5218 return;
5219 }
5220}
5221
5222/*
5223 * This procedure will allocate the inode imagic table
5224 */
5225static void alloc_imagic_map(e2fsck_t ctx)
5226{
5227 struct problem_context pctx;
5228
5229 clear_problem_context(&pctx);
5230 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5231 _("imagic inode map"),
5232 &ctx->inode_imagic_map);
5233 if (pctx.errcode) {
5234 pctx.num = 5;
5235 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5236 /* Should never get here */
5237 ctx->flags |= E2F_FLAG_ABORT;
5238 return;
5239 }
5240}
5241
5242/*
5243 * Marks a block as in use, setting the dup_map if it's been set
5244 * already. Called by process_block and process_bad_block.
5245 *
5246 * WARNING: Assumes checks have already been done to make sure block
5247 * is valid. This is true in both process_block and process_bad_block.
5248 */
5249static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
5250{
5251 struct problem_context pctx;
5252
5253 clear_problem_context(&pctx);
5254
5255 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
5256 if (!ctx->block_dup_map) {
5257 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
5258 _("multiply claimed block map"),
5259 &ctx->block_dup_map);
5260 if (pctx.errcode) {
5261 pctx.num = 3;
5262 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
5263 &pctx);
5264 /* Should never get here */
5265 ctx->flags |= E2F_FLAG_ABORT;
5266 return;
5267 }
5268 }
5269 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
5270 } else {
5271 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
5272 }
5273}
5274
5275/*
5276 * Adjust the extended attribute block's reference counts at the end
5277 * of pass 1, either by subtracting out references for EA blocks that
5278 * are still referenced in ctx->refcount, or by adding references for
5279 * EA blocks that had extra references as accounted for in
5280 * ctx->refcount_extra.
5281 */
5282static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
5283 char *block_buf, int adjust_sign)
5284{
5285 struct ext2_ext_attr_header *header;
5286 struct problem_context pctx;
5287 ext2_filsys fs = ctx->fs;
5288 blk_t blk;
5289 __u32 should_be;
5290 int count;
5291
5292 clear_problem_context(&pctx);
5293
5294 ea_refcount_intr_begin(refcount);
5295 while (1) {
5296 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
5297 break;
5298 pctx.blk = blk;
5299 pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5300 if (pctx.errcode) {
5301 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
5302 return;
5303 }
5304 header = (struct ext2_ext_attr_header *) block_buf;
5305 pctx.blkcount = header->h_refcount;
5306 should_be = header->h_refcount + adjust_sign * count;
5307 pctx.num = should_be;
5308 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
5309 header->h_refcount = should_be;
5310 pctx.errcode = ext2fs_write_ext_attr(fs, blk,
5311 block_buf);
5312 if (pctx.errcode) {
5313 fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
5314 continue;
5315 }
5316 }
5317 }
5318}
5319
5320/*
5321 * Handle processing the extended attribute blocks
5322 */
5323static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
5324 char *block_buf)
5325{
5326 ext2_filsys fs = ctx->fs;
5327 ext2_ino_t ino = pctx->ino;
5328 struct ext2_inode *inode = pctx->inode;
5329 blk_t blk;
5330 char * end;
5331 struct ext2_ext_attr_header *header;
5332 struct ext2_ext_attr_entry *entry;
5333 int count;
5334 region_t region;
5335
5336 blk = inode->i_file_acl;
5337 if (blk == 0)
5338 return 0;
5339
5340 /*
5341 * If the Extended attribute flag isn't set, then a non-zero
5342 * file acl means that the inode is corrupted.
5343 *
5344 * Or if the extended attribute block is an invalid block,
5345 * then the inode is also corrupted.
5346 */
5347 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
5348 (blk < fs->super->s_first_data_block) ||
5349 (blk >= fs->super->s_blocks_count)) {
5350 mark_inode_bad(ctx, ino);
5351 return 0;
5352 }
5353
5354 /* If ea bitmap hasn't been allocated, create it */
5355 if (!ctx->block_ea_map) {
5356 pctx->errcode = ext2fs_allocate_block_bitmap(fs,
5357 _("ext attr block map"),
5358 &ctx->block_ea_map);
5359 if (pctx->errcode) {
5360 pctx->num = 2;
5361 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
5362 ctx->flags |= E2F_FLAG_ABORT;
5363 return 0;
5364 }
5365 }
5366
5367 /* Create the EA refcount structure if necessary */
5368 if (!ctx->refcount) {
5369 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
5370 if (pctx->errcode) {
5371 pctx->num = 1;
5372 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5373 ctx->flags |= E2F_FLAG_ABORT;
5374 return 0;
5375 }
5376 }
5377
5378#if 0
5379 /* Debugging text */
5380 printf("Inode %u has EA block %u\n", ino, blk);
5381#endif
5382
5383 /* Have we seen this EA block before? */
5384 if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
5385 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
5386 return 1;
5387 /* Ooops, this EA was referenced more than it stated */
5388 if (!ctx->refcount_extra) {
5389 pctx->errcode = ea_refcount_create(0,
5390 &ctx->refcount_extra);
5391 if (pctx->errcode) {
5392 pctx->num = 2;
5393 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5394 ctx->flags |= E2F_FLAG_ABORT;
5395 return 0;
5396 }
5397 }
5398 ea_refcount_increment(ctx->refcount_extra, blk, 0);
5399 return 1;
5400 }
5401
5402 /*
5403 * OK, we haven't seen this EA block yet. So we need to
5404 * validate it
5405 */
5406 pctx->blk = blk;
5407 pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5408 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
5409 goto clear_extattr;
5410 header = (struct ext2_ext_attr_header *) block_buf;
5411 pctx->blk = inode->i_file_acl;
5412 if (((ctx->ext_attr_ver == 1) &&
5413 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
5414 ((ctx->ext_attr_ver == 2) &&
5415 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
5416 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
5417 goto clear_extattr;
5418 }
5419
5420 if (header->h_blocks != 1) {
5421 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
5422 goto clear_extattr;
5423 }
5424
5425 region = region_create(0, fs->blocksize);
5426 if (!region) {
5427 fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
5428 ctx->flags |= E2F_FLAG_ABORT;
5429 return 0;
5430 }
5431 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
5432 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5433 goto clear_extattr;
5434 }
5435
5436 entry = (struct ext2_ext_attr_entry *)(header+1);
5437 end = block_buf + fs->blocksize;
5438 while ((char *)entry < end && *(__u32 *)entry) {
5439 if (region_allocate(region, (char *)entry - (char *)header,
5440 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
5441 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5442 goto clear_extattr;
5443 }
5444 if ((ctx->ext_attr_ver == 1 &&
5445 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
5446 (ctx->ext_attr_ver == 2 &&
5447 entry->e_name_index == 0)) {
5448 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
5449 goto clear_extattr;
5450 }
5451 if (entry->e_value_block != 0) {
5452 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
5453 goto clear_extattr;
5454 }
5455 if (entry->e_value_size &&
5456 region_allocate(region, entry->e_value_offs,
5457 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
5458 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5459 goto clear_extattr;
5460 }
5461 entry = EXT2_EXT_ATTR_NEXT(entry);
5462 }
5463 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
5464 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5465 goto clear_extattr;
5466 }
5467 region_free(region);
5468
5469 count = header->h_refcount - 1;
5470 if (count)
5471 ea_refcount_store(ctx->refcount, blk, count);
5472 mark_block_used(ctx, blk);
5473 ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
5474
5475 return 1;
5476
5477clear_extattr:
5478 inode->i_file_acl = 0;
5479 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
5480 return 0;
5481}
5482
5483/* Returns 1 if bad htree, 0 if OK */
5484static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005485 ext2_ino_t ino FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005486 struct ext2_inode *inode,
5487 char *block_buf)
5488{
5489 struct ext2_dx_root_info *root;
5490 ext2_filsys fs = ctx->fs;
5491 errcode_t retval;
5492 blk_t blk;
5493
5494 if ((!LINUX_S_ISDIR(inode->i_mode) &&
5495 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
5496 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
5497 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
5498 return 1;
5499
5500 blk = inode->i_block[0];
5501 if (((blk == 0) ||
5502 (blk < fs->super->s_first_data_block) ||
5503 (blk >= fs->super->s_blocks_count)) &&
5504 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5505 return 1;
5506
5507 retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
5508 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5509 return 1;
5510
5511 /* XXX should check that beginning matches a directory */
5512 root = (struct ext2_dx_root_info *) (block_buf + 24);
5513
5514 if ((root->reserved_zero || root->info_length < 8) &&
5515 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5516 return 1;
5517
5518 pctx->num = root->hash_version;
5519 if ((root->hash_version != EXT2_HASH_LEGACY) &&
5520 (root->hash_version != EXT2_HASH_HALF_MD4) &&
5521 (root->hash_version != EXT2_HASH_TEA) &&
5522 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
5523 return 1;
5524
5525 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
5526 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
5527 return 1;
5528
5529 pctx->num = root->indirect_levels;
5530 if ((root->indirect_levels > 1) &&
5531 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
5532 return 1;
5533
5534 return 0;
5535}
5536
5537/*
5538 * This subroutine is called on each inode to account for all of the
5539 * blocks used by that inode.
5540 */
5541static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
5542 char *block_buf)
5543{
5544 ext2_filsys fs = ctx->fs;
5545 struct process_block_struct_1 pb;
5546 ext2_ino_t ino = pctx->ino;
5547 struct ext2_inode *inode = pctx->inode;
5548 int bad_size = 0;
5549 int dirty_inode = 0;
5550 __u64 size;
5551
5552 pb.ino = ino;
5553 pb.num_blocks = 0;
5554 pb.last_block = -1;
5555 pb.num_illegal_blocks = 0;
5556 pb.suppress = 0; pb.clear = 0;
5557 pb.fragmented = 0;
5558 pb.compressed = 0;
5559 pb.previous_block = 0;
5560 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
5561 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
5562 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
5563 pb.inode = inode;
5564 pb.pctx = pctx;
5565 pb.ctx = ctx;
5566 pctx->ino = ino;
5567 pctx->errcode = 0;
5568
5569 if (inode->i_flags & EXT2_COMPRBLK_FL) {
5570 if (fs->super->s_feature_incompat &
5571 EXT2_FEATURE_INCOMPAT_COMPRESSION)
5572 pb.compressed = 1;
5573 else {
5574 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
5575 inode->i_flags &= ~EXT2_COMPRBLK_FL;
5576 dirty_inode++;
5577 }
5578 }
5579 }
5580
5581 if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
5582 pb.num_blocks++;
5583
5584 if (ext2fs_inode_has_valid_blocks(inode))
5585 pctx->errcode = ext2fs_block_iterate2(fs, ino,
5586 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
5587 block_buf, process_block, &pb);
5588 end_problem_latch(ctx, PR_LATCH_BLOCK);
5589 end_problem_latch(ctx, PR_LATCH_TOOBIG);
5590 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5591 goto out;
5592 if (pctx->errcode)
5593 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
5594
5595 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
5596 ctx->fs_fragmented++;
5597
5598 if (pb.clear) {
5599 inode->i_links_count = 0;
5600 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5601 inode->i_dtime = time(0);
5602 dirty_inode++;
5603 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5604 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5605 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5606 /*
5607 * The inode was probably partially accounted for
5608 * before processing was aborted, so we need to
5609 * restart the pass 1 scan.
5610 */
5611 ctx->flags |= E2F_FLAG_RESTART;
5612 goto out;
5613 }
5614
5615 if (inode->i_flags & EXT2_INDEX_FL) {
5616 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
5617 inode->i_flags &= ~EXT2_INDEX_FL;
5618 dirty_inode++;
5619 } else {
5620#ifdef ENABLE_HTREE
5621 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
5622#endif
5623 }
5624 }
5625 if (ctx->dirs_to_hash && pb.is_dir &&
5626 !(inode->i_flags & EXT2_INDEX_FL) &&
5627 ((inode->i_size / fs->blocksize) >= 3))
5628 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
5629
5630 if (!pb.num_blocks && pb.is_dir) {
5631 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
5632 inode->i_links_count = 0;
5633 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5634 inode->i_dtime = time(0);
5635 dirty_inode++;
5636 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5637 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5638 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5639 ctx->fs_directory_count--;
5640 goto out;
5641 }
5642 }
5643
5644 pb.num_blocks *= (fs->blocksize / 512);
5645#if 0
5646 printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
5647 ino, inode->i_size, pb.last_block, inode->i_blocks,
5648 pb.num_blocks);
5649#endif
5650 if (pb.is_dir) {
5651 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
5652 if (nblock > (pb.last_block + 1))
5653 bad_size = 1;
5654 else if (nblock < (pb.last_block + 1)) {
5655 if (((pb.last_block + 1) - nblock) >
5656 fs->super->s_prealloc_dir_blocks)
5657 bad_size = 2;
5658 }
5659 } else {
5660 size = EXT2_I_SIZE(inode);
5661 if ((pb.last_block >= 0) &&
5662 (size < (__u64) pb.last_block * fs->blocksize))
5663 bad_size = 3;
5664 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
5665 bad_size = 4;
5666 }
5667 /* i_size for symlinks is checked elsewhere */
5668 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
5669 pctx->num = (pb.last_block+1) * fs->blocksize;
5670 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
5671 inode->i_size = pctx->num;
5672 if (!LINUX_S_ISDIR(inode->i_mode))
5673 inode->i_size_high = pctx->num >> 32;
5674 dirty_inode++;
5675 }
5676 pctx->num = 0;
5677 }
5678 if (LINUX_S_ISREG(inode->i_mode) &&
5679 (inode->i_size_high || inode->i_size & 0x80000000UL))
5680 ctx->large_files++;
5681 if (pb.num_blocks != inode->i_blocks) {
5682 pctx->num = pb.num_blocks;
5683 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
5684 inode->i_blocks = pb.num_blocks;
5685 dirty_inode++;
5686 }
5687 pctx->num = 0;
5688 }
5689out:
5690 if (dirty_inode)
5691 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
5692}
5693
5694#if 0
5695/*
5696 * Helper function called by process block when an illegal block is
5697 * found. It returns a description about why the block is illegal
5698 */
5699static char *describe_illegal_block(ext2_filsys fs, blk_t block)
5700{
5701 blk_t super;
5702 int i;
5703 static char problem[80];
5704
5705 super = fs->super->s_first_data_block;
5706 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
5707 if (block < super) {
5708 sprintf(problem, "< FIRSTBLOCK (%u)", super);
5709 return(problem);
5710 } else if (block >= fs->super->s_blocks_count) {
5711 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
5712 return(problem);
5713 }
5714 for (i = 0; i < fs->group_desc_count; i++) {
5715 if (block == super) {
5716 sprintf(problem, "is the superblock in group %d", i);
5717 break;
5718 }
5719 if (block > super &&
5720 block <= (super + fs->desc_blocks)) {
5721 sprintf(problem, "is in the group descriptors "
5722 "of group %d", i);
5723 break;
5724 }
5725 if (block == fs->group_desc[i].bg_block_bitmap) {
5726 sprintf(problem, "is the block bitmap of group %d", i);
5727 break;
5728 }
5729 if (block == fs->group_desc[i].bg_inode_bitmap) {
5730 sprintf(problem, "is the inode bitmap of group %d", i);
5731 break;
5732 }
5733 if (block >= fs->group_desc[i].bg_inode_table &&
5734 (block < fs->group_desc[i].bg_inode_table
5735 + fs->inode_blocks_per_group)) {
5736 sprintf(problem, "is in the inode table of group %d",
5737 i);
5738 break;
5739 }
5740 super += fs->super->s_blocks_per_group;
5741 }
5742 return(problem);
5743}
5744#endif
5745
5746/*
5747 * This is a helper function for check_blocks().
5748 */
5749static int process_block(ext2_filsys fs,
5750 blk_t *block_nr,
5751 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005752 blk_t ref_block FSCK_ATTR((unused)),
5753 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005754 void *priv_data)
5755{
5756 struct process_block_struct_1 *p;
5757 struct problem_context *pctx;
5758 blk_t blk = *block_nr;
5759 int ret_code = 0;
5760 int problem = 0;
5761 e2fsck_t ctx;
5762
5763 p = (struct process_block_struct_1 *) priv_data;
5764 pctx = p->pctx;
5765 ctx = p->ctx;
5766
5767 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
5768 /* todo: Check that the comprblk_fl is high, that the
5769 blkaddr pattern looks right (all non-holes up to
5770 first EXT2FS_COMPRESSED_BLKADDR, then all
5771 EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
5772 that the feature_incompat bit is high, and that the
5773 inode is a regular file. If we're doing a "full
5774 check" (a concept introduced to e2fsck by e2compr,
5775 meaning that we look at data blocks as well as
5776 metadata) then call some library routine that
5777 checks the compressed data. I'll have to think
5778 about this, because one particularly important
5779 problem to be able to fix is to recalculate the
5780 cluster size if necessary. I think that perhaps
5781 we'd better do most/all e2compr-specific checks
5782 separately, after the non-e2compr checks. If not
5783 doing a full check, it may be useful to test that
5784 the personality is linux; e.g. if it isn't then
5785 perhaps this really is just an illegal block. */
5786 return 0;
5787 }
5788
5789 if (blk == 0) {
5790 if (p->is_dir == 0) {
5791 /*
5792 * Should never happen, since only directories
5793 * get called with BLOCK_FLAG_HOLE
5794 */
5795#if DEBUG_E2FSCK
5796 printf("process_block() called with blk == 0, "
5797 "blockcnt=%d, inode %lu???\n",
5798 blockcnt, p->ino);
5799#endif
5800 return 0;
5801 }
5802 if (blockcnt < 0)
5803 return 0;
5804 if (blockcnt * fs->blocksize < p->inode->i_size) {
5805#if 0
5806 printf("Missing block (#%d) in directory inode %lu!\n",
5807 blockcnt, p->ino);
5808#endif
5809 goto mark_dir;
5810 }
5811 return 0;
5812 }
5813
5814#if 0
5815 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
5816 blockcnt);
5817#endif
5818
5819 /*
5820 * Simplistic fragmentation check. We merely require that the
5821 * file be contiguous. (Which can never be true for really
5822 * big files that are greater than a block group.)
5823 */
5824 if (!HOLE_BLKADDR(p->previous_block)) {
5825 if (p->previous_block+1 != blk)
5826 p->fragmented = 1;
5827 }
5828 p->previous_block = blk;
5829
5830 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
5831 problem = PR_1_TOOBIG_DIR;
5832 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
5833 problem = PR_1_TOOBIG_REG;
5834 if (!p->is_dir && !p->is_reg && blockcnt > 0)
5835 problem = PR_1_TOOBIG_SYMLINK;
5836
5837 if (blk < fs->super->s_first_data_block ||
5838 blk >= fs->super->s_blocks_count)
5839 problem = PR_1_ILLEGAL_BLOCK_NUM;
5840
5841 if (problem) {
5842 p->num_illegal_blocks++;
5843 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
5844 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
5845 p->clear = 1;
5846 return BLOCK_ABORT;
5847 }
5848 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
5849 p->suppress = 1;
5850 set_latch_flags(PR_LATCH_BLOCK,
5851 PRL_SUPPRESS, 0);
5852 }
5853 }
5854 pctx->blk = blk;
5855 pctx->blkcount = blockcnt;
5856 if (fix_problem(ctx, problem, pctx)) {
5857 blk = *block_nr = 0;
5858 ret_code = BLOCK_CHANGED;
5859 goto mark_dir;
5860 } else
5861 return 0;
5862 }
5863
5864 if (p->ino == EXT2_RESIZE_INO) {
5865 /*
5866 * The resize inode has already be sanity checked
5867 * during pass #0 (the superblock checks). All we
5868 * have to do is mark the double indirect block as
5869 * being in use; all of the other blocks are handled
5870 * by mark_table_blocks()).
5871 */
5872 if (blockcnt == BLOCK_COUNT_DIND)
5873 mark_block_used(ctx, blk);
5874 } else
5875 mark_block_used(ctx, blk);
5876 p->num_blocks++;
5877 if (blockcnt >= 0)
5878 p->last_block = blockcnt;
5879mark_dir:
5880 if (p->is_dir && (blockcnt >= 0)) {
5881 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
5882 blk, blockcnt);
5883 if (pctx->errcode) {
5884 pctx->blk = blk;
5885 pctx->num = blockcnt;
5886 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
5887 /* Should never get here */
5888 ctx->flags |= E2F_FLAG_ABORT;
5889 return BLOCK_ABORT;
5890 }
5891 }
5892 return ret_code;
5893}
5894
5895static int process_bad_block(ext2_filsys fs,
5896 blk_t *block_nr,
5897 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005898 blk_t ref_block FSCK_ATTR((unused)),
5899 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005900 void *priv_data)
5901{
5902 struct process_block_struct_1 *p;
5903 blk_t blk = *block_nr;
5904 blk_t first_block;
5905 dgrp_t i;
5906 struct problem_context *pctx;
5907 e2fsck_t ctx;
5908
5909 /*
5910 * Note: This function processes blocks for the bad blocks
5911 * inode, which is never compressed. So we don't use HOLE_BLKADDR().
5912 */
5913
5914 if (!blk)
5915 return 0;
5916
5917 p = (struct process_block_struct_1 *) priv_data;
5918 ctx = p->ctx;
5919 pctx = p->pctx;
5920
5921 pctx->ino = EXT2_BAD_INO;
5922 pctx->blk = blk;
5923 pctx->blkcount = blockcnt;
5924
5925 if ((blk < fs->super->s_first_data_block) ||
5926 (blk >= fs->super->s_blocks_count)) {
5927 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
5928 *block_nr = 0;
5929 return BLOCK_CHANGED;
5930 } else
5931 return 0;
5932 }
5933
5934 if (blockcnt < 0) {
5935 if (ext2fs_test_block_bitmap(p->fs_meta_blocks, blk)) {
5936 p->bbcheck = 1;
5937 if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) {
5938 *block_nr = 0;
5939 return BLOCK_CHANGED;
5940 }
5941 } else if (ext2fs_test_block_bitmap(ctx->block_found_map,
5942 blk)) {
5943 p->bbcheck = 1;
5944 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
5945 pctx)) {
5946 *block_nr = 0;
5947 return BLOCK_CHANGED;
5948 }
5949 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5950 return BLOCK_ABORT;
5951 } else
5952 mark_block_used(ctx, blk);
5953 return 0;
5954 }
5955#if 0
5956 printf ("DEBUG: Marking %u as bad.\n", blk);
5957#endif
5958 ctx->fs_badblocks_count++;
5959 /*
5960 * If the block is not used, then mark it as used and return.
5961 * If it is already marked as found, this must mean that
5962 * there's an overlap between the filesystem table blocks
5963 * (bitmaps and inode table) and the bad block list.
5964 */
5965 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
5966 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
5967 return 0;
5968 }
5969 /*
5970 * Try to find the where the filesystem block was used...
5971 */
5972 first_block = fs->super->s_first_data_block;
5973
5974 for (i = 0; i < fs->group_desc_count; i++ ) {
5975 pctx->group = i;
5976 pctx->blk = blk;
5977 if (!ext2fs_bg_has_super(fs, i))
5978 goto skip_super;
5979 if (blk == first_block) {
5980 if (i == 0) {
5981 if (fix_problem(ctx,
5982 PR_1_BAD_PRIMARY_SUPERBLOCK,
5983 pctx)) {
5984 *block_nr = 0;
5985 return BLOCK_CHANGED;
5986 }
5987 return 0;
5988 }
5989 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
5990 return 0;
5991 }
5992 if ((blk > first_block) &&
5993 (blk <= first_block + fs->desc_blocks)) {
5994 if (i == 0) {
5995 pctx->blk = *block_nr;
5996 if (fix_problem(ctx,
5997 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
5998 *block_nr = 0;
5999 return BLOCK_CHANGED;
6000 }
6001 return 0;
6002 }
6003 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
6004 return 0;
6005 }
6006 skip_super:
6007 if (blk == fs->group_desc[i].bg_block_bitmap) {
6008 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
6009 ctx->invalid_block_bitmap_flag[i]++;
6010 ctx->invalid_bitmaps++;
6011 }
6012 return 0;
6013 }
6014 if (blk == fs->group_desc[i].bg_inode_bitmap) {
6015 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
6016 ctx->invalid_inode_bitmap_flag[i]++;
6017 ctx->invalid_bitmaps++;
6018 }
6019 return 0;
6020 }
6021 if ((blk >= fs->group_desc[i].bg_inode_table) &&
6022 (blk < (fs->group_desc[i].bg_inode_table +
6023 fs->inode_blocks_per_group))) {
6024 /*
6025 * If there are bad blocks in the inode table,
6026 * the inode scan code will try to do
6027 * something reasonable automatically.
6028 */
6029 return 0;
6030 }
6031 first_block += fs->super->s_blocks_per_group;
6032 }
6033 /*
6034 * If we've gotten to this point, then the only
6035 * possibility is that the bad block inode meta data
6036 * is using a bad block.
6037 */
6038 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
6039 (blk == p->inode->i_block[EXT2_DIND_BLOCK]) ||
6040 (blk == p->inode->i_block[EXT2_TIND_BLOCK])) {
6041 p->bbcheck = 1;
6042 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) {
6043 *block_nr = 0;
6044 return BLOCK_CHANGED;
6045 }
6046 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6047 return BLOCK_ABORT;
6048 return 0;
6049 }
6050
6051 pctx->group = -1;
6052
6053 /* Warn user that the block wasn't claimed */
6054 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
6055
6056 return 0;
6057}
6058
6059static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
6060 const char *name, int num, blk_t *new_block)
6061{
6062 ext2_filsys fs = ctx->fs;
6063 blk_t old_block = *new_block;
6064 int i;
6065 char *buf;
6066 struct problem_context pctx;
6067
6068 clear_problem_context(&pctx);
6069
6070 pctx.group = group;
6071 pctx.blk = old_block;
6072 pctx.str = name;
6073
6074 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
6075 first_block + fs->super->s_blocks_per_group,
6076 num, ctx->block_found_map, new_block);
6077 if (pctx.errcode) {
6078 pctx.num = num;
6079 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
6080 ext2fs_unmark_valid(fs);
6081 return;
6082 }
6083 pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf);
6084 if (pctx.errcode) {
6085 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
6086 ext2fs_unmark_valid(fs);
6087 return;
6088 }
6089 ext2fs_mark_super_dirty(fs);
6090 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
6091 pctx.blk2 = *new_block;
6092 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
6093 PR_1_RELOC_TO), &pctx);
6094 pctx.blk2 = 0;
6095 for (i = 0; i < num; i++) {
6096 pctx.blk = i;
6097 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
6098 if (old_block) {
6099 pctx.errcode = io_channel_read_blk(fs->io,
6100 old_block + i, 1, buf);
6101 if (pctx.errcode)
6102 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
6103 } else
6104 memset(buf, 0, fs->blocksize);
6105
6106 pctx.blk = (*new_block) + i;
6107 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
6108 1, buf);
6109 if (pctx.errcode)
6110 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
6111 }
6112 ext2fs_free_mem(&buf);
6113}
6114
6115/*
6116 * This routine gets called at the end of pass 1 if bad blocks are
6117 * detected in the superblock, group descriptors, inode_bitmaps, or
6118 * block bitmaps. At this point, all of the blocks have been mapped
6119 * out, so we can try to allocate new block(s) to replace the bad
6120 * blocks.
6121 */
6122static void handle_fs_bad_blocks(e2fsck_t ctx)
6123{
6124 ext2_filsys fs = ctx->fs;
6125 dgrp_t i;
6126 int first_block = fs->super->s_first_data_block;
6127
6128 for (i = 0; i < fs->group_desc_count; i++) {
6129 if (ctx->invalid_block_bitmap_flag[i]) {
6130 new_table_block(ctx, first_block, i, _("block bitmap"),
6131 1, &fs->group_desc[i].bg_block_bitmap);
6132 }
6133 if (ctx->invalid_inode_bitmap_flag[i]) {
6134 new_table_block(ctx, first_block, i, _("inode bitmap"),
6135 1, &fs->group_desc[i].bg_inode_bitmap);
6136 }
6137 if (ctx->invalid_inode_table_flag[i]) {
6138 new_table_block(ctx, first_block, i, _("inode table"),
6139 fs->inode_blocks_per_group,
6140 &fs->group_desc[i].bg_inode_table);
6141 ctx->flags |= E2F_FLAG_RESTART;
6142 }
6143 first_block += fs->super->s_blocks_per_group;
6144 }
6145 ctx->invalid_bitmaps = 0;
6146}
6147
6148/*
6149 * This routine marks all blocks which are used by the superblock,
6150 * group descriptors, inode bitmaps, and block bitmaps.
6151 */
6152static void mark_table_blocks(e2fsck_t ctx)
6153{
6154 ext2_filsys fs = ctx->fs;
6155 blk_t block, b;
6156 dgrp_t i;
6157 int j;
6158 struct problem_context pctx;
6159
6160 clear_problem_context(&pctx);
6161
6162 block = fs->super->s_first_data_block;
6163 for (i = 0; i < fs->group_desc_count; i++) {
6164 pctx.group = i;
6165
6166 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
6167
6168 /*
6169 * Mark the blocks used for the inode table
6170 */
6171 if (fs->group_desc[i].bg_inode_table) {
6172 for (j = 0, b = fs->group_desc[i].bg_inode_table;
6173 j < fs->inode_blocks_per_group;
6174 j++, b++) {
6175 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6176 b)) {
6177 pctx.blk = b;
6178 if (fix_problem(ctx,
6179 PR_1_ITABLE_CONFLICT, &pctx)) {
6180 ctx->invalid_inode_table_flag[i]++;
6181 ctx->invalid_bitmaps++;
6182 }
6183 } else {
6184 ext2fs_mark_block_bitmap(ctx->block_found_map,
6185 b);
6186 }
6187 }
6188 }
6189
6190 /*
6191 * Mark block used for the block bitmap
6192 */
6193 if (fs->group_desc[i].bg_block_bitmap) {
6194 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6195 fs->group_desc[i].bg_block_bitmap)) {
6196 pctx.blk = fs->group_desc[i].bg_block_bitmap;
6197 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
6198 ctx->invalid_block_bitmap_flag[i]++;
6199 ctx->invalid_bitmaps++;
6200 }
6201 } else {
6202 ext2fs_mark_block_bitmap(ctx->block_found_map,
6203 fs->group_desc[i].bg_block_bitmap);
6204 }
6205
6206 }
6207 /*
6208 * Mark block used for the inode bitmap
6209 */
6210 if (fs->group_desc[i].bg_inode_bitmap) {
6211 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6212 fs->group_desc[i].bg_inode_bitmap)) {
6213 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
6214 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
6215 ctx->invalid_inode_bitmap_flag[i]++;
6216 ctx->invalid_bitmaps++;
6217 }
6218 } else {
6219 ext2fs_mark_block_bitmap(ctx->block_found_map,
6220 fs->group_desc[i].bg_inode_bitmap);
6221 }
6222 }
6223 block += fs->super->s_blocks_per_group;
6224 }
6225}
6226
6227/*
6228 * Thes subroutines short circuits ext2fs_get_blocks and
6229 * ext2fs_check_directory; we use them since we already have the inode
6230 * structure, so there's no point in letting the ext2fs library read
6231 * the inode again.
6232 */
6233static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
6234 blk_t *blocks)
6235{
6236 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6237 int i;
6238
6239 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6240 return EXT2_ET_CALLBACK_NOTHANDLED;
6241
6242 for (i=0; i < EXT2_N_BLOCKS; i++)
6243 blocks[i] = ctx->stashed_inode->i_block[i];
6244 return 0;
6245}
6246
6247static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
6248 struct ext2_inode *inode)
6249{
6250 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6251
6252 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6253 return EXT2_ET_CALLBACK_NOTHANDLED;
6254 *inode = *ctx->stashed_inode;
6255 return 0;
6256}
6257
6258static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
6259 struct ext2_inode *inode)
6260{
6261 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6262
6263 if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
6264 *ctx->stashed_inode = *inode;
6265 return EXT2_ET_CALLBACK_NOTHANDLED;
6266}
6267
6268static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
6269{
6270 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6271
6272 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6273 return EXT2_ET_CALLBACK_NOTHANDLED;
6274
6275 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
6276 return EXT2_ET_NO_DIRECTORY;
6277 return 0;
6278}
6279
6280void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
6281{
6282 ext2_filsys fs = ctx->fs;
6283
6284 if (bool) {
6285 fs->get_blocks = pass1_get_blocks;
6286 fs->check_directory = pass1_check_directory;
6287 fs->read_inode = pass1_read_inode;
6288 fs->write_inode = pass1_write_inode;
6289 ctx->stashed_ino = 0;
6290 } else {
6291 fs->get_blocks = 0;
6292 fs->check_directory = 0;
6293 fs->read_inode = 0;
6294 fs->write_inode = 0;
6295 }
6296}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006297
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006298/*
6299 * pass1b.c --- Pass #1b of e2fsck
6300 *
6301 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
6302 * only invoked if pass 1 discovered blocks which are in use by more
6303 * than one inode.
6304 *
6305 * Pass1B scans the data blocks of all the inodes again, generating a
6306 * complete list of duplicate blocks and which inodes have claimed
6307 * them.
6308 *
6309 * Pass1C does a tree-traversal of the filesystem, to determine the
6310 * parent directories of these inodes. This step is necessary so that
6311 * e2fsck can print out the pathnames of affected inodes.
6312 *
6313 * Pass1D is a reconciliation pass. For each inode with duplicate
6314 * blocks, the user is prompted if s/he would like to clone the file
6315 * (so that the file gets a fresh copy of the duplicated blocks) or
6316 * simply to delete the file.
6317 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006318 */
6319
6320
6321/* Needed for architectures where sizeof(int) != sizeof(void *) */
6322#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
6323#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
6324
6325/* Define an extension to the ext2 library's block count information */
6326#define BLOCK_COUNT_EXTATTR (-5)
6327
6328struct block_el {
6329 blk_t block;
6330 struct block_el *next;
6331};
6332
6333struct inode_el {
6334 ext2_ino_t inode;
6335 struct inode_el *next;
6336};
6337
6338struct dup_block {
6339 int num_bad;
6340 struct inode_el *inode_list;
6341};
6342
6343/*
6344 * This structure stores information about a particular inode which
6345 * is sharing blocks with other inodes. This information is collected
6346 * to display to the user, so that the user knows what files he or she
6347 * is dealing with, when trying to decide how to resolve the conflict
6348 * of multiply-claimed blocks.
6349 */
6350struct dup_inode {
6351 ext2_ino_t dir;
6352 int num_dupblocks;
6353 struct ext2_inode inode;
6354 struct block_el *block_list;
6355};
6356
6357static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
6358 e2_blkcnt_t blockcnt, blk_t ref_blk,
6359 int ref_offset, void *priv_data);
6360static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
6361 struct dup_inode *dp, char *block_buf);
6362static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
6363 struct dup_inode *dp, char* block_buf);
6364static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
6365
6366static void pass1b(e2fsck_t ctx, char *block_buf);
6367static void pass1c(e2fsck_t ctx, char *block_buf);
6368static void pass1d(e2fsck_t ctx, char *block_buf);
6369
6370static int dup_inode_count = 0;
6371
6372static dict_t blk_dict, ino_dict;
6373
6374static ext2fs_inode_bitmap inode_dup_map;
6375
6376static int dict_int_cmp(const void *a, const void *b)
6377{
6378 intptr_t ia, ib;
6379
6380 ia = (intptr_t)a;
6381 ib = (intptr_t)b;
6382
6383 return (ia-ib);
6384}
6385
6386/*
6387 * Add a duplicate block record
6388 */
6389static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
6390 struct ext2_inode *inode)
6391{
6392 dnode_t *n;
6393 struct dup_block *db;
6394 struct dup_inode *di;
6395 struct block_el *blk_el;
6396 struct inode_el *ino_el;
6397
6398 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
6399 if (n)
6400 db = (struct dup_block *) dnode_get(n);
6401 else {
6402 db = (struct dup_block *) e2fsck_allocate_memory(ctx,
6403 sizeof(struct dup_block), "duplicate block header");
6404 db->num_bad = 0;
6405 db->inode_list = 0;
6406 dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
6407 }
6408 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
6409 sizeof(struct inode_el), "inode element");
6410 ino_el->inode = ino;
6411 ino_el->next = db->inode_list;
6412 db->inode_list = ino_el;
6413 db->num_bad++;
6414
6415 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
6416 if (n)
6417 di = (struct dup_inode *) dnode_get(n);
6418 else {
6419 di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
6420 sizeof(struct dup_inode), "duplicate inode header");
6421 di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0 ;
6422 di->num_dupblocks = 0;
6423 di->block_list = 0;
6424 di->inode = *inode;
6425 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
6426 }
6427 blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
6428 sizeof(struct block_el), "block element");
6429 blk_el->block = blk;
6430 blk_el->next = di->block_list;
6431 di->block_list = blk_el;
6432 di->num_dupblocks++;
6433}
6434
6435/*
6436 * Free a duplicate inode record
6437 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006438static void inode_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006439{
6440 struct dup_inode *di;
6441 struct block_el *p, *next;
6442
6443 di = (struct dup_inode *) dnode_get(node);
6444 for (p = di->block_list; p; p = next) {
6445 next = p->next;
6446 free(p);
6447 }
6448 free(node);
6449}
6450
6451/*
6452 * Free a duplicate block record
6453 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006454static void block_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006455{
6456 struct dup_block *db;
6457 struct inode_el *p, *next;
6458
6459 db = (struct dup_block *) dnode_get(node);
6460 for (p = db->inode_list; p; p = next) {
6461 next = p->next;
6462 free(p);
6463 }
6464 free(node);
6465}
6466
6467
6468/*
6469 * Main procedure for handling duplicate blocks
6470 */
6471void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
6472{
6473 ext2_filsys fs = ctx->fs;
6474 struct problem_context pctx;
6475
6476 clear_problem_context(&pctx);
6477
6478 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
6479 _("multiply claimed inode map"), &inode_dup_map);
6480 if (pctx.errcode) {
6481 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
6482 ctx->flags |= E2F_FLAG_ABORT;
6483 return;
6484 }
6485
6486 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
6487 dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006488 dict_set_allocator(&ino_dict, inode_dnode_free);
6489 dict_set_allocator(&blk_dict, block_dnode_free);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006490
6491 pass1b(ctx, block_buf);
6492 pass1c(ctx, block_buf);
6493 pass1d(ctx, block_buf);
6494
6495 /*
6496 * Time to free all of the accumulated data structures that we
6497 * don't need anymore.
6498 */
6499 dict_free_nodes(&ino_dict);
6500 dict_free_nodes(&blk_dict);
6501}
6502
6503/*
6504 * Scan the inodes looking for inodes that contain duplicate blocks.
6505 */
6506struct process_block_struct_1b {
6507 e2fsck_t ctx;
6508 ext2_ino_t ino;
6509 int dup_blocks;
6510 struct ext2_inode *inode;
6511 struct problem_context *pctx;
6512};
6513
6514static void pass1b(e2fsck_t ctx, char *block_buf)
6515{
6516 ext2_filsys fs = ctx->fs;
6517 ext2_ino_t ino;
6518 struct ext2_inode inode;
6519 ext2_inode_scan scan;
6520 struct process_block_struct_1b pb;
6521 struct problem_context pctx;
6522
6523 clear_problem_context(&pctx);
6524
6525 if (!(ctx->options & E2F_OPT_PREEN))
6526 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
6527 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
6528 &scan);
6529 if (pctx.errcode) {
6530 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6531 ctx->flags |= E2F_FLAG_ABORT;
6532 return;
6533 }
6534 ctx->stashed_inode = &inode;
6535 pb.ctx = ctx;
6536 pb.pctx = &pctx;
6537 pctx.str = "pass1b";
6538 while (1) {
6539 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
6540 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
6541 continue;
6542 if (pctx.errcode) {
6543 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6544 ctx->flags |= E2F_FLAG_ABORT;
6545 return;
6546 }
6547 if (!ino)
6548 break;
6549 pctx.ino = ctx->stashed_ino = ino;
6550 if ((ino != EXT2_BAD_INO) &&
6551 !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
6552 continue;
6553
6554 pb.ino = ino;
6555 pb.dup_blocks = 0;
6556 pb.inode = &inode;
6557
6558 if (ext2fs_inode_has_valid_blocks(&inode) ||
6559 (ino == EXT2_BAD_INO))
6560 pctx.errcode = ext2fs_block_iterate2(fs, ino,
6561 0, block_buf, process_pass1b_block, &pb);
6562 if (inode.i_file_acl)
6563 process_pass1b_block(fs, &inode.i_file_acl,
6564 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
6565 if (pb.dup_blocks) {
6566 end_problem_latch(ctx, PR_LATCH_DBLOCK);
6567 if (ino >= EXT2_FIRST_INODE(fs->super) ||
6568 ino == EXT2_ROOT_INO)
6569 dup_inode_count++;
6570 }
6571 if (pctx.errcode)
6572 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
6573 }
6574 ext2fs_close_inode_scan(scan);
6575 e2fsck_use_inode_shortcuts(ctx, 0);
6576}
6577
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006578static int process_pass1b_block(ext2_filsys fs FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006579 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006580 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
6581 blk_t ref_blk FSCK_ATTR((unused)),
6582 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006583 void *priv_data)
6584{
6585 struct process_block_struct_1b *p;
6586 e2fsck_t ctx;
6587
6588 if (HOLE_BLKADDR(*block_nr))
6589 return 0;
6590 p = (struct process_block_struct_1b *) priv_data;
6591 ctx = p->ctx;
6592
6593 if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
6594 return 0;
6595
6596 /* OK, this is a duplicate block */
6597 if (p->ino != EXT2_BAD_INO) {
6598 p->pctx->blk = *block_nr;
6599 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
6600 }
6601 p->dup_blocks++;
6602 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
6603
6604 add_dupe(ctx, p->ino, *block_nr, p->inode);
6605
6606 return 0;
6607}
6608
6609/*
6610 * Pass 1c: Scan directories for inodes with duplicate blocks. This
6611 * is used so that we can print pathnames when prompting the user for
6612 * what to do.
6613 */
6614struct search_dir_struct {
6615 int count;
6616 ext2_ino_t first_inode;
6617 ext2_ino_t max_inode;
6618};
6619
6620static int search_dirent_proc(ext2_ino_t dir, int entry,
6621 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006622 int offset FSCK_ATTR((unused)),
6623 int blocksize FSCK_ATTR((unused)),
6624 char *buf FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006625 void *priv_data)
6626{
6627 struct search_dir_struct *sd;
6628 struct dup_inode *p;
6629 dnode_t *n;
6630
6631 sd = (struct search_dir_struct *) priv_data;
6632
6633 if (dirent->inode > sd->max_inode)
6634 /* Should abort this inode, but not everything */
6635 return 0;
6636
6637 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
6638 !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
6639 return 0;
6640
6641 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
6642 if (!n)
6643 return 0;
6644 p = (struct dup_inode *) dnode_get(n);
6645 p->dir = dir;
6646 sd->count--;
6647
6648 return(sd->count ? 0 : DIRENT_ABORT);
6649}
6650
6651
6652static void pass1c(e2fsck_t ctx, char *block_buf)
6653{
6654 ext2_filsys fs = ctx->fs;
6655 struct search_dir_struct sd;
6656 struct problem_context pctx;
6657
6658 clear_problem_context(&pctx);
6659
6660 if (!(ctx->options & E2F_OPT_PREEN))
6661 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
6662
6663 /*
6664 * Search through all directories to translate inodes to names
6665 * (by searching for the containing directory for that inode.)
6666 */
6667 sd.count = dup_inode_count;
6668 sd.first_inode = EXT2_FIRST_INODE(fs->super);
6669 sd.max_inode = fs->super->s_inodes_count;
6670 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
6671 search_dirent_proc, &sd);
6672}
6673
6674static void pass1d(e2fsck_t ctx, char *block_buf)
6675{
6676 ext2_filsys fs = ctx->fs;
6677 struct dup_inode *p, *t;
6678 struct dup_block *q;
6679 ext2_ino_t *shared, ino;
6680 int shared_len;
6681 int i;
6682 int file_ok;
6683 int meta_data = 0;
6684 struct problem_context pctx;
6685 dnode_t *n, *m;
6686 struct block_el *s;
6687 struct inode_el *r;
6688
6689 clear_problem_context(&pctx);
6690
6691 if (!(ctx->options & E2F_OPT_PREEN))
6692 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
6693 e2fsck_read_bitmaps(ctx);
6694
6695 pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
6696 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
6697 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
6698 sizeof(ext2_ino_t) * dict_count(&ino_dict),
6699 "Shared inode list");
6700 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
6701 p = (struct dup_inode *) dnode_get(n);
6702 shared_len = 0;
6703 file_ok = 1;
6704 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
6705 if (ino == EXT2_BAD_INO)
6706 continue;
6707
6708 /*
6709 * Find all of the inodes which share blocks with this
6710 * one. First we find all of the duplicate blocks
6711 * belonging to this inode, and then search each block
6712 * get the list of inodes, and merge them together.
6713 */
6714 for (s = p->block_list; s; s = s->next) {
6715 m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
6716 if (!m)
6717 continue; /* Should never happen... */
6718 q = (struct dup_block *) dnode_get(m);
6719 if (q->num_bad > 1)
6720 file_ok = 0;
6721 if (check_if_fs_block(ctx, s->block)) {
6722 file_ok = 0;
6723 meta_data = 1;
6724 }
6725
6726 /*
6727 * Add all inodes used by this block to the
6728 * shared[] --- which is a unique list, so
6729 * if an inode is already in shared[], don't
6730 * add it again.
6731 */
6732 for (r = q->inode_list; r; r = r->next) {
6733 if (r->inode == ino)
6734 continue;
6735 for (i = 0; i < shared_len; i++)
6736 if (shared[i] == r->inode)
6737 break;
6738 if (i == shared_len) {
6739 shared[shared_len++] = r->inode;
6740 }
6741 }
6742 }
6743
6744 /*
6745 * Report the inode that we are working on
6746 */
6747 pctx.inode = &p->inode;
6748 pctx.ino = ino;
6749 pctx.dir = p->dir;
6750 pctx.blkcount = p->num_dupblocks;
6751 pctx.num = meta_data ? shared_len+1 : shared_len;
6752 fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
6753 pctx.blkcount = 0;
6754 pctx.num = 0;
6755
6756 if (meta_data)
6757 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
6758
6759 for (i = 0; i < shared_len; i++) {
6760 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
6761 if (!m)
6762 continue; /* should never happen */
6763 t = (struct dup_inode *) dnode_get(m);
6764 /*
6765 * Report the inode that we are sharing with
6766 */
6767 pctx.inode = &t->inode;
6768 pctx.ino = shared[i];
6769 pctx.dir = t->dir;
6770 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
6771 }
6772 if (file_ok) {
6773 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
6774 continue;
6775 }
6776 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
6777 pctx.errcode = clone_file(ctx, ino, p, block_buf);
6778 if (pctx.errcode)
6779 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
6780 else
6781 continue;
6782 }
6783 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
6784 delete_file(ctx, ino, p, block_buf);
6785 else
6786 ext2fs_unmark_valid(fs);
6787 }
6788 ext2fs_free_mem(&shared);
6789}
6790
6791/*
6792 * Drop the refcount on the dup_block structure, and clear the entry
6793 * in the block_dup_map if appropriate.
6794 */
6795static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
6796{
6797 p->num_bad--;
6798 if (p->num_bad <= 0 ||
6799 (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
6800 ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
6801}
6802
6803static int delete_file_block(ext2_filsys fs,
6804 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006805 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
6806 blk_t ref_block FSCK_ATTR((unused)),
6807 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006808 void *priv_data)
6809{
6810 struct process_block_struct_1b *pb;
6811 struct dup_block *p;
6812 dnode_t *n;
6813 e2fsck_t ctx;
6814
6815 pb = (struct process_block_struct_1b *) priv_data;
6816 ctx = pb->ctx;
6817
6818 if (HOLE_BLKADDR(*block_nr))
6819 return 0;
6820
6821 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
6822 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
6823 if (n) {
6824 p = (struct dup_block *) dnode_get(n);
6825 decrement_badcount(ctx, *block_nr, p);
6826 } else
6827 com_err("delete_file_block", 0,
6828 _("internal error; can't find dup_blk for %d\n"),
6829 *block_nr);
6830 } else {
6831 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
6832 ext2fs_block_alloc_stats(fs, *block_nr, -1);
6833 }
6834
6835 return 0;
6836}
6837
6838static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
6839 struct dup_inode *dp, char* block_buf)
6840{
6841 ext2_filsys fs = ctx->fs;
6842 struct process_block_struct_1b pb;
6843 struct ext2_inode inode;
6844 struct problem_context pctx;
6845 unsigned int count;
6846
6847 clear_problem_context(&pctx);
6848 pctx.ino = pb.ino = ino;
6849 pb.dup_blocks = dp->num_dupblocks;
6850 pb.ctx = ctx;
6851 pctx.str = "delete_file";
6852
6853 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
6854 if (ext2fs_inode_has_valid_blocks(&inode))
6855 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
6856 delete_file_block, &pb);
6857 if (pctx.errcode)
6858 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
6859 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
6860 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
6861 if (ctx->inode_bad_map)
6862 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
6863 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
6864
6865 /* Inode may have changed by block_iterate, so reread it */
6866 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
6867 inode.i_links_count = 0;
6868 inode.i_dtime = time(0);
6869 if (inode.i_file_acl &&
6870 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
6871 count = 1;
6872 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
6873 block_buf, -1, &count);
6874 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
6875 pctx.errcode = 0;
6876 count = 1;
6877 }
6878 if (pctx.errcode) {
6879 pctx.blk = inode.i_file_acl;
6880 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
6881 }
6882 /*
6883 * If the count is zero, then arrange to have the
6884 * block deleted. If the block is in the block_dup_map,
6885 * also call delete_file_block since it will take care
6886 * of keeping the accounting straight.
6887 */
6888 if ((count == 0) ||
6889 ext2fs_test_block_bitmap(ctx->block_dup_map,
6890 inode.i_file_acl))
6891 delete_file_block(fs, &inode.i_file_acl,
6892 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
6893 }
6894 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
6895}
6896
6897struct clone_struct {
6898 errcode_t errcode;
6899 ext2_ino_t dir;
6900 char *buf;
6901 e2fsck_t ctx;
6902};
6903
6904static int clone_file_block(ext2_filsys fs,
6905 blk_t *block_nr,
6906 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006907 blk_t ref_block FSCK_ATTR((unused)),
6908 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006909 void *priv_data)
6910{
6911 struct dup_block *p;
6912 blk_t new_block;
6913 errcode_t retval;
6914 struct clone_struct *cs = (struct clone_struct *) priv_data;
6915 dnode_t *n;
6916 e2fsck_t ctx;
6917
6918 ctx = cs->ctx;
6919
6920 if (HOLE_BLKADDR(*block_nr))
6921 return 0;
6922
6923 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
6924 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
6925 if (n) {
6926 p = (struct dup_block *) dnode_get(n);
6927 retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
6928 &new_block);
6929 if (retval) {
6930 cs->errcode = retval;
6931 return BLOCK_ABORT;
6932 }
6933 if (cs->dir && (blockcnt >= 0)) {
6934 retval = ext2fs_set_dir_block(fs->dblist,
6935 cs->dir, new_block, blockcnt);
6936 if (retval) {
6937 cs->errcode = retval;
6938 return BLOCK_ABORT;
6939 }
6940 }
6941#if 0
6942 printf("Cloning block %u to %u\n", *block_nr,
6943 new_block);
6944#endif
6945 retval = io_channel_read_blk(fs->io, *block_nr, 1,
6946 cs->buf);
6947 if (retval) {
6948 cs->errcode = retval;
6949 return BLOCK_ABORT;
6950 }
6951 retval = io_channel_write_blk(fs->io, new_block, 1,
6952 cs->buf);
6953 if (retval) {
6954 cs->errcode = retval;
6955 return BLOCK_ABORT;
6956 }
6957 decrement_badcount(ctx, *block_nr, p);
6958 *block_nr = new_block;
6959 ext2fs_mark_block_bitmap(ctx->block_found_map,
6960 new_block);
6961 ext2fs_mark_block_bitmap(fs->block_map, new_block);
6962 return BLOCK_CHANGED;
6963 } else
6964 com_err("clone_file_block", 0,
6965 _("internal error; can't find dup_blk for %d\n"),
6966 *block_nr);
6967 }
6968 return 0;
6969}
6970
6971static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
6972 struct dup_inode *dp, char* block_buf)
6973{
6974 ext2_filsys fs = ctx->fs;
6975 errcode_t retval;
6976 struct clone_struct cs;
6977 struct problem_context pctx;
6978 blk_t blk;
6979 dnode_t *n;
6980 struct inode_el *ino_el;
6981 struct dup_block *db;
6982 struct dup_inode *di;
6983
6984 clear_problem_context(&pctx);
6985 cs.errcode = 0;
6986 cs.dir = 0;
6987 cs.ctx = ctx;
6988 retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
6989 if (retval)
6990 return retval;
6991
6992 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
6993 cs.dir = ino;
6994
6995 pctx.ino = ino;
6996 pctx.str = "clone_file";
6997 if (ext2fs_inode_has_valid_blocks(&dp->inode))
6998 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
6999 clone_file_block, &cs);
7000 ext2fs_mark_bb_dirty(fs);
7001 if (pctx.errcode) {
7002 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
7003 retval = pctx.errcode;
7004 goto errout;
7005 }
7006 if (cs.errcode) {
7007 com_err("clone_file", cs.errcode,
7008 _("returned from clone_file_block"));
7009 retval = cs.errcode;
7010 goto errout;
7011 }
7012 /* The inode may have changed on disk, so we have to re-read it */
7013 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
7014 blk = dp->inode.i_file_acl;
7015 if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
7016 BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
7017 BLOCK_CHANGED)) {
7018 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
7019 /*
7020 * If we cloned the EA block, find all other inodes
7021 * which refered to that EA block, and modify
7022 * them to point to the new EA block.
7023 */
7024 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
7025 db = (struct dup_block *) dnode_get(n);
7026 for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
7027 if (ino_el->inode == ino)
7028 continue;
7029 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
7030 di = (struct dup_inode *) dnode_get(n);
7031 if (di->inode.i_file_acl == blk) {
7032 di->inode.i_file_acl = dp->inode.i_file_acl;
7033 e2fsck_write_inode(ctx, ino_el->inode,
7034 &di->inode, "clone file EA");
7035 decrement_badcount(ctx, blk, db);
7036 }
7037 }
7038 }
7039 retval = 0;
7040errout:
7041 ext2fs_free_mem(&cs.buf);
7042 return retval;
7043}
7044
7045/*
7046 * This routine returns 1 if a block overlaps with one of the superblocks,
7047 * group descriptors, inode bitmaps, or block bitmaps.
7048 */
7049static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
7050{
7051 ext2_filsys fs = ctx->fs;
7052 blk_t block;
7053 dgrp_t i;
7054
7055 block = fs->super->s_first_data_block;
7056 for (i = 0; i < fs->group_desc_count; i++) {
7057
7058 /* Check superblocks/block group descriptros */
7059 if (ext2fs_bg_has_super(fs, i)) {
7060 if (test_block >= block &&
7061 (test_block <= block + fs->desc_blocks))
7062 return 1;
7063 }
7064
7065 /* Check the inode table */
7066 if ((fs->group_desc[i].bg_inode_table) &&
7067 (test_block >= fs->group_desc[i].bg_inode_table) &&
7068 (test_block < (fs->group_desc[i].bg_inode_table +
7069 fs->inode_blocks_per_group)))
7070 return 1;
7071
7072 /* Check the bitmap blocks */
7073 if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
7074 (test_block == fs->group_desc[i].bg_inode_bitmap))
7075 return 1;
7076
7077 block += fs->super->s_blocks_per_group;
7078 }
7079 return 0;
7080}
7081/*
7082 * pass2.c --- check directory structure
7083 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007084 * Pass 2 of e2fsck iterates through all active directory inodes, and
7085 * applies to following tests to each directory entry in the directory
7086 * blocks in the inodes:
7087 *
7088 * - The length of the directory entry (rec_len) should be at
7089 * least 8 bytes, and no more than the remaining space
7090 * left in the directory block.
7091 * - The length of the name in the directory entry (name_len)
7092 * should be less than (rec_len - 8).
7093 * - The inode number in the directory entry should be within
7094 * legal bounds.
7095 * - The inode number should refer to a in-use inode.
7096 * - The first entry should be '.', and its inode should be
7097 * the inode of the directory.
7098 * - The second entry should be '..'.
7099 *
7100 * To minimize disk seek time, the directory blocks are processed in
7101 * sorted order of block numbers.
7102 *
7103 * Pass 2 also collects the following information:
7104 * - The inode numbers of the subdirectories for each directory.
7105 *
7106 * Pass 2 relies on the following information from previous passes:
7107 * - The directory information collected in pass 1.
7108 * - The inode_used_map bitmap
7109 * - The inode_bad_map bitmap
7110 * - The inode_dir_map bitmap
7111 *
7112 * Pass 2 frees the following data structures
7113 * - The inode_bad_map bitmap
7114 * - The inode_reg_map bitmap
7115 */
7116
7117/* #define DX_DEBUG */
7118
7119/*
7120 * Keeps track of how many times an inode is referenced.
7121 */
7122static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
7123static int check_dir_block(ext2_filsys fs,
7124 struct ext2_db_entry *dir_blocks_info,
7125 void *priv_data);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007126static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info,
7127 struct problem_context *pctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007128static int update_dir_block(ext2_filsys fs,
7129 blk_t *block_nr,
7130 e2_blkcnt_t blockcnt,
7131 blk_t ref_block,
7132 int ref_offset,
7133 void *priv_data);
7134static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
7135static int htree_depth(struct dx_dir_info *dx_dir,
7136 struct dx_dirblock_info *dx_db);
7137static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
7138
7139struct check_dir_struct {
7140 char *buf;
7141 struct problem_context pctx;
7142 int count, max;
7143 e2fsck_t ctx;
7144};
7145
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007146static void e2fsck_pass2(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007147{
7148 struct ext2_super_block *sb = ctx->fs->super;
7149 struct problem_context pctx;
7150 ext2_filsys fs = ctx->fs;
7151 char *buf;
7152#ifdef RESOURCE_TRACK
7153 struct resource_track rtrack;
7154#endif
7155 struct dir_info *dir;
7156 struct check_dir_struct cd;
7157 struct dx_dir_info *dx_dir;
7158 struct dx_dirblock_info *dx_db, *dx_parent;
7159 int b;
7160 int i, depth;
7161 problem_t code;
7162 int bad_dir;
7163
7164#ifdef RESOURCE_TRACK
7165 init_resource_track(&rtrack);
7166#endif
7167
7168 clear_problem_context(&cd.pctx);
7169
7170#ifdef MTRACE
7171 mtrace_print("Pass 2");
7172#endif
7173
7174 if (!(ctx->options & E2F_OPT_PREEN))
7175 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
7176
7177 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
7178 0, ctx->inode_link_info,
7179 &ctx->inode_count);
7180 if (cd.pctx.errcode) {
7181 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
7182 ctx->flags |= E2F_FLAG_ABORT;
7183 return;
7184 }
7185 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
7186 "directory scan buffer");
7187
7188 /*
7189 * Set up the parent pointer for the root directory, if
7190 * present. (If the root directory is not present, we will
7191 * create it in pass 3.)
7192 */
7193 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
7194 if (dir)
7195 dir->parent = EXT2_ROOT_INO;
7196
7197 cd.buf = buf;
7198 cd.ctx = ctx;
7199 cd.count = 1;
7200 cd.max = ext2fs_dblist_count(fs->dblist);
7201
7202 if (ctx->progress)
7203 (void) (ctx->progress)(ctx, 2, 0, cd.max);
7204
7205 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
7206 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
7207
7208 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
7209 &cd);
7210 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7211 return;
7212 if (cd.pctx.errcode) {
7213 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
7214 ctx->flags |= E2F_FLAG_ABORT;
7215 return;
7216 }
7217
7218#ifdef ENABLE_HTREE
7219 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
7220 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7221 return;
7222 if (dx_dir->numblocks == 0)
7223 continue;
7224 clear_problem_context(&pctx);
7225 bad_dir = 0;
7226 pctx.dir = dx_dir->ino;
7227 dx_db = dx_dir->dx_block;
7228 if (dx_db->flags & DX_FLAG_REFERENCED)
7229 dx_db->flags |= DX_FLAG_DUP_REF;
7230 else
7231 dx_db->flags |= DX_FLAG_REFERENCED;
7232 /*
7233 * Find all of the first and last leaf blocks, and
7234 * update their parent's min and max hash values
7235 */
7236 for (b=0, dx_db = dx_dir->dx_block;
7237 b < dx_dir->numblocks;
7238 b++, dx_db++) {
7239 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
7240 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
7241 continue;
7242 dx_parent = &dx_dir->dx_block[dx_db->parent];
7243 /*
7244 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
7245 */
7246 if (dx_db->flags & DX_FLAG_FIRST)
7247 dx_parent->min_hash = dx_db->min_hash;
7248 /*
7249 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
7250 */
7251 if (dx_db->flags & DX_FLAG_LAST)
7252 dx_parent->max_hash = dx_db->max_hash;
7253 }
7254
7255 for (b=0, dx_db = dx_dir->dx_block;
7256 b < dx_dir->numblocks;
7257 b++, dx_db++) {
7258 pctx.blkcount = b;
7259 pctx.group = dx_db->parent;
7260 code = 0;
7261 if (!(dx_db->flags & DX_FLAG_FIRST) &&
7262 (dx_db->min_hash < dx_db->node_min_hash)) {
7263 pctx.blk = dx_db->min_hash;
7264 pctx.blk2 = dx_db->node_min_hash;
7265 code = PR_2_HTREE_MIN_HASH;
7266 fix_problem(ctx, code, &pctx);
7267 bad_dir++;
7268 }
7269 if (dx_db->type == DX_DIRBLOCK_LEAF) {
7270 depth = htree_depth(dx_dir, dx_db);
7271 if (depth != dx_dir->depth) {
7272 code = PR_2_HTREE_BAD_DEPTH;
7273 fix_problem(ctx, code, &pctx);
7274 bad_dir++;
7275 }
7276 }
7277 /*
7278 * This test doesn't apply for the root block
7279 * at block #0
7280 */
7281 if (b &&
7282 (dx_db->max_hash > dx_db->node_max_hash)) {
7283 pctx.blk = dx_db->max_hash;
7284 pctx.blk2 = dx_db->node_max_hash;
7285 code = PR_2_HTREE_MAX_HASH;
7286 fix_problem(ctx, code, &pctx);
7287 bad_dir++;
7288 }
7289 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
7290 code = PR_2_HTREE_NOTREF;
7291 fix_problem(ctx, code, &pctx);
7292 bad_dir++;
7293 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
7294 code = PR_2_HTREE_DUPREF;
7295 fix_problem(ctx, code, &pctx);
7296 bad_dir++;
7297 }
7298 if (code == 0)
7299 continue;
7300 }
7301 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
7302 clear_htree(ctx, dx_dir->ino);
7303 dx_dir->numblocks = 0;
7304 }
7305 }
7306#endif
7307 ext2fs_free_mem(&buf);
7308 ext2fs_free_dblist(fs->dblist);
7309
Rob Landleye7c43b62006-03-01 16:39:45 +00007310 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
7311 ctx->inode_bad_map = 0;
7312 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
7313 ctx->inode_reg_map = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007314
7315 clear_problem_context(&pctx);
7316 if (ctx->large_files) {
7317 if (!(sb->s_feature_ro_compat &
7318 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
7319 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
7320 sb->s_feature_ro_compat |=
7321 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7322 ext2fs_mark_super_dirty(fs);
7323 }
7324 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
7325 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
7326 ext2fs_update_dynamic_rev(fs);
7327 ext2fs_mark_super_dirty(fs);
7328 }
7329 } else if (!ctx->large_files &&
7330 (sb->s_feature_ro_compat &
7331 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
7332 if (fs->flags & EXT2_FLAG_RW) {
7333 sb->s_feature_ro_compat &=
7334 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7335 ext2fs_mark_super_dirty(fs);
7336 }
7337 }
7338
7339#ifdef RESOURCE_TRACK
7340 if (ctx->options & E2F_OPT_TIME2) {
7341 e2fsck_clear_progbar(ctx);
7342 print_resource_track(_("Pass 2"), &rtrack);
7343 }
7344#endif
7345}
7346
7347#define MAX_DEPTH 32000
7348static int htree_depth(struct dx_dir_info *dx_dir,
7349 struct dx_dirblock_info *dx_db)
7350{
7351 int depth = 0;
7352
7353 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
7354 dx_db = &dx_dir->dx_block[dx_db->parent];
7355 depth++;
7356 }
7357 return depth;
7358}
7359
7360static int dict_de_cmp(const void *a, const void *b)
7361{
7362 const struct ext2_dir_entry *de_a, *de_b;
7363 int a_len, b_len;
7364
7365 de_a = (const struct ext2_dir_entry *) a;
7366 a_len = de_a->name_len & 0xFF;
7367 de_b = (const struct ext2_dir_entry *) b;
7368 b_len = de_b->name_len & 0xFF;
7369
7370 if (a_len != b_len)
7371 return (a_len - b_len);
7372
7373 return strncmp(de_a->name, de_b->name, a_len);
7374}
7375
7376/*
7377 * This is special sort function that makes sure that directory blocks
7378 * with a dirblock of zero are sorted to the beginning of the list.
7379 * This guarantees that the root node of the htree directories are
7380 * processed first, so we know what hash version to use.
7381 */
7382static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
7383{
7384 const struct ext2_db_entry *db_a =
7385 (const struct ext2_db_entry *) a;
7386 const struct ext2_db_entry *db_b =
7387 (const struct ext2_db_entry *) b;
7388
7389 if (db_a->blockcnt && !db_b->blockcnt)
7390 return 1;
7391
7392 if (!db_a->blockcnt && db_b->blockcnt)
7393 return -1;
7394
7395 if (db_a->blk != db_b->blk)
7396 return (int) (db_a->blk - db_b->blk);
7397
7398 if (db_a->ino != db_b->ino)
7399 return (int) (db_a->ino - db_b->ino);
7400
7401 return (int) (db_a->blockcnt - db_b->blockcnt);
7402}
7403
7404
7405/*
7406 * Make sure the first entry in the directory is '.', and that the
7407 * directory entry is sane.
7408 */
7409static int check_dot(e2fsck_t ctx,
7410 struct ext2_dir_entry *dirent,
7411 ext2_ino_t ino, struct problem_context *pctx)
7412{
7413 struct ext2_dir_entry *nextdir;
7414 int status = 0;
7415 int created = 0;
7416 int new_len;
7417 int problem = 0;
7418
7419 if (!dirent->inode)
7420 problem = PR_2_MISSING_DOT;
7421 else if (((dirent->name_len & 0xFF) != 1) ||
7422 (dirent->name[0] != '.'))
7423 problem = PR_2_1ST_NOT_DOT;
7424 else if (dirent->name[1] != '\0')
7425 problem = PR_2_DOT_NULL_TERM;
7426
7427 if (problem) {
7428 if (fix_problem(ctx, problem, pctx)) {
7429 if (dirent->rec_len < 12)
7430 dirent->rec_len = 12;
7431 dirent->inode = ino;
7432 dirent->name_len = 1;
7433 dirent->name[0] = '.';
7434 dirent->name[1] = '\0';
7435 status = 1;
7436 created = 1;
7437 }
7438 }
7439 if (dirent->inode != ino) {
7440 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
7441 dirent->inode = ino;
7442 status = 1;
7443 }
7444 }
7445 if (dirent->rec_len > 12) {
7446 new_len = dirent->rec_len - 12;
7447 if (new_len > 12) {
7448 if (created ||
7449 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
7450 nextdir = (struct ext2_dir_entry *)
7451 ((char *) dirent + 12);
7452 dirent->rec_len = 12;
7453 nextdir->rec_len = new_len;
7454 nextdir->inode = 0;
7455 nextdir->name_len = 0;
7456 status = 1;
7457 }
7458 }
7459 }
7460 return status;
7461}
7462
7463/*
7464 * Make sure the second entry in the directory is '..', and that the
7465 * directory entry is sane. We do not check the inode number of '..'
7466 * here; this gets done in pass 3.
7467 */
7468static int check_dotdot(e2fsck_t ctx,
7469 struct ext2_dir_entry *dirent,
7470 struct dir_info *dir, struct problem_context *pctx)
7471{
7472 int problem = 0;
7473
7474 if (!dirent->inode)
7475 problem = PR_2_MISSING_DOT_DOT;
7476 else if (((dirent->name_len & 0xFF) != 2) ||
7477 (dirent->name[0] != '.') ||
7478 (dirent->name[1] != '.'))
7479 problem = PR_2_2ND_NOT_DOT_DOT;
7480 else if (dirent->name[2] != '\0')
7481 problem = PR_2_DOT_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 /*
7488 * Note: we don't have the parent inode just
7489 * yet, so we will fill it in with the root
7490 * inode. This will get fixed in pass 3.
7491 */
7492 dirent->inode = EXT2_ROOT_INO;
7493 dirent->name_len = 2;
7494 dirent->name[0] = '.';
7495 dirent->name[1] = '.';
7496 dirent->name[2] = '\0';
7497 return 1;
7498 }
7499 return 0;
7500 }
7501 dir->dotdot = dirent->inode;
7502 return 0;
7503}
7504
7505/*
7506 * Check to make sure a directory entry doesn't contain any illegal
7507 * characters.
7508 */
7509static int check_name(e2fsck_t ctx,
7510 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007511 struct problem_context *pctx)
7512{
7513 int i;
7514 int fixup = -1;
7515 int ret = 0;
7516
7517 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
7518 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
7519 if (fixup < 0) {
7520 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
7521 }
7522 if (fixup) {
7523 dirent->name[i] = '.';
7524 ret = 1;
7525 }
7526 }
7527 }
7528 return ret;
7529}
7530
7531/*
7532 * Check the directory filetype (if present)
7533 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007534
7535/*
7536 * Given a mode, return the ext2 file type
7537 */
7538static int ext2_file_type(unsigned int mode)
7539{
7540 if (LINUX_S_ISREG(mode))
7541 return EXT2_FT_REG_FILE;
7542
7543 if (LINUX_S_ISDIR(mode))
7544 return EXT2_FT_DIR;
7545
7546 if (LINUX_S_ISCHR(mode))
7547 return EXT2_FT_CHRDEV;
7548
7549 if (LINUX_S_ISBLK(mode))
7550 return EXT2_FT_BLKDEV;
7551
7552 if (LINUX_S_ISLNK(mode))
7553 return EXT2_FT_SYMLINK;
7554
7555 if (LINUX_S_ISFIFO(mode))
7556 return EXT2_FT_FIFO;
7557
7558 if (LINUX_S_ISSOCK(mode))
7559 return EXT2_FT_SOCK;
7560
7561 return 0;
7562}
7563
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007564static _INLINE_ int check_filetype(e2fsck_t ctx,
7565 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007566 struct problem_context *pctx)
7567{
7568 int filetype = dirent->name_len >> 8;
7569 int should_be = EXT2_FT_UNKNOWN;
7570 struct ext2_inode inode;
7571
7572 if (!(ctx->fs->super->s_feature_incompat &
7573 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
7574 if (filetype == 0 ||
7575 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
7576 return 0;
7577 dirent->name_len = dirent->name_len & 0xFF;
7578 return 1;
7579 }
7580
7581 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
7582 should_be = EXT2_FT_DIR;
7583 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
7584 dirent->inode)) {
7585 should_be = EXT2_FT_REG_FILE;
7586 } else if (ctx->inode_bad_map &&
7587 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
7588 dirent->inode))
7589 should_be = 0;
7590 else {
7591 e2fsck_read_inode(ctx, dirent->inode, &inode,
7592 "check_filetype");
7593 should_be = ext2_file_type(inode.i_mode);
7594 }
7595 if (filetype == should_be)
7596 return 0;
7597 pctx->num = should_be;
7598
7599 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
7600 pctx) == 0)
7601 return 0;
7602
7603 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
7604 return 1;
7605}
7606
7607#ifdef ENABLE_HTREE
7608static void parse_int_node(ext2_filsys fs,
7609 struct ext2_db_entry *db,
7610 struct check_dir_struct *cd,
7611 struct dx_dir_info *dx_dir,
7612 char *block_buf)
7613{
7614 struct ext2_dx_root_info *root;
7615 struct ext2_dx_entry *ent;
7616 struct ext2_dx_countlimit *limit;
7617 struct dx_dirblock_info *dx_db;
7618 int i, expect_limit, count;
7619 blk_t blk;
7620 ext2_dirhash_t min_hash = 0xffffffff;
7621 ext2_dirhash_t max_hash = 0;
7622 ext2_dirhash_t hash = 0, prev_hash;
7623
7624 if (db->blockcnt == 0) {
7625 root = (struct ext2_dx_root_info *) (block_buf + 24);
7626
7627#ifdef DX_DEBUG
7628 printf("Root node dump:\n");
7629 printf("\t Reserved zero: %d\n", root->reserved_zero);
7630 printf("\t Hash Version: %d\n", root->hash_version);
7631 printf("\t Info length: %d\n", root->info_length);
7632 printf("\t Indirect levels: %d\n", root->indirect_levels);
7633 printf("\t Flags: %d\n", root->unused_flags);
7634#endif
7635
7636 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
7637 } else {
7638 ent = (struct ext2_dx_entry *) (block_buf+8);
7639 }
7640 limit = (struct ext2_dx_countlimit *) ent;
7641
7642#ifdef DX_DEBUG
7643 printf("Number of entries (count): %d\n",
7644 ext2fs_le16_to_cpu(limit->count));
7645 printf("Number of entries (limit): %d\n",
7646 ext2fs_le16_to_cpu(limit->limit));
7647#endif
7648
7649 count = ext2fs_le16_to_cpu(limit->count);
7650 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
7651 sizeof(struct ext2_dx_entry);
7652 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
7653 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
7654 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
7655 goto clear_and_exit;
7656 }
7657 if (count > expect_limit) {
7658 cd->pctx.num = count;
7659 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
7660 goto clear_and_exit;
7661 count = expect_limit;
7662 }
7663
7664 for (i=0; i < count; i++) {
7665 prev_hash = hash;
7666 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
7667#ifdef DX_DEBUG
7668 printf("Entry #%d: Hash 0x%08x, block %d\n", i,
7669 hash, ext2fs_le32_to_cpu(ent[i].block));
7670#endif
7671 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
7672 /* Check to make sure the block is valid */
7673 if (blk > (blk_t) dx_dir->numblocks) {
7674 cd->pctx.blk = blk;
7675 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
7676 &cd->pctx))
7677 goto clear_and_exit;
7678 }
7679 if (hash < prev_hash &&
7680 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
7681 goto clear_and_exit;
7682 dx_db = &dx_dir->dx_block[blk];
7683 if (dx_db->flags & DX_FLAG_REFERENCED) {
7684 dx_db->flags |= DX_FLAG_DUP_REF;
7685 } else {
7686 dx_db->flags |= DX_FLAG_REFERENCED;
7687 dx_db->parent = db->blockcnt;
7688 }
7689 if (hash < min_hash)
7690 min_hash = hash;
7691 if (hash > max_hash)
7692 max_hash = hash;
7693 dx_db->node_min_hash = hash;
7694 if ((i+1) < count)
7695 dx_db->node_max_hash =
7696 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
7697 else {
7698 dx_db->node_max_hash = 0xfffffffe;
7699 dx_db->flags |= DX_FLAG_LAST;
7700 }
7701 if (i == 0)
7702 dx_db->flags |= DX_FLAG_FIRST;
7703 }
7704#ifdef DX_DEBUG
7705 printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
7706 db->blockcnt, min_hash, max_hash);
7707#endif
7708 dx_db = &dx_dir->dx_block[db->blockcnt];
7709 dx_db->min_hash = min_hash;
7710 dx_db->max_hash = max_hash;
7711 return;
7712
7713clear_and_exit:
7714 clear_htree(cd->ctx, cd->pctx.ino);
7715 dx_dir->numblocks = 0;
7716}
7717#endif /* ENABLE_HTREE */
7718
7719/*
7720 * Given a busted directory, try to salvage it somehow.
7721 *
7722 */
7723static void salvage_directory(ext2_filsys fs,
7724 struct ext2_dir_entry *dirent,
7725 struct ext2_dir_entry *prev,
7726 unsigned int *offset)
7727{
7728 char *cp = (char *) dirent;
7729 int left = fs->blocksize - *offset - dirent->rec_len;
7730 int name_len = dirent->name_len & 0xFF;
7731
7732 /*
7733 * Special case of directory entry of size 8: copy what's left
7734 * of the directory block up to cover up the invalid hole.
7735 */
7736 if ((left >= 12) && (dirent->rec_len == 8)) {
7737 memmove(cp, cp+8, left);
7738 memset(cp + left, 0, 8);
7739 return;
7740 }
7741 /*
7742 * If the directory entry overruns the end of the directory
7743 * block, and the name is small enough to fit, then adjust the
7744 * record length.
7745 */
7746 if ((left < 0) &&
7747 (name_len + 8 <= dirent->rec_len + left) &&
7748 dirent->inode <= fs->super->s_inodes_count &&
7749 strnlen(dirent->name, name_len) == name_len) {
7750 dirent->rec_len += left;
7751 return;
7752 }
7753 /*
7754 * If the directory entry is a multiple of four, so it is
7755 * valid, let the previous directory entry absorb the invalid
7756 * one.
7757 */
7758 if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
7759 prev->rec_len += dirent->rec_len;
7760 *offset += dirent->rec_len;
7761 return;
7762 }
7763 /*
7764 * Default salvage method --- kill all of the directory
7765 * entries for the rest of the block. We will either try to
7766 * absorb it into the previous directory entry, or create a
7767 * new empty directory entry the rest of the directory block.
7768 */
7769 if (prev) {
7770 prev->rec_len += fs->blocksize - *offset;
7771 *offset = fs->blocksize;
7772 } else {
7773 dirent->rec_len = fs->blocksize - *offset;
7774 dirent->name_len = 0;
7775 dirent->inode = 0;
7776 }
7777}
7778
7779static int check_dir_block(ext2_filsys fs,
7780 struct ext2_db_entry *db,
7781 void *priv_data)
7782{
7783 struct dir_info *subdir, *dir;
7784 struct dx_dir_info *dx_dir;
7785#ifdef ENABLE_HTREE
7786 struct dx_dirblock_info *dx_db = 0;
7787#endif /* ENABLE_HTREE */
7788 struct ext2_dir_entry *dirent, *prev;
7789 ext2_dirhash_t hash;
7790 unsigned int offset = 0;
7791 int dir_modified = 0;
7792 int dot_state;
7793 blk_t block_nr = db->blk;
7794 ext2_ino_t ino = db->ino;
7795 __u16 links;
7796 struct check_dir_struct *cd;
7797 char *buf;
7798 e2fsck_t ctx;
7799 int problem;
7800 struct ext2_dx_root_info *root;
7801 struct ext2_dx_countlimit *limit;
7802 static dict_t de_dict;
7803 struct problem_context pctx;
7804 int dups_found = 0;
7805
7806 cd = (struct check_dir_struct *) priv_data;
7807 buf = cd->buf;
7808 ctx = cd->ctx;
7809
7810 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7811 return DIRENT_ABORT;
7812
7813 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
7814 return DIRENT_ABORT;
7815
7816 /*
7817 * Make sure the inode is still in use (could have been
7818 * deleted in the duplicate/bad blocks pass.
7819 */
7820 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
7821 return 0;
7822
7823 cd->pctx.ino = ino;
7824 cd->pctx.blk = block_nr;
7825 cd->pctx.blkcount = db->blockcnt;
7826 cd->pctx.ino2 = 0;
7827 cd->pctx.dirent = 0;
7828 cd->pctx.num = 0;
7829
7830 if (db->blk == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007831 if (allocate_dir_block(ctx, db, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007832 return 0;
7833 block_nr = db->blk;
7834 }
7835
7836 if (db->blockcnt)
7837 dot_state = 2;
7838 else
7839 dot_state = 0;
7840
7841 if (ctx->dirs_to_hash &&
7842 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
7843 dups_found++;
7844
7845#if 0
7846 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
7847 db->blockcnt, ino);
7848#endif
7849
7850 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
7851 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
7852 cd->pctx.errcode = 0; /* We'll handle this ourselves */
7853 if (cd->pctx.errcode) {
7854 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
7855 ctx->flags |= E2F_FLAG_ABORT;
7856 return DIRENT_ABORT;
7857 }
7858 memset(buf, 0, fs->blocksize);
7859 }
7860#ifdef ENABLE_HTREE
7861 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
7862 if (dx_dir && dx_dir->numblocks) {
7863 if (db->blockcnt >= dx_dir->numblocks) {
7864 printf("XXX should never happen!!!\n");
7865 abort();
7866 }
7867 dx_db = &dx_dir->dx_block[db->blockcnt];
7868 dx_db->type = DX_DIRBLOCK_LEAF;
7869 dx_db->phys = block_nr;
7870 dx_db->min_hash = ~0;
7871 dx_db->max_hash = 0;
7872
7873 dirent = (struct ext2_dir_entry *) buf;
7874 limit = (struct ext2_dx_countlimit *) (buf+8);
7875 if (db->blockcnt == 0) {
7876 root = (struct ext2_dx_root_info *) (buf + 24);
7877 dx_db->type = DX_DIRBLOCK_ROOT;
7878 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
7879 if ((root->reserved_zero ||
7880 root->info_length < 8 ||
7881 root->indirect_levels > 1) &&
7882 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
7883 clear_htree(ctx, ino);
7884 dx_dir->numblocks = 0;
7885 dx_db = 0;
7886 }
7887 dx_dir->hashversion = root->hash_version;
7888 dx_dir->depth = root->indirect_levels + 1;
7889 } else if ((dirent->inode == 0) &&
7890 (dirent->rec_len == fs->blocksize) &&
7891 (dirent->name_len == 0) &&
7892 (ext2fs_le16_to_cpu(limit->limit) ==
7893 ((fs->blocksize-8) /
7894 sizeof(struct ext2_dx_entry))))
7895 dx_db->type = DX_DIRBLOCK_NODE;
7896 }
7897#endif /* ENABLE_HTREE */
7898
7899 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
7900 prev = 0;
7901 do {
7902 problem = 0;
7903 dirent = (struct ext2_dir_entry *) (buf + offset);
7904 cd->pctx.dirent = dirent;
7905 cd->pctx.num = offset;
7906 if (((offset + dirent->rec_len) > fs->blocksize) ||
7907 (dirent->rec_len < 12) ||
7908 ((dirent->rec_len % 4) != 0) ||
7909 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
7910 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
7911 salvage_directory(fs, dirent, prev, &offset);
7912 dir_modified++;
7913 continue;
7914 } else
7915 goto abort_free_dict;
7916 }
7917 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
7918 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
7919 dirent->name_len = EXT2_NAME_LEN;
7920 dir_modified++;
7921 }
7922 }
7923
7924 if (dot_state == 0) {
7925 if (check_dot(ctx, dirent, ino, &cd->pctx))
7926 dir_modified++;
7927 } else if (dot_state == 1) {
7928 dir = e2fsck_get_dir_info(ctx, ino);
7929 if (!dir) {
7930 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
7931 goto abort_free_dict;
7932 }
7933 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
7934 dir_modified++;
7935 } else if (dirent->inode == ino) {
7936 problem = PR_2_LINK_DOT;
7937 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
7938 dirent->inode = 0;
7939 dir_modified++;
7940 goto next;
7941 }
7942 }
7943 if (!dirent->inode)
7944 goto next;
7945
7946 /*
7947 * Make sure the inode listed is a legal one.
7948 */
7949 if (((dirent->inode != EXT2_ROOT_INO) &&
7950 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
7951 (dirent->inode > fs->super->s_inodes_count)) {
7952 problem = PR_2_BAD_INO;
7953 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
7954 dirent->inode))) {
7955 /*
7956 * If the inode is unused, offer to clear it.
7957 */
7958 problem = PR_2_UNUSED_INODE;
7959 } else if (ctx->inode_bb_map &&
7960 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
7961 dirent->inode))) {
7962 /*
7963 * If the inode is in a bad block, offer to
7964 * clear it.
7965 */
7966 problem = PR_2_BB_INODE;
7967 } else if ((dot_state > 1) &&
7968 ((dirent->name_len & 0xFF) == 1) &&
7969 (dirent->name[0] == '.')) {
7970 /*
7971 * If there's a '.' entry in anything other
7972 * than the first directory entry, it's a
7973 * duplicate entry that should be removed.
7974 */
7975 problem = PR_2_DUP_DOT;
7976 } else if ((dot_state > 1) &&
7977 ((dirent->name_len & 0xFF) == 2) &&
7978 (dirent->name[0] == '.') &&
7979 (dirent->name[1] == '.')) {
7980 /*
7981 * If there's a '..' entry in anything other
7982 * than the second directory entry, it's a
7983 * duplicate entry that should be removed.
7984 */
7985 problem = PR_2_DUP_DOT_DOT;
7986 } else if ((dot_state > 1) &&
7987 (dirent->inode == EXT2_ROOT_INO)) {
7988 /*
7989 * Don't allow links to the root directory.
7990 * We check this specially to make sure we
7991 * catch this error case even if the root
7992 * directory hasn't been created yet.
7993 */
7994 problem = PR_2_LINK_ROOT;
7995 } else if ((dot_state > 1) &&
7996 (dirent->name_len & 0xFF) == 0) {
7997 /*
7998 * Don't allow zero-length directory names.
7999 */
8000 problem = PR_2_NULL_NAME;
8001 }
8002
8003 if (problem) {
8004 if (fix_problem(ctx, problem, &cd->pctx)) {
8005 dirent->inode = 0;
8006 dir_modified++;
8007 goto next;
8008 } else {
8009 ext2fs_unmark_valid(fs);
8010 if (problem == PR_2_BAD_INO)
8011 goto next;
8012 }
8013 }
8014
8015 /*
8016 * If the inode was marked as having bad fields in
8017 * pass1, process it and offer to fix/clear it.
8018 * (We wait until now so that we can display the
8019 * pathname to the user.)
8020 */
8021 if (ctx->inode_bad_map &&
8022 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
8023 dirent->inode)) {
8024 if (e2fsck_process_bad_inode(ctx, ino,
8025 dirent->inode,
8026 buf + fs->blocksize)) {
8027 dirent->inode = 0;
8028 dir_modified++;
8029 goto next;
8030 }
8031 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8032 return DIRENT_ABORT;
8033 }
8034
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008035 if (check_name(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008036 dir_modified++;
8037
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008038 if (check_filetype(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008039 dir_modified++;
8040
8041#ifdef ENABLE_HTREE
8042 if (dx_db) {
8043 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
8044 (dirent->name_len & 0xFF),
8045 fs->super->s_hash_seed, &hash, 0);
8046 if (hash < dx_db->min_hash)
8047 dx_db->min_hash = hash;
8048 if (hash > dx_db->max_hash)
8049 dx_db->max_hash = hash;
8050 }
8051#endif
8052
8053 /*
8054 * If this is a directory, then mark its parent in its
8055 * dir_info structure. If the parent field is already
8056 * filled in, then this directory has more than one
8057 * hard link. We assume the first link is correct,
8058 * and ask the user if he/she wants to clear this one.
8059 */
8060 if ((dot_state > 1) &&
8061 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8062 dirent->inode))) {
8063 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
8064 if (!subdir) {
8065 cd->pctx.ino = dirent->inode;
8066 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
8067 goto abort_free_dict;
8068 }
8069 if (subdir->parent) {
8070 cd->pctx.ino2 = subdir->parent;
8071 if (fix_problem(ctx, PR_2_LINK_DIR,
8072 &cd->pctx)) {
8073 dirent->inode = 0;
8074 dir_modified++;
8075 goto next;
8076 }
8077 cd->pctx.ino2 = 0;
8078 } else
8079 subdir->parent = ino;
8080 }
8081
8082 if (dups_found) {
8083 ;
8084 } else if (dict_lookup(&de_dict, dirent)) {
8085 clear_problem_context(&pctx);
8086 pctx.ino = ino;
8087 pctx.dirent = dirent;
8088 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
8089 if (!ctx->dirs_to_hash)
8090 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
8091 if (ctx->dirs_to_hash)
8092 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8093 dups_found++;
8094 } else
8095 dict_alloc_insert(&de_dict, dirent, dirent);
8096
8097 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
8098 &links);
8099 if (links > 1)
8100 ctx->fs_links_count++;
8101 ctx->fs_total_count++;
8102 next:
8103 prev = dirent;
8104 offset += dirent->rec_len;
8105 dot_state++;
8106 } while (offset < fs->blocksize);
8107#if 0
8108 printf("\n");
8109#endif
8110#ifdef ENABLE_HTREE
8111 if (dx_db) {
8112#ifdef DX_DEBUG
8113 printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
8114 db->blockcnt, dx_db->type,
8115 dx_db->min_hash, dx_db->max_hash);
8116#endif
8117 cd->pctx.dir = cd->pctx.ino;
8118 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
8119 (dx_db->type == DX_DIRBLOCK_NODE))
8120 parse_int_node(fs, db, cd, dx_dir, buf);
8121 }
8122#endif /* ENABLE_HTREE */
8123 if (offset != fs->blocksize) {
8124 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
8125 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
8126 dirent->rec_len = cd->pctx.num;
8127 dir_modified++;
8128 }
8129 }
8130 if (dir_modified) {
8131 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
8132 if (cd->pctx.errcode) {
8133 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
8134 &cd->pctx))
8135 goto abort_free_dict;
8136 }
8137 ext2fs_mark_changed(fs);
8138 }
8139 dict_free_nodes(&de_dict);
8140 return 0;
8141abort_free_dict:
8142 dict_free_nodes(&de_dict);
8143 ctx->flags |= E2F_FLAG_ABORT;
8144 return DIRENT_ABORT;
8145}
8146
8147/*
8148 * This function is called to deallocate a block, and is an interator
8149 * functioned called by deallocate inode via ext2fs_iterate_block().
8150 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008151static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00008152 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
8153 blk_t ref_block FSCK_ATTR((unused)),
8154 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008155 void *priv_data)
8156{
8157 e2fsck_t ctx = (e2fsck_t) priv_data;
8158
8159 if (HOLE_BLKADDR(*block_nr))
8160 return 0;
8161 if ((*block_nr < fs->super->s_first_data_block) ||
8162 (*block_nr >= fs->super->s_blocks_count))
8163 return 0;
8164 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
8165 ext2fs_block_alloc_stats(fs, *block_nr, -1);
8166 return 0;
8167}
8168
8169/*
8170 * This fuction deallocates an inode
8171 */
8172static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
8173{
8174 ext2_filsys fs = ctx->fs;
8175 struct ext2_inode inode;
8176 struct problem_context pctx;
8177 __u32 count;
8178
8179 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
8180 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
8181 inode.i_links_count = 0;
8182 inode.i_dtime = time(0);
8183 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
8184 clear_problem_context(&pctx);
8185 pctx.ino = ino;
8186
8187 /*
8188 * Fix up the bitmaps...
8189 */
8190 e2fsck_read_bitmaps(ctx);
8191 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
8192 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
8193 if (ctx->inode_bad_map)
8194 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8195 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
8196
8197 if (inode.i_file_acl &&
8198 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
8199 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
8200 block_buf, -1, &count);
8201 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
8202 pctx.errcode = 0;
8203 count = 1;
8204 }
8205 if (pctx.errcode) {
8206 pctx.blk = inode.i_file_acl;
8207 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
8208 ctx->flags |= E2F_FLAG_ABORT;
8209 return;
8210 }
8211 if (count == 0) {
8212 ext2fs_unmark_block_bitmap(ctx->block_found_map,
8213 inode.i_file_acl);
8214 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
8215 }
8216 inode.i_file_acl = 0;
8217 }
8218
8219 if (!ext2fs_inode_has_valid_blocks(&inode))
8220 return;
8221
8222 if (LINUX_S_ISREG(inode.i_mode) &&
8223 (inode.i_size_high || inode.i_size & 0x80000000UL))
8224 ctx->large_files--;
8225
8226 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
8227 deallocate_inode_block, ctx);
8228 if (pctx.errcode) {
8229 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
8230 ctx->flags |= E2F_FLAG_ABORT;
8231 return;
8232 }
8233}
8234
8235/*
8236 * This fuction clears the htree flag on an inode
8237 */
8238static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
8239{
8240 struct ext2_inode inode;
8241
8242 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
8243 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
8244 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
8245 if (ctx->dirs_to_hash)
8246 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8247}
8248
8249
8250static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
8251 ext2_ino_t ino, char *buf)
8252{
8253 ext2_filsys fs = ctx->fs;
8254 struct ext2_inode inode;
8255 int inode_modified = 0;
8256 int not_fixed = 0;
8257 unsigned char *frag, *fsize;
8258 struct problem_context pctx;
8259 int problem = 0;
8260
8261 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
8262
8263 clear_problem_context(&pctx);
8264 pctx.ino = ino;
8265 pctx.dir = dir;
8266 pctx.inode = &inode;
8267
8268 if (inode.i_file_acl &&
8269 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
8270 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
8271 inode.i_file_acl = 0;
8272#ifdef EXT2FS_ENABLE_SWAPFS
8273 /*
8274 * This is a special kludge to deal with long symlinks
8275 * on big endian systems. i_blocks had already been
8276 * decremented earlier in pass 1, but since i_file_acl
8277 * hadn't yet been cleared, ext2fs_read_inode()
8278 * assumed that the file was short symlink and would
8279 * not have byte swapped i_block[0]. Hence, we have
8280 * to byte-swap it here.
8281 */
8282 if (LINUX_S_ISLNK(inode.i_mode) &&
8283 (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
8284 (inode.i_blocks == fs->blocksize >> 9))
8285 inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
8286#endif
8287 inode_modified++;
8288 } else
8289 not_fixed++;
8290
8291 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
8292 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
8293 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
8294 !(LINUX_S_ISSOCK(inode.i_mode)))
8295 problem = PR_2_BAD_MODE;
8296 else if (LINUX_S_ISCHR(inode.i_mode)
8297 && !e2fsck_pass1_check_device_inode(fs, &inode))
8298 problem = PR_2_BAD_CHAR_DEV;
8299 else if (LINUX_S_ISBLK(inode.i_mode)
8300 && !e2fsck_pass1_check_device_inode(fs, &inode))
8301 problem = PR_2_BAD_BLOCK_DEV;
8302 else if (LINUX_S_ISFIFO(inode.i_mode)
8303 && !e2fsck_pass1_check_device_inode(fs, &inode))
8304 problem = PR_2_BAD_FIFO;
8305 else if (LINUX_S_ISSOCK(inode.i_mode)
8306 && !e2fsck_pass1_check_device_inode(fs, &inode))
8307 problem = PR_2_BAD_SOCKET;
8308 else if (LINUX_S_ISLNK(inode.i_mode)
8309 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
8310 problem = PR_2_INVALID_SYMLINK;
8311 }
8312
8313 if (problem) {
8314 if (fix_problem(ctx, problem, &pctx)) {
8315 deallocate_inode(ctx, ino, 0);
8316 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8317 return 0;
8318 return 1;
8319 } else
8320 not_fixed++;
8321 problem = 0;
8322 }
8323
8324 if (inode.i_faddr) {
8325 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
8326 inode.i_faddr = 0;
8327 inode_modified++;
8328 } else
8329 not_fixed++;
8330 }
8331
8332 switch (fs->super->s_creator_os) {
8333 case EXT2_OS_LINUX:
8334 frag = &inode.osd2.linux2.l_i_frag;
8335 fsize = &inode.osd2.linux2.l_i_fsize;
8336 break;
8337 case EXT2_OS_HURD:
8338 frag = &inode.osd2.hurd2.h_i_frag;
8339 fsize = &inode.osd2.hurd2.h_i_fsize;
8340 break;
8341 case EXT2_OS_MASIX:
8342 frag = &inode.osd2.masix2.m_i_frag;
8343 fsize = &inode.osd2.masix2.m_i_fsize;
8344 break;
8345 default:
8346 frag = fsize = 0;
8347 }
8348 if (frag && *frag) {
8349 pctx.num = *frag;
8350 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
8351 *frag = 0;
8352 inode_modified++;
8353 } else
8354 not_fixed++;
8355 pctx.num = 0;
8356 }
8357 if (fsize && *fsize) {
8358 pctx.num = *fsize;
8359 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
8360 *fsize = 0;
8361 inode_modified++;
8362 } else
8363 not_fixed++;
8364 pctx.num = 0;
8365 }
8366
8367 if (inode.i_file_acl &&
8368 ((inode.i_file_acl < fs->super->s_first_data_block) ||
8369 (inode.i_file_acl >= fs->super->s_blocks_count))) {
8370 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
8371 inode.i_file_acl = 0;
8372 inode_modified++;
8373 } else
8374 not_fixed++;
8375 }
8376 if (inode.i_dir_acl &&
8377 LINUX_S_ISDIR(inode.i_mode)) {
8378 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
8379 inode.i_dir_acl = 0;
8380 inode_modified++;
8381 } else
8382 not_fixed++;
8383 }
8384
8385 if (inode_modified)
8386 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
8387 if (!not_fixed)
8388 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8389 return 0;
8390}
8391
8392
8393/*
8394 * allocate_dir_block --- this function allocates a new directory
8395 * block for a particular inode; this is done if a directory has
8396 * a "hole" in it, or if a directory has a illegal block number
8397 * that was zeroed out and now needs to be replaced.
8398 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008399static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008400 struct problem_context *pctx)
8401{
8402 ext2_filsys fs = ctx->fs;
8403 blk_t blk;
8404 char *block;
8405 struct ext2_inode inode;
8406
8407 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
8408 return 1;
8409
8410 /*
8411 * Read the inode and block bitmaps in; we'll be messing with
8412 * them.
8413 */
8414 e2fsck_read_bitmaps(ctx);
8415
8416 /*
8417 * First, find a free block
8418 */
8419 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8420 if (pctx->errcode) {
8421 pctx->str = "ext2fs_new_block";
8422 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8423 return 1;
8424 }
8425 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8426 ext2fs_mark_block_bitmap(fs->block_map, blk);
8427 ext2fs_mark_bb_dirty(fs);
8428
8429 /*
8430 * Now let's create the actual data block for the inode
8431 */
8432 if (db->blockcnt)
8433 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
8434 else
8435 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
8436 EXT2_ROOT_INO, &block);
8437
8438 if (pctx->errcode) {
8439 pctx->str = "ext2fs_new_dir_block";
8440 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8441 return 1;
8442 }
8443
8444 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
8445 ext2fs_free_mem(&block);
8446 if (pctx->errcode) {
8447 pctx->str = "ext2fs_write_dir_block";
8448 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8449 return 1;
8450 }
8451
8452 /*
8453 * Update the inode block count
8454 */
8455 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
8456 inode.i_blocks += fs->blocksize / 512;
8457 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
8458 inode.i_size = (db->blockcnt+1) * fs->blocksize;
8459 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
8460
8461 /*
8462 * Finally, update the block pointers for the inode
8463 */
8464 db->blk = blk;
8465 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
8466 0, update_dir_block, db);
8467 if (pctx->errcode) {
8468 pctx->str = "ext2fs_block_iterate";
8469 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8470 return 1;
8471 }
8472
8473 return 0;
8474}
8475
8476/*
8477 * This is a helper function for allocate_dir_block().
8478 */
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00008479static int update_dir_block(ext2_filsys fs FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008480 blk_t *block_nr,
8481 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00008482 blk_t ref_block FSCK_ATTR((unused)),
8483 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008484 void *priv_data)
8485{
8486 struct ext2_db_entry *db;
8487
8488 db = (struct ext2_db_entry *) priv_data;
8489 if (db->blockcnt == (int) blockcnt) {
8490 *block_nr = db->blk;
8491 return BLOCK_CHANGED;
8492 }
8493 return 0;
8494}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008495
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008496/*
8497 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
8498 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008499 * Pass #3 assures that all directories are connected to the
8500 * filesystem tree, using the following algorithm:
8501 *
8502 * First, the root directory is checked to make sure it exists; if
8503 * not, e2fsck will offer to create a new one. It is then marked as
8504 * "done".
8505 *
8506 * Then, pass3 interates over all directory inodes; for each directory
8507 * it attempts to trace up the filesystem tree, using dirinfo.parent
8508 * until it reaches a directory which has been marked "done". If it
8509 * can not do so, then the directory must be disconnected, and e2fsck
8510 * will offer to reconnect it to /lost+found. While it is chasing
8511 * parent pointers up the filesystem tree, if pass3 sees a directory
8512 * twice, then it has detected a filesystem loop, and it will again
8513 * offer to reconnect the directory to /lost+found in to break the
8514 * filesystem loop.
8515 *
8516 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
8517 * reconnect inodes to /lost+found; this subroutine is also used by
8518 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
8519 * is responsible for creating /lost+found if it does not exist.
8520 *
8521 * Pass 3 frees the following data structures:
8522 * - The dirinfo directory information cache.
8523 */
8524
8525static void check_root(e2fsck_t ctx);
8526static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8527 struct problem_context *pctx);
8528static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
8529
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008530static ext2fs_inode_bitmap inode_loop_detect;
8531static ext2fs_inode_bitmap inode_done_map;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008532
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008533static void e2fsck_pass3(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008534{
8535 ext2_filsys fs = ctx->fs;
8536 int i;
8537#ifdef RESOURCE_TRACK
8538 struct resource_track rtrack;
8539#endif
8540 struct problem_context pctx;
8541 struct dir_info *dir;
8542 unsigned long maxdirs, count;
8543
8544#ifdef RESOURCE_TRACK
8545 init_resource_track(&rtrack);
8546#endif
8547
8548 clear_problem_context(&pctx);
8549
8550#ifdef MTRACE
8551 mtrace_print("Pass 3");
8552#endif
8553
8554 if (!(ctx->options & E2F_OPT_PREEN))
8555 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
8556
8557 /*
8558 * Allocate some bitmaps to do loop detection.
8559 */
8560 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
8561 &inode_done_map);
8562 if (pctx.errcode) {
8563 pctx.num = 2;
8564 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
8565 ctx->flags |= E2F_FLAG_ABORT;
8566 goto abort_exit;
8567 }
8568#ifdef RESOURCE_TRACK
8569 if (ctx->options & E2F_OPT_TIME) {
8570 e2fsck_clear_progbar(ctx);
8571 print_resource_track(_("Peak memory"), &ctx->global_rtrack);
8572 }
8573#endif
8574
8575 check_root(ctx);
8576 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8577 goto abort_exit;
8578
8579 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
8580
8581 maxdirs = e2fsck_get_num_dirinfo(ctx);
8582 count = 1;
8583
8584 if (ctx->progress)
8585 if ((ctx->progress)(ctx, 3, 0, maxdirs))
8586 goto abort_exit;
8587
8588 for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
8589 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8590 goto abort_exit;
8591 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
8592 goto abort_exit;
8593 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
8594 if (check_directory(ctx, dir, &pctx))
8595 goto abort_exit;
8596 }
8597
8598 /*
8599 * Force the creation of /lost+found if not present
8600 */
8601 if ((ctx->flags & E2F_OPT_READONLY) == 0)
8602 e2fsck_get_lost_and_found(ctx, 1);
8603
8604 /*
8605 * If there are any directories that need to be indexed or
8606 * optimized, do it here.
8607 */
8608 e2fsck_rehash_directories(ctx);
8609
8610abort_exit:
8611 e2fsck_free_dir_info(ctx);
Rob Landleye7c43b62006-03-01 16:39:45 +00008612 ext2fs_free_inode_bitmap(inode_loop_detect);
8613 inode_loop_detect = 0;
8614 ext2fs_free_inode_bitmap(inode_done_map);
8615 inode_done_map = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008616
8617#ifdef RESOURCE_TRACK
8618 if (ctx->options & E2F_OPT_TIME2) {
8619 e2fsck_clear_progbar(ctx);
8620 print_resource_track(_("Pass 3"), &rtrack);
8621 }
8622#endif
8623}
8624
8625/*
8626 * This makes sure the root inode is present; if not, we ask if the
8627 * user wants us to create it. Not creating it is a fatal error.
8628 */
8629static void check_root(e2fsck_t ctx)
8630{
8631 ext2_filsys fs = ctx->fs;
8632 blk_t blk;
8633 struct ext2_inode inode;
8634 char * block;
8635 struct problem_context pctx;
8636
8637 clear_problem_context(&pctx);
8638
8639 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
8640 /*
8641 * If the root inode is not a directory, die here. The
8642 * user must have answered 'no' in pass1 when we
8643 * offered to clear it.
8644 */
8645 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8646 EXT2_ROOT_INO))) {
8647 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
8648 ctx->flags |= E2F_FLAG_ABORT;
8649 }
8650 return;
8651 }
8652
8653 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
8654 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
8655 ctx->flags |= E2F_FLAG_ABORT;
8656 return;
8657 }
8658
8659 e2fsck_read_bitmaps(ctx);
8660
8661 /*
8662 * First, find a free block
8663 */
8664 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8665 if (pctx.errcode) {
8666 pctx.str = "ext2fs_new_block";
8667 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8668 ctx->flags |= E2F_FLAG_ABORT;
8669 return;
8670 }
8671 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8672 ext2fs_mark_block_bitmap(fs->block_map, blk);
8673 ext2fs_mark_bb_dirty(fs);
8674
8675 /*
8676 * Now let's create the actual data block for the inode
8677 */
8678 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
8679 &block);
8680 if (pctx.errcode) {
8681 pctx.str = "ext2fs_new_dir_block";
8682 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8683 ctx->flags |= E2F_FLAG_ABORT;
8684 return;
8685 }
8686
8687 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
8688 if (pctx.errcode) {
8689 pctx.str = "ext2fs_write_dir_block";
8690 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8691 ctx->flags |= E2F_FLAG_ABORT;
8692 return;
8693 }
8694 ext2fs_free_mem(&block);
8695
8696 /*
8697 * Set up the inode structure
8698 */
8699 memset(&inode, 0, sizeof(inode));
8700 inode.i_mode = 040755;
8701 inode.i_size = fs->blocksize;
8702 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
8703 inode.i_links_count = 2;
8704 inode.i_blocks = fs->blocksize / 512;
8705 inode.i_block[0] = blk;
8706
8707 /*
8708 * Write out the inode.
8709 */
8710 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
8711 if (pctx.errcode) {
8712 pctx.str = "ext2fs_write_inode";
8713 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8714 ctx->flags |= E2F_FLAG_ABORT;
8715 return;
8716 }
8717
8718 /*
8719 * Miscellaneous bookkeeping...
8720 */
8721 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
8722 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
8723 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
8724
8725 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
8726 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
8727 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
8728 ext2fs_mark_ib_dirty(fs);
8729}
8730
8731/*
8732 * This subroutine is responsible for making sure that a particular
8733 * directory is connected to the root; if it isn't we trace it up as
8734 * far as we can go, and then offer to connect the resulting parent to
8735 * the lost+found. We have to do loop detection; if we ever discover
8736 * a loop, we treat that as a disconnected directory and offer to
8737 * reparent it to lost+found.
8738 *
8739 * However, loop detection is expensive, because for very large
8740 * filesystems, the inode_loop_detect bitmap is huge, and clearing it
8741 * is non-trivial. Loops in filesystems are also a rare error case,
8742 * and we shouldn't optimize for error cases. So we try two passes of
8743 * the algorithm. The first time, we ignore loop detection and merely
8744 * increment a counter; if the counter exceeds some extreme threshold,
8745 * then we try again with the loop detection bitmap enabled.
8746 */
8747static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8748 struct problem_context *pctx)
8749{
8750 ext2_filsys fs = ctx->fs;
8751 struct dir_info *p = dir;
8752 int loop_pass = 0, parent_count = 0;
8753
8754 if (!p)
8755 return 0;
8756
8757 while (1) {
8758 /*
8759 * Mark this inode as being "done"; by the time we
8760 * return from this function, the inode we either be
8761 * verified as being connected to the directory tree,
8762 * or we will have offered to reconnect this to
8763 * lost+found.
8764 *
8765 * If it was marked done already, then we've reached a
8766 * parent we've already checked.
8767 */
8768 if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
8769 break;
8770
8771 /*
8772 * If this directory doesn't have a parent, or we've
8773 * seen the parent once already, then offer to
8774 * reparent it to lost+found
8775 */
8776 if (!p->parent ||
8777 (loop_pass &&
8778 (ext2fs_test_inode_bitmap(inode_loop_detect,
8779 p->parent)))) {
8780 pctx->ino = p->ino;
8781 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
8782 if (e2fsck_reconnect_file(ctx, pctx->ino))
8783 ext2fs_unmark_valid(fs);
8784 else {
8785 p = e2fsck_get_dir_info(ctx, pctx->ino);
8786 p->parent = ctx->lost_and_found;
8787 fix_dotdot(ctx, p, ctx->lost_and_found);
8788 }
8789 }
8790 break;
8791 }
8792 p = e2fsck_get_dir_info(ctx, p->parent);
8793 if (!p) {
8794 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
8795 return 0;
8796 }
8797 if (loop_pass) {
8798 ext2fs_mark_inode_bitmap(inode_loop_detect,
8799 p->ino);
8800 } else if (parent_count++ > 2048) {
8801 /*
8802 * If we've run into a path depth that's
8803 * greater than 2048, try again with the inode
8804 * loop bitmap turned on and start from the
8805 * top.
8806 */
8807 loop_pass = 1;
8808 if (inode_loop_detect)
8809 ext2fs_clear_inode_bitmap(inode_loop_detect);
8810 else {
8811 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
8812 if (pctx->errcode) {
8813 pctx->num = 1;
8814 fix_problem(ctx,
8815 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
8816 ctx->flags |= E2F_FLAG_ABORT;
8817 return -1;
8818 }
8819 }
8820 p = dir;
8821 }
8822 }
8823
8824 /*
8825 * Make sure that .. and the parent directory are the same;
8826 * offer to fix it if not.
8827 */
8828 if (dir->parent != dir->dotdot) {
8829 pctx->ino = dir->ino;
8830 pctx->ino2 = dir->dotdot;
8831 pctx->dir = dir->parent;
8832 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
8833 fix_dotdot(ctx, dir, dir->parent);
8834 }
8835 return 0;
8836}
8837
8838/*
8839 * This routine gets the lost_and_found inode, making it a directory
8840 * if necessary
8841 */
8842ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
8843{
8844 ext2_filsys fs = ctx->fs;
8845 ext2_ino_t ino;
8846 blk_t blk;
8847 errcode_t retval;
8848 struct ext2_inode inode;
8849 char * block;
8850 static const char name[] = "lost+found";
8851 struct problem_context pctx;
8852 struct dir_info *dirinfo;
8853
8854 if (ctx->lost_and_found)
8855 return ctx->lost_and_found;
8856
8857 clear_problem_context(&pctx);
8858
8859 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
8860 sizeof(name)-1, 0, &ino);
8861 if (retval && !fix)
8862 return 0;
8863 if (!retval) {
8864 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
8865 ctx->lost_and_found = ino;
8866 return ino;
8867 }
8868
8869 /* Lost+found isn't a directory! */
8870 if (!fix)
8871 return 0;
8872 pctx.ino = ino;
8873 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
8874 return 0;
8875
8876 /* OK, unlink the old /lost+found file. */
8877 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
8878 if (pctx.errcode) {
8879 pctx.str = "ext2fs_unlink";
8880 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
8881 return 0;
8882 }
8883 dirinfo = e2fsck_get_dir_info(ctx, ino);
8884 if (dirinfo)
8885 dirinfo->parent = 0;
8886 e2fsck_adjust_inode_count(ctx, ino, -1);
8887 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
8888 pctx.errcode = retval;
8889 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
8890 }
8891 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
8892 return 0;
8893
8894 /*
8895 * Read the inode and block bitmaps in; we'll be messing with
8896 * them.
8897 */
8898 e2fsck_read_bitmaps(ctx);
8899
8900 /*
8901 * First, find a free block
8902 */
8903 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8904 if (retval) {
8905 pctx.errcode = retval;
8906 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
8907 return 0;
8908 }
8909 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8910 ext2fs_block_alloc_stats(fs, blk, +1);
8911
8912 /*
8913 * Next find a free inode.
8914 */
8915 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
8916 ctx->inode_used_map, &ino);
8917 if (retval) {
8918 pctx.errcode = retval;
8919 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
8920 return 0;
8921 }
8922 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
8923 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
8924 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
8925
8926 /*
8927 * Now let's create the actual data block for the inode
8928 */
8929 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
8930 if (retval) {
8931 pctx.errcode = retval;
8932 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
8933 return 0;
8934 }
8935
8936 retval = ext2fs_write_dir_block(fs, blk, block);
8937 ext2fs_free_mem(&block);
8938 if (retval) {
8939 pctx.errcode = retval;
8940 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
8941 return 0;
8942 }
8943
8944 /*
8945 * Set up the inode structure
8946 */
8947 memset(&inode, 0, sizeof(inode));
8948 inode.i_mode = 040700;
8949 inode.i_size = fs->blocksize;
8950 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
8951 inode.i_links_count = 2;
8952 inode.i_blocks = fs->blocksize / 512;
8953 inode.i_block[0] = blk;
8954
8955 /*
8956 * Next, write out the inode.
8957 */
8958 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
8959 if (pctx.errcode) {
8960 pctx.str = "ext2fs_write_inode";
8961 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
8962 return 0;
8963 }
8964 /*
8965 * Finally, create the directory link
8966 */
8967 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
8968 if (pctx.errcode) {
8969 pctx.str = "ext2fs_link";
8970 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
8971 return 0;
8972 }
8973
8974 /*
8975 * Miscellaneous bookkeeping that needs to be kept straight.
8976 */
8977 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
8978 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
8979 ext2fs_icount_store(ctx->inode_count, ino, 2);
8980 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
8981 ctx->lost_and_found = ino;
8982#if 0
8983 printf("/lost+found created; inode #%lu\n", ino);
8984#endif
8985 return ino;
8986}
8987
8988/*
8989 * This routine will connect a file to lost+found
8990 */
8991int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
8992{
8993 ext2_filsys fs = ctx->fs;
8994 errcode_t retval;
8995 char name[80];
8996 struct problem_context pctx;
8997 struct ext2_inode inode;
8998 int file_type = 0;
8999
9000 clear_problem_context(&pctx);
9001 pctx.ino = ino;
9002
9003 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
9004 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
9005 ctx->bad_lost_and_found++;
9006 }
9007 if (ctx->bad_lost_and_found) {
9008 fix_problem(ctx, PR_3_NO_LPF, &pctx);
9009 return 1;
9010 }
9011
9012 sprintf(name, "#%u", ino);
9013 if (ext2fs_read_inode(fs, ino, &inode) == 0)
9014 file_type = ext2_file_type(inode.i_mode);
9015 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
9016 if (retval == EXT2_ET_DIR_NO_SPACE) {
9017 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
9018 return 1;
9019 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
9020 1, 0);
9021 if (retval) {
9022 pctx.errcode = retval;
9023 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
9024 return 1;
9025 }
9026 retval = ext2fs_link(fs, ctx->lost_and_found, name,
9027 ino, file_type);
9028 }
9029 if (retval) {
9030 pctx.errcode = retval;
9031 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
9032 return 1;
9033 }
9034 e2fsck_adjust_inode_count(ctx, ino, 1);
9035
9036 return 0;
9037}
9038
9039/*
9040 * Utility routine to adjust the inode counts on an inode.
9041 */
9042errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
9043{
9044 ext2_filsys fs = ctx->fs;
9045 errcode_t retval;
9046 struct ext2_inode inode;
9047
9048 if (!ino)
9049 return 0;
9050
9051 retval = ext2fs_read_inode(fs, ino, &inode);
9052 if (retval)
9053 return retval;
9054
9055#if 0
9056 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
9057 inode.i_links_count);
9058#endif
9059
9060 if (adj == 1) {
9061 ext2fs_icount_increment(ctx->inode_count, ino, 0);
9062 if (inode.i_links_count == (__u16) ~0)
9063 return 0;
9064 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
9065 inode.i_links_count++;
9066 } else if (adj == -1) {
9067 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
9068 if (inode.i_links_count == 0)
9069 return 0;
9070 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
9071 inode.i_links_count--;
9072 }
9073
9074 retval = ext2fs_write_inode(fs, ino, &inode);
9075 if (retval)
9076 return retval;
9077
9078 return 0;
9079}
9080
9081/*
9082 * Fix parent --- this routine fixes up the parent of a directory.
9083 */
9084struct fix_dotdot_struct {
9085 ext2_filsys fs;
9086 ext2_ino_t parent;
9087 int done;
9088 e2fsck_t ctx;
9089};
9090
9091static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00009092 int offset FSCK_ATTR((unused)),
9093 int blocksize FSCK_ATTR((unused)),
9094 char *buf FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009095 void *priv_data)
9096{
9097 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
9098 errcode_t retval;
9099 struct problem_context pctx;
9100
9101 if ((dirent->name_len & 0xFF) != 2)
9102 return 0;
9103 if (strncmp(dirent->name, "..", 2))
9104 return 0;
9105
9106 clear_problem_context(&pctx);
9107
9108 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
9109 if (retval) {
9110 pctx.errcode = retval;
9111 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9112 }
9113 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
9114 if (retval) {
9115 pctx.errcode = retval;
9116 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9117 }
9118 dirent->inode = fp->parent;
9119
9120 fp->done++;
9121 return DIRENT_ABORT | DIRENT_CHANGED;
9122}
9123
9124static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
9125{
9126 ext2_filsys fs = ctx->fs;
9127 errcode_t retval;
9128 struct fix_dotdot_struct fp;
9129 struct problem_context pctx;
9130
9131 fp.fs = fs;
9132 fp.parent = parent;
9133 fp.done = 0;
9134 fp.ctx = ctx;
9135
9136#if 0
9137 printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent);
9138#endif
9139
9140 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
9141 0, fix_dotdot_proc, &fp);
9142 if (retval || !fp.done) {
9143 clear_problem_context(&pctx);
9144 pctx.ino = dir->ino;
9145 pctx.errcode = retval;
9146 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
9147 PR_3_FIX_PARENT_NOFIND, &pctx);
9148 ext2fs_unmark_valid(fs);
9149 }
9150 dir->dotdot = parent;
9151
9152 return;
9153}
9154
9155/*
9156 * These routines are responsible for expanding a /lost+found if it is
9157 * too small.
9158 */
9159
9160struct expand_dir_struct {
9161 int num;
9162 int guaranteed_size;
9163 int newblocks;
9164 int last_block;
9165 errcode_t err;
9166 e2fsck_t ctx;
9167};
9168
9169static int expand_dir_proc(ext2_filsys fs,
9170 blk_t *blocknr,
9171 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00009172 blk_t ref_block FSCK_ATTR((unused)),
9173 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009174 void *priv_data)
9175{
9176 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
9177 blk_t new_blk;
9178 static blk_t last_blk = 0;
9179 char *block;
9180 errcode_t retval;
9181 e2fsck_t ctx;
9182
9183 ctx = es->ctx;
9184
9185 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
9186 return BLOCK_ABORT;
9187
9188 if (blockcnt > 0)
9189 es->last_block = blockcnt;
9190 if (*blocknr) {
9191 last_blk = *blocknr;
9192 return 0;
9193 }
9194 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
9195 &new_blk);
9196 if (retval) {
9197 es->err = retval;
9198 return BLOCK_ABORT;
9199 }
9200 if (blockcnt > 0) {
9201 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
9202 if (retval) {
9203 es->err = retval;
9204 return BLOCK_ABORT;
9205 }
9206 es->num--;
9207 retval = ext2fs_write_dir_block(fs, new_blk, block);
9208 } else {
9209 retval = ext2fs_get_mem(fs->blocksize, &block);
9210 if (retval) {
9211 es->err = retval;
9212 return BLOCK_ABORT;
9213 }
9214 memset(block, 0, fs->blocksize);
9215 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
9216 }
9217 if (retval) {
9218 es->err = retval;
9219 return BLOCK_ABORT;
9220 }
9221 ext2fs_free_mem(&block);
9222 *blocknr = new_blk;
9223 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
9224 ext2fs_block_alloc_stats(fs, new_blk, +1);
9225 es->newblocks++;
9226
9227 if (es->num == 0)
9228 return (BLOCK_CHANGED | BLOCK_ABORT);
9229 else
9230 return BLOCK_CHANGED;
9231}
9232
9233errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
9234 int num, int guaranteed_size)
9235{
9236 ext2_filsys fs = ctx->fs;
9237 errcode_t retval;
9238 struct expand_dir_struct es;
9239 struct ext2_inode inode;
9240
9241 if (!(fs->flags & EXT2_FLAG_RW))
9242 return EXT2_ET_RO_FILSYS;
9243
9244 /*
9245 * Read the inode and block bitmaps in; we'll be messing with
9246 * them.
9247 */
9248 e2fsck_read_bitmaps(ctx);
9249
9250 retval = ext2fs_check_directory(fs, dir);
9251 if (retval)
9252 return retval;
9253
9254 es.num = num;
9255 es.guaranteed_size = guaranteed_size;
9256 es.last_block = 0;
9257 es.err = 0;
9258 es.newblocks = 0;
9259 es.ctx = ctx;
9260
9261 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
9262 0, expand_dir_proc, &es);
9263
9264 if (es.err)
9265 return es.err;
9266
9267 /*
9268 * Update the size and block count fields in the inode.
9269 */
9270 retval = ext2fs_read_inode(fs, dir, &inode);
9271 if (retval)
9272 return retval;
9273
9274 inode.i_size = (es.last_block + 1) * fs->blocksize;
9275 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
9276
9277 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
9278
9279 return 0;
9280}
9281
9282/*
9283 * pass4.c -- pass #4 of e2fsck: Check reference counts
9284 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009285 * Pass 4 frees the following data structures:
9286 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
9287 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
9288 */
9289
9290/*
9291 * This routine is called when an inode is not connected to the
9292 * directory tree.
9293 *
9294 * This subroutine returns 1 then the caller shouldn't bother with the
9295 * rest of the pass 4 tests.
9296 */
9297static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
9298{
9299 ext2_filsys fs = ctx->fs;
9300 struct ext2_inode inode;
9301 struct problem_context pctx;
9302
9303 e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
9304 clear_problem_context(&pctx);
9305 pctx.ino = i;
9306 pctx.inode = &inode;
9307
9308 /*
9309 * Offer to delete any zero-length files that does not have
9310 * blocks. If there is an EA block, it might have useful
9311 * information, so we won't prompt to delete it, but let it be
9312 * reconnected to lost+found.
9313 */
9314 if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
9315 LINUX_S_ISDIR(inode.i_mode))) {
9316 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
9317 ext2fs_icount_store(ctx->inode_link_info, i, 0);
9318 inode.i_links_count = 0;
9319 inode.i_dtime = time(0);
9320 e2fsck_write_inode(ctx, i, &inode,
9321 "disconnect_inode");
9322 /*
9323 * Fix up the bitmaps...
9324 */
9325 e2fsck_read_bitmaps(ctx);
9326 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
9327 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
9328 ext2fs_inode_alloc_stats2(fs, i, -1,
9329 LINUX_S_ISDIR(inode.i_mode));
9330 return 0;
9331 }
9332 }
9333
9334 /*
9335 * Prompt to reconnect.
9336 */
9337 if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
9338 if (e2fsck_reconnect_file(ctx, i))
9339 ext2fs_unmark_valid(fs);
9340 } else {
9341 /*
9342 * If we don't attach the inode, then skip the
9343 * i_links_test since there's no point in trying to
9344 * force i_links_count to zero.
9345 */
9346 ext2fs_unmark_valid(fs);
9347 return 1;
9348 }
9349 return 0;
9350}
9351
9352
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009353static void e2fsck_pass4(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009354{
9355 ext2_filsys fs = ctx->fs;
9356 ext2_ino_t i;
9357 struct ext2_inode inode;
9358#ifdef RESOURCE_TRACK
9359 struct resource_track rtrack;
9360#endif
9361 struct problem_context pctx;
9362 __u16 link_count, link_counted;
9363 char *buf = 0;
9364 int group, maxgroup;
9365
9366#ifdef RESOURCE_TRACK
9367 init_resource_track(&rtrack);
9368#endif
9369
9370#ifdef MTRACE
9371 mtrace_print("Pass 4");
9372#endif
9373
9374 clear_problem_context(&pctx);
9375
9376 if (!(ctx->options & E2F_OPT_PREEN))
9377 fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
9378
9379 group = 0;
9380 maxgroup = fs->group_desc_count;
9381 if (ctx->progress)
9382 if ((ctx->progress)(ctx, 4, 0, maxgroup))
9383 return;
9384
9385 for (i=1; i <= fs->super->s_inodes_count; i++) {
9386 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9387 return;
9388 if ((i % fs->super->s_inodes_per_group) == 0) {
9389 group++;
9390 if (ctx->progress)
9391 if ((ctx->progress)(ctx, 4, group, maxgroup))
9392 return;
9393 }
9394 if (i == EXT2_BAD_INO ||
9395 (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
9396 continue;
9397 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
9398 (ctx->inode_imagic_map &&
9399 ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) ||
9400 (ctx->inode_bb_map &&
9401 ext2fs_test_inode_bitmap(ctx->inode_bb_map, i)))
9402 continue;
9403 ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
9404 ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
9405 if (link_counted == 0) {
9406 if (!buf)
9407 buf = e2fsck_allocate_memory(ctx,
9408 fs->blocksize, "bad_inode buffer");
9409 if (e2fsck_process_bad_inode(ctx, 0, i, buf))
9410 continue;
9411 if (disconnect_inode(ctx, i))
9412 continue;
9413 ext2fs_icount_fetch(ctx->inode_link_info, i,
9414 &link_count);
9415 ext2fs_icount_fetch(ctx->inode_count, i,
9416 &link_counted);
9417 }
9418 if (link_counted != link_count) {
9419 e2fsck_read_inode(ctx, i, &inode, "pass4");
9420 pctx.ino = i;
9421 pctx.inode = &inode;
9422 if (link_count != inode.i_links_count) {
9423 pctx.num = link_count;
9424 fix_problem(ctx,
9425 PR_4_INCONSISTENT_COUNT, &pctx);
9426 }
9427 pctx.num = link_counted;
9428 if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
9429 inode.i_links_count = link_counted;
9430 e2fsck_write_inode(ctx, i, &inode, "pass4");
9431 }
9432 }
9433 }
9434 ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
9435 ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
9436 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
9437 ctx->inode_bb_map = 0;
9438 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
9439 ctx->inode_imagic_map = 0;
Rob Landleye7c43b62006-03-01 16:39:45 +00009440 ext2fs_free_mem(&buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009441#ifdef RESOURCE_TRACK
9442 if (ctx->options & E2F_OPT_TIME2) {
9443 e2fsck_clear_progbar(ctx);
9444 print_resource_track(_("Pass 4"), &rtrack);
9445 }
9446#endif
9447}
9448
9449/*
9450 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009451 */
9452
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009453#define NO_BLK ((blk_t) -1)
9454
9455static void print_bitmap_problem(e2fsck_t ctx, int problem,
9456 struct problem_context *pctx)
9457{
9458 switch (problem) {
9459 case PR_5_BLOCK_UNUSED:
9460 if (pctx->blk == pctx->blk2)
9461 pctx->blk2 = 0;
9462 else
9463 problem = PR_5_BLOCK_RANGE_UNUSED;
9464 break;
9465 case PR_5_BLOCK_USED:
9466 if (pctx->blk == pctx->blk2)
9467 pctx->blk2 = 0;
9468 else
9469 problem = PR_5_BLOCK_RANGE_USED;
9470 break;
9471 case PR_5_INODE_UNUSED:
9472 if (pctx->ino == pctx->ino2)
9473 pctx->ino2 = 0;
9474 else
9475 problem = PR_5_INODE_RANGE_UNUSED;
9476 break;
9477 case PR_5_INODE_USED:
9478 if (pctx->ino == pctx->ino2)
9479 pctx->ino2 = 0;
9480 else
9481 problem = PR_5_INODE_RANGE_USED;
9482 break;
9483 }
9484 fix_problem(ctx, problem, pctx);
9485 pctx->blk = pctx->blk2 = NO_BLK;
9486 pctx->ino = pctx->ino2 = 0;
9487}
9488
9489static void check_block_bitmaps(e2fsck_t ctx)
9490{
9491 ext2_filsys fs = ctx->fs;
9492 blk_t i;
9493 int *free_array;
9494 int group = 0;
9495 unsigned int blocks = 0;
9496 unsigned int free_blocks = 0;
9497 int group_free = 0;
9498 int actual, bitmap;
9499 struct problem_context pctx;
9500 int problem, save_problem, fixit, had_problem;
9501 errcode_t retval;
9502
9503 clear_problem_context(&pctx);
9504 free_array = (int *) e2fsck_allocate_memory(ctx,
9505 fs->group_desc_count * sizeof(int), "free block count array");
9506
9507 if ((fs->super->s_first_data_block <
9508 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
9509 (fs->super->s_blocks_count-1 >
9510 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
9511 pctx.num = 1;
9512 pctx.blk = fs->super->s_first_data_block;
9513 pctx.blk2 = fs->super->s_blocks_count -1;
9514 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
9515 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
9516 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9517
9518 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9519 return;
9520 }
9521
9522 if ((fs->super->s_first_data_block <
9523 ext2fs_get_block_bitmap_start(fs->block_map)) ||
9524 (fs->super->s_blocks_count-1 >
9525 ext2fs_get_block_bitmap_end(fs->block_map))) {
9526 pctx.num = 2;
9527 pctx.blk = fs->super->s_first_data_block;
9528 pctx.blk2 = fs->super->s_blocks_count -1;
9529 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
9530 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
9531 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9532
9533 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9534 return;
9535 }
9536
9537redo_counts:
9538 had_problem = 0;
9539 save_problem = 0;
9540 pctx.blk = pctx.blk2 = NO_BLK;
9541 for (i = fs->super->s_first_data_block;
9542 i < fs->super->s_blocks_count;
9543 i++) {
9544 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
9545 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
9546
9547 if (actual == bitmap)
9548 goto do_counts;
9549
9550 if (!actual && bitmap) {
9551 /*
9552 * Block not used, but marked in use in the bitmap.
9553 */
9554 problem = PR_5_BLOCK_UNUSED;
9555 } else {
9556 /*
9557 * Block used, but not marked in use in the bitmap.
9558 */
9559 problem = PR_5_BLOCK_USED;
9560 }
9561 if (pctx.blk == NO_BLK) {
9562 pctx.blk = pctx.blk2 = i;
9563 save_problem = problem;
9564 } else {
9565 if ((problem == save_problem) &&
9566 (pctx.blk2 == i-1))
9567 pctx.blk2++;
9568 else {
9569 print_bitmap_problem(ctx, save_problem, &pctx);
9570 pctx.blk = pctx.blk2 = i;
9571 save_problem = problem;
9572 }
9573 }
9574 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
9575 had_problem++;
9576
9577 do_counts:
9578 if (!bitmap) {
9579 group_free++;
9580 free_blocks++;
9581 }
9582 blocks ++;
9583 if ((blocks == fs->super->s_blocks_per_group) ||
9584 (i == fs->super->s_blocks_count-1)) {
9585 free_array[group] = group_free;
9586 group ++;
9587 blocks = 0;
9588 group_free = 0;
9589 if (ctx->progress)
9590 if ((ctx->progress)(ctx, 5, group,
9591 fs->group_desc_count*2))
9592 return;
9593 }
9594 }
9595 if (pctx.blk != NO_BLK)
9596 print_bitmap_problem(ctx, save_problem, &pctx);
9597 if (had_problem)
9598 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
9599 else
9600 fixit = -1;
9601 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
9602
9603 if (fixit == 1) {
9604 ext2fs_free_block_bitmap(fs->block_map);
9605 retval = ext2fs_copy_bitmap(ctx->block_found_map,
9606 &fs->block_map);
9607 if (retval) {
9608 clear_problem_context(&pctx);
9609 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
9610 ctx->flags |= E2F_FLAG_ABORT;
9611 return;
9612 }
9613 ext2fs_set_bitmap_padding(fs->block_map);
9614 ext2fs_mark_bb_dirty(fs);
9615
9616 /* Redo the counts */
9617 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
9618 memset(free_array, 0, fs->group_desc_count * sizeof(int));
9619 goto redo_counts;
9620 } else if (fixit == 0)
9621 ext2fs_unmark_valid(fs);
9622
9623 for (i = 0; i < fs->group_desc_count; i++) {
9624 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
9625 pctx.group = i;
9626 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
9627 pctx.blk2 = free_array[i];
9628
9629 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
9630 &pctx)) {
9631 fs->group_desc[i].bg_free_blocks_count =
9632 free_array[i];
9633 ext2fs_mark_super_dirty(fs);
9634 } else
9635 ext2fs_unmark_valid(fs);
9636 }
9637 }
9638 if (free_blocks != fs->super->s_free_blocks_count) {
9639 pctx.group = 0;
9640 pctx.blk = fs->super->s_free_blocks_count;
9641 pctx.blk2 = free_blocks;
9642
9643 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
9644 fs->super->s_free_blocks_count = free_blocks;
9645 ext2fs_mark_super_dirty(fs);
9646 } else
9647 ext2fs_unmark_valid(fs);
9648 }
9649 ext2fs_free_mem(&free_array);
9650}
9651
9652static void check_inode_bitmaps(e2fsck_t ctx)
9653{
9654 ext2_filsys fs = ctx->fs;
9655 ext2_ino_t i;
9656 unsigned int free_inodes = 0;
9657 int group_free = 0;
9658 int dirs_count = 0;
9659 int group = 0;
9660 unsigned int inodes = 0;
9661 int *free_array;
9662 int *dir_array;
9663 int actual, bitmap;
9664 errcode_t retval;
9665 struct problem_context pctx;
9666 int problem, save_problem, fixit, had_problem;
9667
9668 clear_problem_context(&pctx);
9669 free_array = (int *) e2fsck_allocate_memory(ctx,
9670 fs->group_desc_count * sizeof(int), "free inode count array");
9671
9672 dir_array = (int *) e2fsck_allocate_memory(ctx,
9673 fs->group_desc_count * sizeof(int), "directory count array");
9674
9675 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
9676 (fs->super->s_inodes_count >
9677 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
9678 pctx.num = 3;
9679 pctx.blk = 1;
9680 pctx.blk2 = fs->super->s_inodes_count;
9681 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
9682 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
9683 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9684
9685 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9686 return;
9687 }
9688 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
9689 (fs->super->s_inodes_count >
9690 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
9691 pctx.num = 4;
9692 pctx.blk = 1;
9693 pctx.blk2 = fs->super->s_inodes_count;
9694 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
9695 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
9696 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9697
9698 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9699 return;
9700 }
9701
9702redo_counts:
9703 had_problem = 0;
9704 save_problem = 0;
9705 pctx.ino = pctx.ino2 = 0;
9706 for (i = 1; i <= fs->super->s_inodes_count; i++) {
9707 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
9708 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
9709
9710 if (actual == bitmap)
9711 goto do_counts;
9712
9713 if (!actual && bitmap) {
9714 /*
9715 * Inode wasn't used, but marked in bitmap
9716 */
9717 problem = PR_5_INODE_UNUSED;
9718 } else /* if (actual && !bitmap) */ {
9719 /*
9720 * Inode used, but not in bitmap
9721 */
9722 problem = PR_5_INODE_USED;
9723 }
9724 if (pctx.ino == 0) {
9725 pctx.ino = pctx.ino2 = i;
9726 save_problem = problem;
9727 } else {
9728 if ((problem == save_problem) &&
9729 (pctx.ino2 == i-1))
9730 pctx.ino2++;
9731 else {
9732 print_bitmap_problem(ctx, save_problem, &pctx);
9733 pctx.ino = pctx.ino2 = i;
9734 save_problem = problem;
9735 }
9736 }
9737 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
9738 had_problem++;
9739
9740do_counts:
9741 if (!bitmap) {
9742 group_free++;
9743 free_inodes++;
9744 } else {
9745 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
9746 dirs_count++;
9747 }
9748 inodes++;
9749 if ((inodes == fs->super->s_inodes_per_group) ||
9750 (i == fs->super->s_inodes_count)) {
9751 free_array[group] = group_free;
9752 dir_array[group] = dirs_count;
9753 group ++;
9754 inodes = 0;
9755 group_free = 0;
9756 dirs_count = 0;
9757 if (ctx->progress)
9758 if ((ctx->progress)(ctx, 5,
9759 group + fs->group_desc_count,
9760 fs->group_desc_count*2))
9761 return;
9762 }
9763 }
9764 if (pctx.ino)
9765 print_bitmap_problem(ctx, save_problem, &pctx);
9766
9767 if (had_problem)
9768 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
9769 else
9770 fixit = -1;
9771 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
9772
9773 if (fixit == 1) {
9774 ext2fs_free_inode_bitmap(fs->inode_map);
9775 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
9776 &fs->inode_map);
9777 if (retval) {
9778 clear_problem_context(&pctx);
9779 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
9780 ctx->flags |= E2F_FLAG_ABORT;
9781 return;
9782 }
9783 ext2fs_set_bitmap_padding(fs->inode_map);
9784 ext2fs_mark_ib_dirty(fs);
9785
9786 /* redo counts */
9787 inodes = 0; free_inodes = 0; group_free = 0;
9788 dirs_count = 0; group = 0;
9789 memset(free_array, 0, fs->group_desc_count * sizeof(int));
9790 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
9791 goto redo_counts;
9792 } else if (fixit == 0)
9793 ext2fs_unmark_valid(fs);
9794
9795 for (i = 0; i < fs->group_desc_count; i++) {
9796 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
9797 pctx.group = i;
9798 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
9799 pctx.ino2 = free_array[i];
9800 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
9801 &pctx)) {
9802 fs->group_desc[i].bg_free_inodes_count =
9803 free_array[i];
9804 ext2fs_mark_super_dirty(fs);
9805 } else
9806 ext2fs_unmark_valid(fs);
9807 }
9808 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
9809 pctx.group = i;
9810 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
9811 pctx.ino2 = dir_array[i];
9812
9813 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
9814 &pctx)) {
9815 fs->group_desc[i].bg_used_dirs_count =
9816 dir_array[i];
9817 ext2fs_mark_super_dirty(fs);
9818 } else
9819 ext2fs_unmark_valid(fs);
9820 }
9821 }
9822 if (free_inodes != fs->super->s_free_inodes_count) {
9823 pctx.group = -1;
9824 pctx.ino = fs->super->s_free_inodes_count;
9825 pctx.ino2 = free_inodes;
9826
9827 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
9828 fs->super->s_free_inodes_count = free_inodes;
9829 ext2fs_mark_super_dirty(fs);
9830 } else
9831 ext2fs_unmark_valid(fs);
9832 }
9833 ext2fs_free_mem(&free_array);
9834 ext2fs_free_mem(&dir_array);
9835}
9836
9837static void check_inode_end(e2fsck_t ctx)
9838{
9839 ext2_filsys fs = ctx->fs;
9840 ext2_ino_t end, save_inodes_count, i;
9841 struct problem_context pctx;
9842
9843 clear_problem_context(&pctx);
9844
9845 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
9846 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
9847 &save_inodes_count);
9848 if (pctx.errcode) {
9849 pctx.num = 1;
9850 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9851 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9852 return;
9853 }
9854 if (save_inodes_count == end)
9855 return;
9856
9857 for (i = save_inodes_count + 1; i <= end; i++) {
9858 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
9859 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
9860 for (i = save_inodes_count + 1; i <= end; i++)
9861 ext2fs_mark_inode_bitmap(fs->inode_map,
9862 i);
9863 ext2fs_mark_ib_dirty(fs);
9864 } else
9865 ext2fs_unmark_valid(fs);
9866 break;
9867 }
9868 }
9869
9870 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
9871 save_inodes_count, 0);
9872 if (pctx.errcode) {
9873 pctx.num = 2;
9874 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9875 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9876 return;
9877 }
9878}
9879
9880static void check_block_end(e2fsck_t ctx)
9881{
9882 ext2_filsys fs = ctx->fs;
9883 blk_t end, save_blocks_count, i;
9884 struct problem_context pctx;
9885
9886 clear_problem_context(&pctx);
9887
9888 end = fs->block_map->start +
9889 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
9890 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
9891 &save_blocks_count);
9892 if (pctx.errcode) {
9893 pctx.num = 3;
9894 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9895 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9896 return;
9897 }
9898 if (save_blocks_count == end)
9899 return;
9900
9901 for (i = save_blocks_count + 1; i <= end; i++) {
9902 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
9903 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
9904 for (i = save_blocks_count + 1; i <= end; i++)
9905 ext2fs_mark_block_bitmap(fs->block_map,
9906 i);
9907 ext2fs_mark_bb_dirty(fs);
9908 } else
9909 ext2fs_unmark_valid(fs);
9910 break;
9911 }
9912 }
9913
9914 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
9915 save_blocks_count, 0);
9916 if (pctx.errcode) {
9917 pctx.num = 4;
9918 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9919 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9920 return;
9921 }
9922}
9923
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009924static void e2fsck_pass5(e2fsck_t ctx)
9925{
9926#ifdef RESOURCE_TRACK
9927 struct resource_track rtrack;
9928#endif
9929 struct problem_context pctx;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009930
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009931#ifdef MTRACE
9932 mtrace_print("Pass 5");
9933#endif
9934
9935#ifdef RESOURCE_TRACK
9936 init_resource_track(&rtrack);
9937#endif
9938
9939 clear_problem_context(&pctx);
9940
9941 if (!(ctx->options & E2F_OPT_PREEN))
9942 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
9943
9944 if (ctx->progress)
9945 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
9946 return;
9947
9948 e2fsck_read_bitmaps(ctx);
9949
9950 check_block_bitmaps(ctx);
9951 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9952 return;
9953 check_inode_bitmaps(ctx);
9954 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9955 return;
9956 check_inode_end(ctx);
9957 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9958 return;
9959 check_block_end(ctx);
9960 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9961 return;
9962
9963 ext2fs_free_inode_bitmap(ctx->inode_used_map);
9964 ctx->inode_used_map = 0;
9965 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
9966 ctx->inode_dir_map = 0;
9967 ext2fs_free_block_bitmap(ctx->block_found_map);
9968 ctx->block_found_map = 0;
9969
9970#ifdef RESOURCE_TRACK
9971 if (ctx->options & E2F_OPT_TIME2) {
9972 e2fsck_clear_progbar(ctx);
9973 print_resource_track(_("Pass 5"), &rtrack);
9974 }
9975#endif
9976}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009977
9978/*
9979 * problem.c --- report filesystem problems to the user
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009980 */
9981
9982#define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */
9983#define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */
9984#define PR_NO_DEFAULT 0x000004 /* Default to no */
9985#define PR_MSG_ONLY 0x000008 /* Print message only */
9986
9987/* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */
9988
9989#define PR_FATAL 0x001000 /* Fatal error */
9990#define PR_AFTER_CODE 0x002000 /* After asking the first question, */
9991 /* ask another */
9992#define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */
9993#define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */
9994#define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */
9995#define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */
9996#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
9997
9998
9999#define PROMPT_NONE 0
10000#define PROMPT_FIX 1
10001#define PROMPT_CLEAR 2
10002#define PROMPT_RELOCATE 3
10003#define PROMPT_ALLOCATE 4
10004#define PROMPT_EXPAND 5
10005#define PROMPT_CONNECT 6
10006#define PROMPT_CREATE 7
10007#define PROMPT_SALVAGE 8
10008#define PROMPT_TRUNCATE 9
10009#define PROMPT_CLEAR_INODE 10
10010#define PROMPT_ABORT 11
10011#define PROMPT_SPLIT 12
10012#define PROMPT_CONTINUE 13
10013#define PROMPT_CLONE 14
10014#define PROMPT_DELETE 15
10015#define PROMPT_SUPPRESS 16
10016#define PROMPT_UNLINK 17
10017#define PROMPT_CLEAR_HTREE 18
10018#define PROMPT_RECREATE 19
10019#define PROMPT_NULL 20
10020
10021struct e2fsck_problem {
10022 problem_t e2p_code;
10023 const char * e2p_description;
10024 char prompt;
10025 int flags;
10026 problem_t second_code;
10027};
10028
10029struct latch_descr {
10030 int latch_code;
10031 problem_t question;
10032 problem_t end_message;
10033 int flags;
10034};
10035
10036/*
10037 * These are the prompts which are used to ask the user if they want
10038 * to fix a problem.
10039 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010040static const char * const prompt[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010041 N_("(no prompt)"), /* 0 */
10042 N_("Fix"), /* 1 */
10043 N_("Clear"), /* 2 */
10044 N_("Relocate"), /* 3 */
10045 N_("Allocate"), /* 4 */
10046 N_("Expand"), /* 5 */
10047 N_("Connect to /lost+found"), /* 6 */
10048 N_("Create"), /* 7 */
10049 N_("Salvage"), /* 8 */
10050 N_("Truncate"), /* 9 */
10051 N_("Clear inode"), /* 10 */
10052 N_("Abort"), /* 11 */
10053 N_("Split"), /* 12 */
10054 N_("Continue"), /* 13 */
10055 N_("Clone duplicate/bad blocks"), /* 14 */
10056 N_("Delete file"), /* 15 */
10057 N_("Suppress messages"),/* 16 */
10058 N_("Unlink"), /* 17 */
10059 N_("Clear HTree index"),/* 18 */
10060 N_("Recreate"), /* 19 */
10061 "", /* 20 */
10062};
10063
10064/*
10065 * These messages are printed when we are preen mode and we will be
10066 * automatically fixing the problem.
10067 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010068static const char * const preen_msg[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010069 N_("(NONE)"), /* 0 */
10070 N_("FIXED"), /* 1 */
10071 N_("CLEARED"), /* 2 */
10072 N_("RELOCATED"), /* 3 */
10073 N_("ALLOCATED"), /* 4 */
10074 N_("EXPANDED"), /* 5 */
10075 N_("RECONNECTED"), /* 6 */
10076 N_("CREATED"), /* 7 */
10077 N_("SALVAGED"), /* 8 */
10078 N_("TRUNCATED"), /* 9 */
10079 N_("INODE CLEARED"), /* 10 */
10080 N_("ABORTED"), /* 11 */
10081 N_("SPLIT"), /* 12 */
10082 N_("CONTINUING"), /* 13 */
10083 N_("DUPLICATE/BAD BLOCKS CLONED"), /* 14 */
10084 N_("FILE DELETED"), /* 15 */
10085 N_("SUPPRESSED"), /* 16 */
10086 N_("UNLINKED"), /* 17 */
10087 N_("HTREE INDEX CLEARED"),/* 18 */
10088 N_("WILL RECREATE"), /* 19 */
10089 "", /* 20 */
10090};
10091
10092static const struct e2fsck_problem problem_table[] = {
10093
10094 /* Pre-Pass 1 errors */
10095
10096 /* Block bitmap not in group */
10097 { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
10098 PROMPT_RELOCATE, PR_LATCH_RELOC },
10099
10100 /* Inode bitmap not in group */
10101 { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
10102 PROMPT_RELOCATE, PR_LATCH_RELOC },
10103
10104 /* Inode table not in group */
10105 { PR_0_ITABLE_NOT_GROUP,
10106 N_("@i table for @g %g is not in @g. (@b %b)\n"
10107 "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
10108 PROMPT_RELOCATE, PR_LATCH_RELOC },
10109
10110 /* Superblock corrupt */
10111 { PR_0_SB_CORRUPT,
10112 N_("\nThe @S could not be read or does not describe a correct ext2\n"
10113 "@f. If the @v is valid and it really contains an ext2\n"
10114 "@f (and not swap or ufs or something else), then the @S\n"
10115 "is corrupt, and you might try running e2fsck with an alternate @S:\n"
10116 " e2fsck -b %S <@v>\n\n"),
10117 PROMPT_NONE, PR_FATAL },
10118
10119 /* Filesystem size is wrong */
10120 { PR_0_FS_SIZE_WRONG,
10121 N_("The @f size (according to the @S) is %b @bs\n"
10122 "The physical size of the @v is %c @bs\n"
10123 "Either the @S or the partition table is likely to be corrupt!\n"),
10124 PROMPT_ABORT, 0 },
10125
10126 /* Fragments not supported */
10127 { PR_0_NO_FRAGMENTS,
10128 N_("@S @b_size = %b, fragsize = %c.\n"
10129 "This version of e2fsck does not support fragment sizes different\n"
10130 "from the @b size.\n"),
10131 PROMPT_NONE, PR_FATAL },
10132
10133 /* Bad blocks_per_group */
10134 { PR_0_BLOCKS_PER_GROUP,
10135 N_("@S @bs_per_group = %b, should have been %c\n"),
10136 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10137
10138 /* Bad first_data_block */
10139 { PR_0_FIRST_DATA_BLOCK,
10140 N_("@S first_data_@b = %b, should have been %c\n"),
10141 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10142
10143 /* Adding UUID to filesystem */
10144 { PR_0_ADD_UUID,
10145 N_("@f did not have a UUID; generating one.\n\n"),
10146 PROMPT_NONE, 0 },
10147
10148 /* Relocate hint */
10149 { PR_0_RELOCATE_HINT,
10150 N_("Note: if there is several inode or block bitmap blocks\n"
10151 "which require relocation, or one part of the inode table\n"
10152 "which must be moved, you may wish to try running e2fsck\n"
10153 "with the '-b %S' option first. The problem may lie only\n"
10154 "with the primary block group descriptor, and the backup\n"
10155 "block group descriptor may be OK.\n\n"),
10156 PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
10157
10158 /* Miscellaneous superblock corruption */
10159 { PR_0_MISC_CORRUPT_SUPER,
10160 N_("Corruption found in @S. (%s = %N).\n"),
10161 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10162
10163 /* Error determing physical device size of filesystem */
10164 { PR_0_GETSIZE_ERROR,
10165 N_("Error determining size of the physical @v: %m\n"),
10166 PROMPT_NONE, PR_FATAL },
10167
10168 /* Inode count in superblock is incorrect */
10169 { PR_0_INODE_COUNT_WRONG,
10170 N_("@i count in @S is %i, should be %j.\n"),
10171 PROMPT_FIX, 0 },
10172
10173 { PR_0_HURD_CLEAR_FILETYPE,
10174 N_("The Hurd does not support the filetype feature.\n"),
10175 PROMPT_CLEAR, 0 },
10176
10177 /* Journal inode is invalid */
10178 { PR_0_JOURNAL_BAD_INODE,
10179 N_("@S has a bad ext3 @j (@i %i).\n"),
10180 PROMPT_CLEAR, PR_PREEN_OK },
10181
10182 /* The external journal has (unsupported) multiple filesystems */
10183 { PR_0_JOURNAL_UNSUPP_MULTIFS,
10184 N_("External @j has multiple @f users (unsupported).\n"),
10185 PROMPT_NONE, PR_FATAL },
10186
10187 /* Can't find external journal */
10188 { PR_0_CANT_FIND_JOURNAL,
10189 N_("Can't find external @j\n"),
10190 PROMPT_NONE, PR_FATAL },
10191
10192 /* External journal has bad superblock */
10193 { PR_0_EXT_JOURNAL_BAD_SUPER,
10194 N_("External @j has bad @S\n"),
10195 PROMPT_NONE, PR_FATAL },
10196
10197 /* Superblock has a bad journal UUID */
10198 { PR_0_JOURNAL_BAD_UUID,
10199 N_("External @j does not support this @f\n"),
10200 PROMPT_NONE, PR_FATAL },
10201
10202 /* Journal has an unknown superblock type */
10203 { PR_0_JOURNAL_UNSUPP_SUPER,
10204 N_("Ext3 @j @S is unknown type %N (unsupported).\n"
10205 "It is likely that your copy of e2fsck is old and/or doesn't "
10206 "support this @j format.\n"
10207 "It is also possible the @j @S is corrupt.\n"),
10208 PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
10209
10210 /* Journal superblock is corrupt */
10211 { PR_0_JOURNAL_BAD_SUPER,
10212 N_("Ext3 @j @S is corrupt.\n"),
10213 PROMPT_FIX, PR_PREEN_OK },
10214
10215 /* Superblock flag should be cleared */
10216 { PR_0_JOURNAL_HAS_JOURNAL,
10217 N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
10218 PROMPT_CLEAR, PR_PREEN_OK },
10219
10220 /* Superblock flag is incorrect */
10221 { PR_0_JOURNAL_RECOVER_SET,
10222 N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
10223 PROMPT_CLEAR, PR_PREEN_OK },
10224
10225 /* Journal has data, but recovery flag is clear */
10226 { PR_0_JOURNAL_RECOVERY_CLEAR,
10227 N_("ext3 recovery flag clear, but @j has data.\n"),
10228 PROMPT_NONE, 0 },
10229
10230 /* Ask if we should clear the journal */
10231 { PR_0_JOURNAL_RESET_JOURNAL,
10232 N_("Clear @j"),
10233 PROMPT_NULL, PR_PREEN_NOMSG },
10234
10235 /* Ask if we should run the journal anyway */
10236 { PR_0_JOURNAL_RUN,
10237 N_("Run @j anyway"),
10238 PROMPT_NULL, 0 },
10239
10240 /* Run the journal by default */
10241 { PR_0_JOURNAL_RUN_DEFAULT,
10242 N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
10243 PROMPT_NONE, 0 },
10244
10245 /* Clearing orphan inode */
10246 { PR_0_ORPHAN_CLEAR_INODE,
10247 N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
10248 PROMPT_NONE, 0 },
10249
10250 /* Illegal block found in orphaned inode */
10251 { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
10252 N_("@I @b #%B (%b) found in @o @i %i.\n"),
10253 PROMPT_NONE, 0 },
10254
10255 /* Already cleared block found in orphaned inode */
10256 { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
10257 N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
10258 PROMPT_NONE, 0 },
10259
10260 /* Illegal orphan inode in superblock */
10261 { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
10262 N_("@I @o @i %i in @S.\n"),
10263 PROMPT_NONE, 0 },
10264
10265 /* Illegal inode in orphaned inode list */
10266 { PR_0_ORPHAN_ILLEGAL_INODE,
10267 N_("@I @i %i in @o @i list.\n"),
10268 PROMPT_NONE, 0 },
10269
10270 /* Filesystem revision is 0, but feature flags are set */
10271 { PR_0_FS_REV_LEVEL,
10272 "@f has feature flag(s) set, but is a revision 0 @f. ",
10273 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10274
10275 /* Journal superblock has an unknown read-only feature flag set */
10276 { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
10277 N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
10278 PROMPT_ABORT, 0 },
10279
10280 /* Journal superblock has an unknown incompatible feature flag set */
10281 { PR_0_JOURNAL_UNSUPP_INCOMPAT,
10282 N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
10283 PROMPT_ABORT, 0 },
10284
10285 /* Journal has unsupported version number */
10286 { PR_0_JOURNAL_UNSUPP_VERSION,
10287 N_("@j version not supported by this e2fsck.\n"),
10288 PROMPT_ABORT, 0 },
10289
10290 /* Moving journal to hidden file */
10291 { PR_0_MOVE_JOURNAL,
10292 N_("Moving @j from /%s to hidden inode.\n\n"),
10293 PROMPT_NONE, 0 },
10294
10295 /* Error moving journal to hidden file */
10296 { PR_0_ERR_MOVE_JOURNAL,
10297 N_("Error moving @j: %m\n\n"),
10298 PROMPT_NONE, 0 },
10299
10300 /* Clearing V2 journal superblock */
10301 { PR_0_CLEAR_V2_JOURNAL,
10302 N_("Found invalid V2 @j @S fields (from V1 journal).\n"
10303 "Clearing fields beyond the V1 @j @S...\n\n"),
10304 PROMPT_NONE, 0 },
10305
10306 /* Backup journal inode blocks */
10307 { PR_0_BACKUP_JNL,
10308 N_("Backing up @j @i @b information.\n\n"),
10309 PROMPT_NONE, 0 },
10310
10311 /* Reserved blocks w/o resize_inode */
10312 { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
10313 N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
10314 "is %N; @s zero. "),
10315 PROMPT_FIX, 0 },
10316
10317 /* Resize_inode not enabled, but resize inode is non-zero */
10318 { PR_0_CLEAR_RESIZE_INODE,
10319 N_("Resize_@i not enabled, but the resize inode is non-zero. "),
10320 PROMPT_CLEAR, 0 },
10321
10322 /* Resize inode invalid */
10323 { PR_0_RESIZE_INODE_INVALID,
10324 N_("Resize @i not valid. "),
10325 PROMPT_RECREATE, 0 },
10326
10327 /* Pass 1 errors */
10328
10329 /* Pass 1: Checking inodes, blocks, and sizes */
10330 { PR_1_PASS_HEADER,
10331 N_("Pass 1: Checking @is, @bs, and sizes\n"),
10332 PROMPT_NONE, 0 },
10333
10334 /* Root directory is not an inode */
10335 { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
10336 PROMPT_CLEAR, 0 },
10337
10338 /* Root directory has dtime set */
10339 { PR_1_ROOT_DTIME,
10340 N_("@r has dtime set (probably due to old mke2fs). "),
10341 PROMPT_FIX, PR_PREEN_OK },
10342
10343 /* Reserved inode has bad mode */
10344 { PR_1_RESERVED_BAD_MODE,
10345 N_("Reserved @i %i %Q has bad mode. "),
10346 PROMPT_CLEAR, PR_PREEN_OK },
10347
10348 /* Deleted inode has zero dtime */
10349 { PR_1_ZERO_DTIME,
10350 N_("@D @i %i has zero dtime. "),
10351 PROMPT_FIX, PR_PREEN_OK },
10352
10353 /* Inode in use, but dtime set */
10354 { PR_1_SET_DTIME,
10355 N_("@i %i is in use, but has dtime set. "),
10356 PROMPT_FIX, PR_PREEN_OK },
10357
10358 /* Zero-length directory */
10359 { PR_1_ZERO_LENGTH_DIR,
10360 N_("@i %i is a @z @d. "),
10361 PROMPT_CLEAR, PR_PREEN_OK },
10362
10363 /* Block bitmap conflicts with some other fs block */
10364 { PR_1_BB_CONFLICT,
10365 N_("@g %g's @b @B at %b @C.\n"),
10366 PROMPT_RELOCATE, 0 },
10367
10368 /* Inode bitmap conflicts with some other fs block */
10369 { PR_1_IB_CONFLICT,
10370 N_("@g %g's @i @B at %b @C.\n"),
10371 PROMPT_RELOCATE, 0 },
10372
10373 /* Inode table conflicts with some other fs block */
10374 { PR_1_ITABLE_CONFLICT,
10375 N_("@g %g's @i table at %b @C.\n"),
10376 PROMPT_RELOCATE, 0 },
10377
10378 /* Block bitmap is on a bad block */
10379 { PR_1_BB_BAD_BLOCK,
10380 N_("@g %g's @b @B (%b) is bad. "),
10381 PROMPT_RELOCATE, 0 },
10382
10383 /* Inode bitmap is on a bad block */
10384 { PR_1_IB_BAD_BLOCK,
10385 N_("@g %g's @i @B (%b) is bad. "),
10386 PROMPT_RELOCATE, 0 },
10387
10388 /* Inode has incorrect i_size */
10389 { PR_1_BAD_I_SIZE,
10390 N_("@i %i, i_size is %Is, @s %N. "),
10391 PROMPT_FIX, PR_PREEN_OK },
10392
10393 /* Inode has incorrect i_blocks */
10394 { PR_1_BAD_I_BLOCKS,
10395 N_("@i %i, i_@bs is %Ib, @s %N. "),
10396 PROMPT_FIX, PR_PREEN_OK },
10397
10398 /* Illegal blocknumber in inode */
10399 { PR_1_ILLEGAL_BLOCK_NUM,
10400 N_("@I @b #%B (%b) in @i %i. "),
10401 PROMPT_CLEAR, PR_LATCH_BLOCK },
10402
10403 /* Block number overlaps fs metadata */
10404 { PR_1_BLOCK_OVERLAPS_METADATA,
10405 N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
10406 PROMPT_CLEAR, PR_LATCH_BLOCK },
10407
10408 /* Inode has illegal blocks (latch question) */
10409 { PR_1_INODE_BLOCK_LATCH,
10410 N_("@i %i has illegal @b(s). "),
10411 PROMPT_CLEAR, 0 },
10412
10413 /* Too many bad blocks in inode */
10414 { PR_1_TOO_MANY_BAD_BLOCKS,
10415 N_("Too many illegal @bs in @i %i.\n"),
10416 PROMPT_CLEAR_INODE, PR_NO_OK },
10417
10418 /* Illegal block number in bad block inode */
10419 { PR_1_BB_ILLEGAL_BLOCK_NUM,
10420 N_("@I @b #%B (%b) in bad @b @i. "),
10421 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10422
10423 /* Bad block inode has illegal blocks (latch question) */
10424 { PR_1_INODE_BBLOCK_LATCH,
10425 N_("Bad @b @i has illegal @b(s). "),
10426 PROMPT_CLEAR, 0 },
10427
10428 /* Duplicate or bad blocks in use! */
10429 { PR_1_DUP_BLOCKS_PREENSTOP,
10430 N_("Duplicate or bad @b in use!\n"),
10431 PROMPT_NONE, 0 },
10432
10433 /* Bad block used as bad block indirect block */
10434 { PR_1_BBINODE_BAD_METABLOCK,
10435 N_("Bad @b %b used as bad @b @i indirect @b. "),
10436 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10437
10438 /* Inconsistency can't be fixed prompt */
10439 { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
10440 N_("\nThe bad @b @i has probably been corrupted. You probably\n"
10441 "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
10442 "in the @f.\n"),
10443 PROMPT_CONTINUE, PR_PREEN_NOMSG },
10444
10445 /* Bad primary block */
10446 { PR_1_BAD_PRIMARY_BLOCK,
10447 N_("\nIf the @b is really bad, the @f can not be fixed.\n"),
10448 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
10449
10450 /* Bad primary block prompt */
10451 { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
10452 N_("You can clear the this @b (and hope for the best) from the\n"
10453 "bad @b list and hope that @b is really OK, but there are no\n"
10454 "guarantees.\n\n"),
10455 PROMPT_CLEAR, PR_PREEN_NOMSG },
10456
10457 /* Bad primary superblock */
10458 { PR_1_BAD_PRIMARY_SUPERBLOCK,
10459 N_("The primary @S (%b) is on the bad @b list.\n"),
10460 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10461
10462 /* Bad primary block group descriptors */
10463 { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
10464 N_("Block %b in the primary @g descriptors "
10465 "is on the bad @b list\n"),
10466 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10467
10468 /* Bad superblock in group */
10469 { PR_1_BAD_SUPERBLOCK,
10470 N_("Warning: Group %g's @S (%b) is bad.\n"),
10471 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10472
10473 /* Bad block group descriptors in group */
10474 { PR_1_BAD_GROUP_DESCRIPTORS,
10475 N_("Warning: Group %g's copy of the @g descriptors has a bad "
10476 "@b (%b).\n"),
10477 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10478
10479 /* Block claimed for no reason */
10480 { PR_1_PROGERR_CLAIMED_BLOCK,
10481 N_("Programming error? @b #%b claimed for no reason in "
10482 "process_bad_@b.\n"),
10483 PROMPT_NONE, PR_PREEN_OK },
10484
10485 /* Error allocating blocks for relocating metadata */
10486 { PR_1_RELOC_BLOCK_ALLOCATE,
10487 N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
10488 PROMPT_NONE, PR_PREEN_OK },
10489
10490 /* Error allocating block buffer during relocation process */
10491 { PR_1_RELOC_MEMORY_ALLOCATE,
10492 N_("@A @b buffer for relocating %s\n"),
10493 PROMPT_NONE, PR_PREEN_OK },
10494
10495 /* Relocating metadata group information from X to Y */
10496 { PR_1_RELOC_FROM_TO,
10497 N_("Relocating @g %g's %s from %b to %c...\n"),
10498 PROMPT_NONE, PR_PREEN_OK },
10499
10500 /* Relocating metatdata group information to X */
10501 { PR_1_RELOC_TO,
10502 N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
10503 PROMPT_NONE, PR_PREEN_OK },
10504
10505 /* Block read error during relocation process */
10506 { PR_1_RELOC_READ_ERR,
10507 N_("Warning: could not read @b %b of %s: %m\n"),
10508 PROMPT_NONE, PR_PREEN_OK },
10509
10510 /* Block write error during relocation process */
10511 { PR_1_RELOC_WRITE_ERR,
10512 N_("Warning: could not write @b %b for %s: %m\n"),
10513 PROMPT_NONE, PR_PREEN_OK },
10514
10515 /* Error allocating inode bitmap */
10516 { PR_1_ALLOCATE_IBITMAP_ERROR,
10517 "@A @i @B (%N): %m\n",
10518 PROMPT_NONE, PR_FATAL },
10519
10520 /* Error allocating block bitmap */
10521 { PR_1_ALLOCATE_BBITMAP_ERROR,
10522 "@A @b @B (%N): %m\n",
10523 PROMPT_NONE, PR_FATAL },
10524
10525 /* Error allocating icount structure */
10526 { PR_1_ALLOCATE_ICOUNT,
10527 N_("@A icount link information: %m\n"),
10528 PROMPT_NONE, PR_FATAL },
10529
10530 /* Error allocating dbcount */
10531 { PR_1_ALLOCATE_DBCOUNT,
10532 N_("@A @d @b array: %m\n"),
10533 PROMPT_NONE, PR_FATAL },
10534
10535 /* Error while scanning inodes */
10536 { PR_1_ISCAN_ERROR,
10537 N_("Error while scanning @is (%i): %m\n"),
10538 PROMPT_NONE, PR_FATAL },
10539
10540 /* Error while iterating over blocks */
10541 { PR_1_BLOCK_ITERATE,
10542 N_("Error while iterating over @bs in @i %i: %m\n"),
10543 PROMPT_NONE, PR_FATAL },
10544
10545 /* Error while storing inode count information */
10546 { PR_1_ICOUNT_STORE,
10547 N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
10548 PROMPT_NONE, PR_FATAL },
10549
10550 /* Error while storing directory block information */
10551 { PR_1_ADD_DBLOCK,
10552 N_("Error storing @d @b information "
10553 "(@i=%i, @b=%b, num=%N): %m\n"),
10554 PROMPT_NONE, PR_FATAL },
10555
10556 /* Error while reading inode (for clearing) */
10557 { PR_1_READ_INODE,
10558 N_("Error reading @i %i: %m\n"),
10559 PROMPT_NONE, PR_FATAL },
10560
10561 /* Suppress messages prompt */
10562 { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
10563
10564 /* Imagic flag set on an inode when filesystem doesn't support it */
10565 { PR_1_SET_IMAGIC,
10566 N_("@i %i has imagic flag set. "),
10567 PROMPT_CLEAR, 0 },
10568
10569 /* Immutable flag set on a device or socket inode */
10570 { PR_1_SET_IMMUTABLE,
10571 N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
10572 "or append-only flag set. "),
10573 PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
10574
10575 /* Compression flag set on an inode when filesystem doesn't support it */
10576 { PR_1_COMPR_SET,
10577 N_("@i %i has @cion flag set on @f without @cion support. "),
10578 PROMPT_CLEAR, 0 },
10579
10580 /* Non-zero size for device, fifo or socket inode */
10581 { PR_1_SET_NONZSIZE,
10582 "Special (@v/socket/fifo) @i %i has non-zero size. ",
10583 PROMPT_FIX, PR_PREEN_OK },
10584
10585 /* Filesystem revision is 0, but feature flags are set */
10586 { PR_1_FS_REV_LEVEL,
10587 "@f has feature flag(s) set, but is a revision 0 @f. ",
10588 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10589
10590 /* Journal inode is not in use, but contains data */
10591 { PR_1_JOURNAL_INODE_NOT_CLEAR,
10592 "@j @i is not in use, but contains data. ",
10593 PROMPT_CLEAR, PR_PREEN_OK },
10594
10595 /* Journal has bad mode */
10596 { PR_1_JOURNAL_BAD_MODE,
10597 N_("@j is not regular file. "),
10598 PROMPT_FIX, PR_PREEN_OK },
10599
10600 /* Deal with inodes that were part of orphan linked list */
10601 { PR_1_LOW_DTIME,
10602 N_("@i %i was part of the orphaned @i list. "),
10603 PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
10604
10605 /* Deal with inodes that were part of corrupted orphan linked
10606 list (latch question) */
10607 { PR_1_ORPHAN_LIST_REFUGEES,
10608 N_("@is that were part of a corrupted orphan linked list found. "),
10609 PROMPT_FIX, 0 },
10610
10611 /* Error allocating refcount structure */
10612 { PR_1_ALLOCATE_REFCOUNT,
10613 "@A refcount structure (%N): %m\n",
10614 PROMPT_NONE, PR_FATAL },
10615
10616 /* Error reading extended attribute block */
10617 { PR_1_READ_EA_BLOCK,
10618 N_("Error reading @a @b %b for @i %i. "),
10619 PROMPT_CLEAR, 0 },
10620
10621 /* Invalid extended attribute block */
10622 { PR_1_BAD_EA_BLOCK,
10623 N_("@i %i has a bad @a @b %b. "),
10624 PROMPT_CLEAR, 0 },
10625
10626 /* Error reading Extended Attribute block while fixing refcount */
10627 { PR_1_EXTATTR_READ_ABORT,
10628 N_("Error reading @a @b %b (%m). "),
10629 PROMPT_ABORT, 0 },
10630
10631 /* Extended attribute reference count incorrect */
10632 { PR_1_EXTATTR_REFCOUNT,
10633 N_("@a @b %b has reference count %B, should be %N. "),
10634 PROMPT_FIX, 0 },
10635
10636 /* Error writing Extended Attribute block while fixing refcount */
10637 { PR_1_EXTATTR_WRITE,
10638 N_("Error writing @a @b %b (%m). "),
10639 PROMPT_ABORT, 0 },
10640
10641 /* Multiple EA blocks not supported */
10642 { PR_1_EA_MULTI_BLOCK,
10643 N_("@a @b %b has h_blocks > 1. "),
10644 PROMPT_CLEAR, 0},
10645
10646 /* Error allocating EA region allocation structure */
10647 { PR_1_EA_ALLOC_REGION,
10648 N_("Error allocating @a @b %b. "),
10649 PROMPT_ABORT, 0},
10650
10651 /* Error EA allocation collision */
10652 { PR_1_EA_ALLOC_COLLISION,
10653 N_("@a @b %b is corrupt (allocation collision). "),
10654 PROMPT_CLEAR, 0},
10655
10656 /* Bad extended attribute name */
10657 { PR_1_EA_BAD_NAME,
10658 N_("@a @b %b is corrupt (invalid name). "),
10659 PROMPT_CLEAR, 0},
10660
10661 /* Bad extended attribute value */
10662 { PR_1_EA_BAD_VALUE,
10663 N_("@a @b %b is corrupt (invalid value). "),
10664 PROMPT_CLEAR, 0},
10665
10666 /* Inode too big (latch question) */
10667 { PR_1_INODE_TOOBIG,
10668 N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
10669
10670 /* Directory too big */
10671 { PR_1_TOOBIG_DIR,
10672 N_("@b #%B (%b) causes @d to be too big. "),
10673 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10674
10675 /* Regular file too big */
10676 { PR_1_TOOBIG_REG,
10677 N_("@b #%B (%b) causes file to be too big. "),
10678 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10679
10680 /* Symlink too big */
10681 { PR_1_TOOBIG_SYMLINK,
10682 N_("@b #%B (%b) causes symlink to be too big. "),
10683 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10684
10685 /* INDEX_FL flag set on a non-HTREE filesystem */
10686 { PR_1_HTREE_SET,
10687 N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
10688 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10689
10690 /* INDEX_FL flag set on a non-directory */
10691 { PR_1_HTREE_NODIR,
10692 N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
10693 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10694
10695 /* Invalid root node in HTREE directory */
10696 { PR_1_HTREE_BADROOT,
10697 N_("@h %i has an invalid root node.\n"),
10698 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10699
10700 /* Unsupported hash version in HTREE directory */
10701 { PR_1_HTREE_HASHV,
10702 N_("@h %i has an unsupported hash version (%N)\n"),
10703 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10704
10705 /* Incompatible flag in HTREE root node */
10706 { PR_1_HTREE_INCOMPAT,
10707 N_("@h %i uses an incompatible htree root node flag.\n"),
10708 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10709
10710 /* HTREE too deep */
10711 { PR_1_HTREE_DEPTH,
10712 N_("@h %i has a tree depth (%N) which is too big\n"),
10713 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10714
10715 /* Bad block has indirect block that conflicts with filesystem block */
10716 { PR_1_BB_FS_BLOCK,
10717 N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
10718 "@f metadata. "),
10719 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10720
10721 /* Resize inode failed */
10722 { PR_1_RESIZE_INODE_CREATE,
10723 N_("Resize @i (re)creation failed: %m."),
10724 PROMPT_ABORT, 0 },
10725
10726 /* invalid inode->i_extra_isize */
10727 { PR_1_EXTRA_ISIZE,
10728 N_("@i %i has a extra size (%IS) which is invalid\n"),
10729 PROMPT_FIX, PR_PREEN_OK },
10730
10731 /* invalid ea entry->e_name_len */
10732 { PR_1_ATTR_NAME_LEN,
10733 N_("@a in @i %i has a namelen (%N) which is invalid\n"),
10734 PROMPT_CLEAR, PR_PREEN_OK },
10735
10736 /* invalid ea entry->e_value_size */
10737 { PR_1_ATTR_VALUE_SIZE,
10738 N_("@a in @i %i has a value size (%N) which is invalid\n"),
10739 PROMPT_CLEAR, PR_PREEN_OK },
10740
10741 /* invalid ea entry->e_value_offs */
10742 { PR_1_ATTR_VALUE_OFFSET,
10743 N_("@a in @i %i has a value offset (%N) which is invalid\n"),
10744 PROMPT_CLEAR, PR_PREEN_OK },
10745
10746 /* invalid ea entry->e_value_block */
10747 { PR_1_ATTR_VALUE_BLOCK,
10748 N_("@a in @i %i has a value block (%N) which is invalid (must be 0)\n"),
10749 PROMPT_CLEAR, PR_PREEN_OK },
10750
10751 /* invalid ea entry->e_hash */
10752 { PR_1_ATTR_HASH,
10753 N_("@a in @i %i has a hash (%N) which is invalid (must be 0)\n"),
10754 PROMPT_CLEAR, PR_PREEN_OK },
10755
10756 /* Pass 1b errors */
10757
10758 /* Pass 1B: Rescan for duplicate/bad blocks */
10759 { PR_1B_PASS_HEADER,
10760 N_("Duplicate @bs found... invoking duplicate @b passes.\n"
10761 "Pass 1B: Rescan for duplicate/bad @bs\n"),
10762 PROMPT_NONE, 0 },
10763
10764 /* Duplicate/bad block(s) header */
10765 { PR_1B_DUP_BLOCK_HEADER,
10766 N_("Duplicate/bad @b(s) in @i %i:"),
10767 PROMPT_NONE, 0 },
10768
10769 /* Duplicate/bad block(s) in inode */
10770 { PR_1B_DUP_BLOCK,
10771 " %b",
10772 PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
10773
10774 /* Duplicate/bad block(s) end */
10775 { PR_1B_DUP_BLOCK_END,
10776 "\n",
10777 PROMPT_NONE, PR_PREEN_NOHDR },
10778
10779 /* Error while scanning inodes */
10780 { PR_1B_ISCAN_ERROR,
10781 N_("Error while scanning inodes (%i): %m\n"),
10782 PROMPT_NONE, PR_FATAL },
10783
10784 /* Error allocating inode bitmap */
10785 { PR_1B_ALLOCATE_IBITMAP_ERROR,
10786 N_("@A @i @B (inode_dup_map): %m\n"),
10787 PROMPT_NONE, PR_FATAL },
10788
10789 /* Error while iterating over blocks */
10790 { PR_1B_BLOCK_ITERATE,
10791 N_("Error while iterating over @bs in @i %i (%s): %m\n"),
10792 PROMPT_NONE, 0 },
10793
10794 /* Error adjusting EA refcount */
10795 { PR_1B_ADJ_EA_REFCOUNT,
10796 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
10797 PROMPT_NONE, 0 },
10798
10799
10800 /* Pass 1C: Scan directories for inodes with dup blocks. */
10801 { PR_1C_PASS_HEADER,
10802 N_("Pass 1C: Scan directories for @is with dup @bs.\n"),
10803 PROMPT_NONE, 0 },
10804
10805
10806 /* Pass 1D: Reconciling duplicate blocks */
10807 { PR_1D_PASS_HEADER,
10808 N_("Pass 1D: Reconciling duplicate @bs\n"),
10809 PROMPT_NONE, 0 },
10810
10811 /* File has duplicate blocks */
10812 { PR_1D_DUP_FILE,
10813 N_("File %Q (@i #%i, mod time %IM) \n"
10814 " has %B duplicate @b(s), shared with %N file(s):\n"),
10815 PROMPT_NONE, 0 },
10816
10817 /* List of files sharing duplicate blocks */
10818 { PR_1D_DUP_FILE_LIST,
10819 N_("\t%Q (@i #%i, mod time %IM)\n"),
10820 PROMPT_NONE, 0 },
10821
10822 /* File sharing blocks with filesystem metadata */
10823 { PR_1D_SHARE_METADATA,
10824 N_("\t<@f metadata>\n"),
10825 PROMPT_NONE, 0 },
10826
10827 /* Report of how many duplicate/bad inodes */
10828 { PR_1D_NUM_DUP_INODES,
10829 N_("(There are %N @is containing duplicate/bad @bs.)\n\n"),
10830 PROMPT_NONE, 0 },
10831
10832 /* Duplicated blocks already reassigned or cloned. */
10833 { PR_1D_DUP_BLOCKS_DEALT,
10834 N_("Duplicated @bs already reassigned or cloned.\n\n"),
10835 PROMPT_NONE, 0 },
10836
10837 /* Clone duplicate/bad blocks? */
10838 { PR_1D_CLONE_QUESTION,
10839 "", PROMPT_CLONE, PR_NO_OK },
10840
10841 /* Delete file? */
10842 { PR_1D_DELETE_QUESTION,
10843 "", PROMPT_DELETE, 0 },
10844
10845 /* Couldn't clone file (error) */
10846 { PR_1D_CLONE_ERROR,
10847 N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
10848
10849 /* Pass 2 errors */
10850
10851 /* Pass 2: Checking directory structure */
10852 { PR_2_PASS_HEADER,
10853 N_("Pass 2: Checking @d structure\n"),
10854 PROMPT_NONE, 0 },
10855
10856 /* Bad inode number for '.' */
10857 { PR_2_BAD_INODE_DOT,
10858 N_("Bad @i number for '.' in @d @i %i.\n"),
10859 PROMPT_FIX, 0 },
10860
10861 /* Directory entry has bad inode number */
10862 { PR_2_BAD_INO,
10863 N_("@E has bad @i #: %Di.\n"),
10864 PROMPT_CLEAR, 0 },
10865
10866 /* Directory entry has deleted or unused inode */
10867 { PR_2_UNUSED_INODE,
10868 N_("@E has @D/unused @i %Di. "),
10869 PROMPT_CLEAR, PR_PREEN_OK },
10870
10871 /* Directry entry is link to '.' */
10872 { PR_2_LINK_DOT,
10873 N_("@E @L to '.' "),
10874 PROMPT_CLEAR, 0 },
10875
10876 /* Directory entry points to inode now located in a bad block */
10877 { PR_2_BB_INODE,
10878 N_("@E points to @i (%Di) located in a bad @b.\n"),
10879 PROMPT_CLEAR, 0 },
10880
10881 /* Directory entry contains a link to a directory */
10882 { PR_2_LINK_DIR,
10883 N_("@E @L to @d %P (%Di).\n"),
10884 PROMPT_CLEAR, 0 },
10885
10886 /* Directory entry contains a link to the root directry */
10887 { PR_2_LINK_ROOT,
10888 N_("@E @L to the @r.\n"),
10889 PROMPT_CLEAR, 0 },
10890
10891 /* Directory entry has illegal characters in its name */
10892 { PR_2_BAD_NAME,
10893 N_("@E has illegal characters in its name.\n"),
10894 PROMPT_FIX, 0 },
10895
10896 /* Missing '.' in directory inode */
10897 { PR_2_MISSING_DOT,
10898 N_("Missing '.' in @d @i %i.\n"),
10899 PROMPT_FIX, 0 },
10900
10901 /* Missing '..' in directory inode */
10902 { PR_2_MISSING_DOT_DOT,
10903 N_("Missing '..' in @d @i %i.\n"),
10904 PROMPT_FIX, 0 },
10905
10906 /* First entry in directory inode doesn't contain '.' */
10907 { PR_2_1ST_NOT_DOT,
10908 N_("First @e '%Dn' (inode=%Di) in @d @i %i (%p) @s '.'\n"),
10909 PROMPT_FIX, 0 },
10910
10911 /* Second entry in directory inode doesn't contain '..' */
10912 { PR_2_2ND_NOT_DOT_DOT,
10913 N_("Second @e '%Dn' (inode=%Di) in @d @i %i @s '..'\n"),
10914 PROMPT_FIX, 0 },
10915
10916 /* i_faddr should be zero */
10917 { PR_2_FADDR_ZERO,
10918 N_("i_faddr @F %IF, @s zero.\n"),
10919 PROMPT_CLEAR, 0 },
10920
10921 /* i_file_acl should be zero */
10922 { PR_2_FILE_ACL_ZERO,
10923 N_("i_file_acl @F %If, @s zero.\n"),
10924 PROMPT_CLEAR, 0 },
10925
10926 /* i_dir_acl should be zero */
10927 { PR_2_DIR_ACL_ZERO,
10928 N_("i_dir_acl @F %Id, @s zero.\n"),
10929 PROMPT_CLEAR, 0 },
10930
10931 /* i_frag should be zero */
10932 { PR_2_FRAG_ZERO,
10933 N_("i_frag @F %N, @s zero.\n"),
10934 PROMPT_CLEAR, 0 },
10935
10936 /* i_fsize should be zero */
10937 { PR_2_FSIZE_ZERO,
10938 N_("i_fsize @F %N, @s zero.\n"),
10939 PROMPT_CLEAR, 0 },
10940
10941 /* inode has bad mode */
10942 { PR_2_BAD_MODE,
10943 N_("@i %i (%Q) has a bad mode (%Im).\n"),
10944 PROMPT_CLEAR, 0 },
10945
10946 /* directory corrupted */
10947 { PR_2_DIR_CORRUPTED,
10948 N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
10949 PROMPT_SALVAGE, 0 },
10950
10951 /* filename too long */
10952 { PR_2_FILENAME_LONG,
10953 N_("@d @i %i, @b %B, offset %N: filename too long\n"),
10954 PROMPT_TRUNCATE, 0 },
10955
10956 /* Directory inode has a missing block (hole) */
10957 { PR_2_DIRECTORY_HOLE,
10958 N_("@d @i %i has an unallocated @b #%B. "),
10959 PROMPT_ALLOCATE, 0 },
10960
10961 /* '.' is not NULL terminated */
10962 { PR_2_DOT_NULL_TERM,
10963 N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
10964 PROMPT_FIX, 0 },
10965
10966 /* '..' is not NULL terminated */
10967 { PR_2_DOT_DOT_NULL_TERM,
10968 N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
10969 PROMPT_FIX, 0 },
10970
10971 /* Illegal character device inode */
10972 { PR_2_BAD_CHAR_DEV,
10973 N_("@i %i (%Q) is an @I character @v.\n"),
10974 PROMPT_CLEAR, 0 },
10975
10976 /* Illegal block device inode */
10977 { PR_2_BAD_BLOCK_DEV,
10978 N_("@i %i (%Q) is an @I @b @v.\n"),
10979 PROMPT_CLEAR, 0 },
10980
10981 /* Duplicate '.' entry */
10982 { PR_2_DUP_DOT,
10983 N_("@E is duplicate '.' @e.\n"),
10984 PROMPT_FIX, 0 },
10985
10986 /* Duplicate '..' entry */
10987 { PR_2_DUP_DOT_DOT,
10988 N_("@E is duplicate '..' @e.\n"),
10989 PROMPT_FIX, 0 },
10990
10991 /* Internal error: couldn't find dir_info */
10992 { PR_2_NO_DIRINFO,
10993 N_("Internal error: couldn't find dir_info for %i.\n"),
10994 PROMPT_NONE, PR_FATAL },
10995
10996 /* Final rec_len is wrong */
10997 { PR_2_FINAL_RECLEN,
10998 N_("@E has rec_len of %Dr, should be %N.\n"),
10999 PROMPT_FIX, 0 },
11000
11001 /* Error allocating icount structure */
11002 { PR_2_ALLOCATE_ICOUNT,
11003 N_("@A icount structure: %m\n"),
11004 PROMPT_NONE, PR_FATAL },
11005
11006 /* Error iterating over directory blocks */
11007 { PR_2_DBLIST_ITERATE,
11008 N_("Error iterating over @d @bs: %m\n"),
11009 PROMPT_NONE, PR_FATAL },
11010
11011 /* Error reading directory block */
11012 { PR_2_READ_DIRBLOCK,
11013 N_("Error reading @d @b %b (@i %i): %m\n"),
11014 PROMPT_CONTINUE, 0 },
11015
11016 /* Error writing directory block */
11017 { PR_2_WRITE_DIRBLOCK,
11018 N_("Error writing @d @b %b (@i %i): %m\n"),
11019 PROMPT_CONTINUE, 0 },
11020
11021 /* Error allocating new directory block */
11022 { PR_2_ALLOC_DIRBOCK,
11023 N_("@A new @d @b for @i %i (%s): %m\n"),
11024 PROMPT_NONE, 0 },
11025
11026 /* Error deallocating inode */
11027 { PR_2_DEALLOC_INODE,
11028 N_("Error deallocating @i %i: %m\n"),
11029 PROMPT_NONE, PR_FATAL },
11030
11031 /* Directory entry for '.' is big. Split? */
11032 { PR_2_SPLIT_DOT,
11033 N_("@d @e for '.' is big. "),
11034 PROMPT_SPLIT, PR_NO_OK },
11035
11036 /* Illegal FIFO inode */
11037 { PR_2_BAD_FIFO,
11038 N_("@i %i (%Q) is an @I FIFO.\n"),
11039 PROMPT_CLEAR, 0 },
11040
11041 /* Illegal socket inode */
11042 { PR_2_BAD_SOCKET,
11043 N_("@i %i (%Q) is an @I socket.\n"),
11044 PROMPT_CLEAR, 0 },
11045
11046 /* Directory filetype not set */
11047 { PR_2_SET_FILETYPE,
11048 N_("Setting filetype for @E to %N.\n"),
11049 PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
11050
11051 /* Directory filetype incorrect */
11052 { PR_2_BAD_FILETYPE,
11053 N_("@E has an incorrect filetype (was %Dt, should be %N).\n"),
11054 PROMPT_FIX, 0 },
11055
11056 /* Directory filetype set on filesystem */
11057 { PR_2_CLEAR_FILETYPE,
11058 N_("@E has filetype set.\n"),
11059 PROMPT_CLEAR, PR_PREEN_OK },
11060
11061 /* Directory filename is null */
11062 { PR_2_NULL_NAME,
11063 N_("@E has a zero-length name.\n"),
11064 PROMPT_CLEAR, 0 },
11065
11066 /* Invalid symlink */
11067 { PR_2_INVALID_SYMLINK,
11068 N_("Symlink %Q (@i #%i) is invalid.\n"),
11069 PROMPT_CLEAR, 0 },
11070
11071 /* i_file_acl (extended attribute block) is bad */
11072 { PR_2_FILE_ACL_BAD,
11073 N_("@a @b @F invalid (%If).\n"),
11074 PROMPT_CLEAR, 0 },
11075
11076 /* Filesystem contains large files, but has no such flag in sb */
11077 { PR_2_FEATURE_LARGE_FILES,
11078 N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
11079 PROMPT_FIX, 0 },
11080
11081 /* Node in HTREE directory not referenced */
11082 { PR_2_HTREE_NOTREF,
11083 N_("@p @h %d: node (%B) not referenced\n"),
11084 PROMPT_NONE, 0 },
11085
11086 /* Node in HTREE directory referenced twice */
11087 { PR_2_HTREE_DUPREF,
11088 N_("@p @h %d: node (%B) referenced twice\n"),
11089 PROMPT_NONE, 0 },
11090
11091 /* Node in HTREE directory has bad min hash */
11092 { PR_2_HTREE_MIN_HASH,
11093 N_("@p @h %d: node (%B) has bad min hash\n"),
11094 PROMPT_NONE, 0 },
11095
11096 /* Node in HTREE directory has bad max hash */
11097 { PR_2_HTREE_MAX_HASH,
11098 N_("@p @h %d: node (%B) has bad max hash\n"),
11099 PROMPT_NONE, 0 },
11100
11101 /* Clear invalid HTREE directory */
11102 { PR_2_HTREE_CLEAR,
11103 N_("Invalid @h %d (%q). "), PROMPT_CLEAR, 0 },
11104
11105 /* Bad block in htree interior node */
11106 { PR_2_HTREE_BADBLK,
11107 N_("@p @h %d (%q): bad @b number %b.\n"),
11108 PROMPT_CLEAR_HTREE, 0 },
11109
11110 /* Error adjusting EA refcount */
11111 { PR_2_ADJ_EA_REFCOUNT,
11112 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
11113 PROMPT_NONE, PR_FATAL },
11114
11115 /* Invalid HTREE root node */
11116 { PR_2_HTREE_BAD_ROOT,
11117 N_("@p @h %d: root node is invalid\n"),
11118 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11119
11120 /* Invalid HTREE limit */
11121 { PR_2_HTREE_BAD_LIMIT,
11122 N_("@p @h %d: node (%B) has bad limit (%N)\n"),
11123 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11124
11125 /* Invalid HTREE count */
11126 { PR_2_HTREE_BAD_COUNT,
11127 N_("@p @h %d: node (%B) has bad count (%N)\n"),
11128 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11129
11130 /* HTREE interior node has out-of-order hashes in table */
11131 { PR_2_HTREE_HASH_ORDER,
11132 N_("@p @h %d: node (%B) has an unordered hash table\n"),
11133 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11134
11135 /* Node in HTREE directory has bad depth */
11136 { PR_2_HTREE_BAD_DEPTH,
11137 N_("@p @h %d: node (%B) has bad depth\n"),
11138 PROMPT_NONE, 0 },
11139
11140 /* Duplicate directory entry found */
11141 { PR_2_DUPLICATE_DIRENT,
11142 N_("Duplicate @E found. "),
11143 PROMPT_CLEAR, 0 },
11144
11145 /* Non-unique filename found */
11146 { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
11147 N_("@E has a non-unique filename.\nRename to %s"),
11148 PROMPT_NULL, 0 },
11149
11150 /* Duplicate directory entry found */
11151 { PR_2_REPORT_DUP_DIRENT,
11152 N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
11153 PROMPT_NONE, 0 },
11154
11155 /* Pass 3 errors */
11156
11157 /* Pass 3: Checking directory connectivity */
11158 { PR_3_PASS_HEADER,
11159 N_("Pass 3: Checking @d connectivity\n"),
11160 PROMPT_NONE, 0 },
11161
11162 /* Root inode not allocated */
11163 { PR_3_NO_ROOT_INODE,
11164 N_("@r not allocated. "),
11165 PROMPT_ALLOCATE, 0 },
11166
11167 /* No room in lost+found */
11168 { PR_3_EXPAND_LF_DIR,
11169 N_("No room in @l @d. "),
11170 PROMPT_EXPAND, 0 },
11171
11172 /* Unconnected directory inode */
11173 { PR_3_UNCONNECTED_DIR,
11174 N_("Unconnected @d @i %i (%p)\n"),
11175 PROMPT_CONNECT, 0 },
11176
11177 /* /lost+found not found */
11178 { PR_3_NO_LF_DIR,
11179 N_("/@l not found. "),
11180 PROMPT_CREATE, PR_PREEN_OK },
11181
11182 /* .. entry is incorrect */
11183 { PR_3_BAD_DOT_DOT,
11184 N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
11185 PROMPT_FIX, 0 },
11186
11187 /* Bad or non-existent /lost+found. Cannot reconnect */
11188 { PR_3_NO_LPF,
11189 N_("Bad or non-existent /@l. Cannot reconnect.\n"),
11190 PROMPT_NONE, 0 },
11191
11192 /* Could not expand /lost+found */
11193 { PR_3_CANT_EXPAND_LPF,
11194 N_("Could not expand /@l: %m\n"),
11195 PROMPT_NONE, 0 },
11196
11197 /* Could not reconnect inode */
11198 { PR_3_CANT_RECONNECT,
11199 N_("Could not reconnect %i: %m\n"),
11200 PROMPT_NONE, 0 },
11201
11202 /* Error while trying to find /lost+found */
11203 { PR_3_ERR_FIND_LPF,
11204 N_("Error while trying to find /@l: %m\n"),
11205 PROMPT_NONE, 0 },
11206
11207 /* Error in ext2fs_new_block while creating /lost+found */
11208 { PR_3_ERR_LPF_NEW_BLOCK,
11209 N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
11210 PROMPT_NONE, 0 },
11211
11212 /* Error in ext2fs_new_inode while creating /lost+found */
11213 { PR_3_ERR_LPF_NEW_INODE,
11214 N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
11215 PROMPT_NONE, 0 },
11216
11217 /* Error in ext2fs_new_dir_block while creating /lost+found */
11218 { PR_3_ERR_LPF_NEW_DIR_BLOCK,
11219 N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
11220 PROMPT_NONE, 0 },
11221
11222 /* Error while writing directory block for /lost+found */
11223 { PR_3_ERR_LPF_WRITE_BLOCK,
11224 N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
11225 PROMPT_NONE, 0 },
11226
11227 /* Error while adjusting inode count */
11228 { PR_3_ADJUST_INODE,
11229 N_("Error while adjusting @i count on @i %i\n"),
11230 PROMPT_NONE, 0 },
11231
11232 /* Couldn't fix parent directory -- error */
11233 { PR_3_FIX_PARENT_ERR,
11234 N_("Couldn't fix parent of @i %i: %m\n\n"),
11235 PROMPT_NONE, 0 },
11236
11237 /* Couldn't fix parent directory -- couldn't find it */
11238 { PR_3_FIX_PARENT_NOFIND,
11239 N_("Couldn't fix parent of @i %i: Couldn't find parent @d entry\n\n"),
11240 PROMPT_NONE, 0 },
11241
11242 /* Error allocating inode bitmap */
11243 { PR_3_ALLOCATE_IBITMAP_ERROR,
11244 N_("@A @i @B (%N): %m\n"),
11245 PROMPT_NONE, PR_FATAL },
11246
11247 /* Error creating root directory */
11248 { PR_3_CREATE_ROOT_ERROR,
11249 N_("Error creating root @d (%s): %m\n"),
11250 PROMPT_NONE, PR_FATAL },
11251
11252 /* Error creating lost and found directory */
11253 { PR_3_CREATE_LPF_ERROR,
11254 N_("Error creating /@l @d (%s): %m\n"),
11255 PROMPT_NONE, PR_FATAL },
11256
11257 /* Root inode is not directory; aborting */
11258 { PR_3_ROOT_NOT_DIR_ABORT,
11259 N_("@r is not a @d; aborting.\n"),
11260 PROMPT_NONE, PR_FATAL },
11261
11262 /* Cannot proceed without a root inode. */
11263 { PR_3_NO_ROOT_INODE_ABORT,
11264 N_("Cannot proceed without a @r.\n"),
11265 PROMPT_NONE, PR_FATAL },
11266
11267 /* Internal error: couldn't find dir_info */
11268 { PR_3_NO_DIRINFO,
11269 N_("Internal error: couldn't find dir_info for %i.\n"),
11270 PROMPT_NONE, PR_FATAL },
11271
11272 /* Lost+found not a directory */
11273 { PR_3_LPF_NOTDIR,
11274 N_("/@l is not a @d (ino=%i)\n"),
11275 PROMPT_UNLINK, 0 },
11276
11277 /* Pass 3A Directory Optimization */
11278
11279 /* Pass 3A: Optimizing directories */
11280 { PR_3A_PASS_HEADER,
11281 N_("Pass 3A: Optimizing directories\n"),
11282 PROMPT_NONE, PR_PREEN_NOMSG },
11283
11284 /* Error iterating over directories */
11285 { PR_3A_OPTIMIZE_ITER,
11286 N_("Failed to create dirs_to_hash iterator: %m"),
11287 PROMPT_NONE, 0 },
11288
11289 /* Error rehash directory */
11290 { PR_3A_OPTIMIZE_DIR_ERR,
11291 N_("Failed to optimize directory %q (%d): %m"),
11292 PROMPT_NONE, 0 },
11293
11294 /* Rehashing dir header */
11295 { PR_3A_OPTIMIZE_DIR_HEADER,
11296 N_("Optimizing directories: "),
11297 PROMPT_NONE, PR_MSG_ONLY },
11298
11299 /* Rehashing directory %d */
11300 { PR_3A_OPTIMIZE_DIR,
11301 " %d",
11302 PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
11303
11304 /* Rehashing dir end */
11305 { PR_3A_OPTIMIZE_DIR_END,
11306 "\n",
11307 PROMPT_NONE, PR_PREEN_NOHDR },
11308
11309 /* Pass 4 errors */
11310
11311 /* Pass 4: Checking reference counts */
11312 { PR_4_PASS_HEADER,
11313 N_("Pass 4: Checking reference counts\n"),
11314 PROMPT_NONE, 0 },
11315
11316 /* Unattached zero-length inode */
11317 { PR_4_ZERO_LEN_INODE,
11318 "@u @z @i %i. ",
11319 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
11320
11321 /* Unattached inode */
11322 { PR_4_UNATTACHED_INODE,
11323 "@u @i %i\n",
11324 PROMPT_CONNECT, 0 },
11325
11326 /* Inode ref count wrong */
11327 { PR_4_BAD_REF_COUNT,
11328 N_("@i %i ref count is %Il, @s %N. "),
11329 PROMPT_FIX, PR_PREEN_OK },
11330
11331 { PR_4_INCONSISTENT_COUNT,
11332 N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
11333 "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
11334 "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
11335 "They should be the same!\n"),
11336 PROMPT_NONE, 0 },
11337
11338 /* Pass 5 errors */
11339
11340 /* Pass 5: Checking group summary information */
11341 { PR_5_PASS_HEADER,
11342 N_("Pass 5: Checking @g summary information\n"),
11343 PROMPT_NONE, 0 },
11344
11345 /* Padding at end of inode bitmap is not set. */
11346 { PR_5_INODE_BMAP_PADDING,
11347 N_("Padding at end of @i @B is not set. "),
11348 PROMPT_FIX, PR_PREEN_OK },
11349
11350 /* Padding at end of block bitmap is not set. */
11351 { PR_5_BLOCK_BMAP_PADDING,
11352 N_("Padding at end of @b @B is not set. "),
11353 PROMPT_FIX, PR_PREEN_OK },
11354
11355 /* Block bitmap differences header */
11356 { PR_5_BLOCK_BITMAP_HEADER,
11357 N_("@b @B differences: "),
11358 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
11359
11360 /* Block not used, but marked in bitmap */
11361 { PR_5_BLOCK_UNUSED,
11362 " -%b",
11363 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11364
11365 /* Block used, but not marked used in bitmap */
11366 { PR_5_BLOCK_USED,
11367 " +%b",
11368 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11369
11370 /* Block bitmap differences end */
11371 { PR_5_BLOCK_BITMAP_END,
11372 "\n",
11373 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11374
11375 /* Inode bitmap differences header */
11376 { PR_5_INODE_BITMAP_HEADER,
11377 N_("@i @B differences: "),
11378 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
11379
11380 /* Inode not used, but marked in bitmap */
11381 { PR_5_INODE_UNUSED,
11382 " -%i",
11383 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11384
11385 /* Inode used, but not marked used in bitmap */
11386 { PR_5_INODE_USED,
11387 " +%i",
11388 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11389
11390 /* Inode bitmap differences end */
11391 { PR_5_INODE_BITMAP_END,
11392 "\n",
11393 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11394
11395 /* Free inodes count for group wrong */
11396 { PR_5_FREE_INODE_COUNT_GROUP,
11397 N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
11398 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11399
11400 /* Directories count for group wrong */
11401 { PR_5_FREE_DIR_COUNT_GROUP,
11402 N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
11403 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11404
11405 /* Free inodes count wrong */
11406 { PR_5_FREE_INODE_COUNT,
11407 N_("Free @is count wrong (%i, counted=%j).\n"),
11408 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11409
11410 /* Free blocks count for group wrong */
11411 { PR_5_FREE_BLOCK_COUNT_GROUP,
11412 N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
11413 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11414
11415 /* Free blocks count wrong */
11416 { PR_5_FREE_BLOCK_COUNT,
11417 N_("Free @bs count wrong (%b, counted=%c).\n"),
11418 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11419
11420 /* Programming error: bitmap endpoints don't match */
11421 { PR_5_BMAP_ENDPOINTS,
11422 N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
11423 "match calculated @B endpoints (%i, %j)\n"),
11424 PROMPT_NONE, PR_FATAL },
11425
11426 /* Internal error: fudging end of bitmap */
11427 { PR_5_FUDGE_BITMAP_ERROR,
11428 N_("Internal error: fudging end of bitmap (%N)\n"),
11429 PROMPT_NONE, PR_FATAL },
11430
11431 /* Error copying in replacement inode bitmap */
11432 { PR_5_COPY_IBITMAP_ERROR,
11433 "Error copying in replacement @i @B: %m\n",
11434 PROMPT_NONE, PR_FATAL },
11435
11436 /* Error copying in replacement block bitmap */
11437 { PR_5_COPY_BBITMAP_ERROR,
11438 "Error copying in replacement @b @B: %m\n",
11439 PROMPT_NONE, PR_FATAL },
11440
11441 /* Block range not used, but marked in bitmap */
11442 { PR_5_BLOCK_RANGE_UNUSED,
11443 " -(%b--%c)",
11444 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11445
11446 /* Block range used, but not marked used in bitmap */
11447 { PR_5_BLOCK_RANGE_USED,
11448 " +(%b--%c)",
11449 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11450
11451 /* Inode range not used, but marked in bitmap */
11452 { PR_5_INODE_RANGE_UNUSED,
11453 " -(%i--%j)",
11454 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11455
11456 /* Inode range used, but not marked used in bitmap */
11457 { PR_5_INODE_RANGE_USED,
11458 " +(%i--%j)",
11459 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11460
11461 { 0 }
11462};
11463
11464/*
11465 * This is the latch flags register. It allows several problems to be
11466 * "latched" together. This means that the user has to answer but one
11467 * question for the set of problems, and all of the associated
11468 * problems will be either fixed or not fixed.
11469 */
11470static struct latch_descr pr_latch_info[] = {
11471 { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
11472 { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
11473 { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
11474 { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
11475 { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
11476 { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
11477 { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
11478 { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
11479 { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
11480 { -1, 0, 0 },
11481};
11482
11483static const struct e2fsck_problem *find_problem(problem_t code)
11484{
11485 int i;
11486
11487 for (i=0; problem_table[i].e2p_code; i++) {
11488 if (problem_table[i].e2p_code == code)
11489 return &problem_table[i];
11490 }
11491 return 0;
11492}
11493
11494static struct latch_descr *find_latch(int code)
11495{
11496 int i;
11497
11498 for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
11499 if (pr_latch_info[i].latch_code == code)
11500 return &pr_latch_info[i];
11501 }
11502 return 0;
11503}
11504
11505int end_problem_latch(e2fsck_t ctx, int mask)
11506{
11507 struct latch_descr *ldesc;
11508 struct problem_context pctx;
11509 int answer = -1;
11510
11511 ldesc = find_latch(mask);
11512 if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
11513 clear_problem_context(&pctx);
11514 answer = fix_problem(ctx, ldesc->end_message, &pctx);
11515 }
11516 ldesc->flags &= ~(PRL_VARIABLE);
11517 return answer;
11518}
11519
11520int set_latch_flags(int mask, int setflags, int clearflags)
11521{
11522 struct latch_descr *ldesc;
11523
11524 ldesc = find_latch(mask);
11525 if (!ldesc)
11526 return -1;
11527 ldesc->flags |= setflags;
11528 ldesc->flags &= ~clearflags;
11529 return 0;
11530}
11531
11532void clear_problem_context(struct problem_context *ctx)
11533{
11534 memset(ctx, 0, sizeof(struct problem_context));
11535 ctx->blkcount = -1;
11536 ctx->group = -1;
11537}
11538
11539int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
11540{
11541 ext2_filsys fs = ctx->fs;
11542 const struct e2fsck_problem *ptr;
11543 struct latch_descr *ldesc = 0;
11544 const char *message;
11545 int def_yn, answer, ans;
11546 int print_answer = 0;
11547 int suppress = 0;
11548
11549 ptr = find_problem(code);
11550 if (!ptr) {
11551 printf(_("Unhandled error code (0x%x)!\n"), code);
11552 return 0;
11553 }
11554 def_yn = 1;
11555 if ((ptr->flags & PR_NO_DEFAULT) ||
11556 ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
11557 (ctx->options & E2F_OPT_NO))
11558 def_yn= 0;
11559
11560 /*
11561 * Do special latch processing. This is where we ask the
11562 * latch question, if it exists
11563 */
11564 if (ptr->flags & PR_LATCH_MASK) {
11565 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
11566 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
11567 ans = fix_problem(ctx, ldesc->question, pctx);
11568 if (ans == 1)
11569 ldesc->flags |= PRL_YES;
11570 if (ans == 0)
11571 ldesc->flags |= PRL_NO;
11572 ldesc->flags |= PRL_LATCHED;
11573 }
11574 if (ldesc->flags & PRL_SUPPRESS)
11575 suppress++;
11576 }
11577 if ((ptr->flags & PR_PREEN_NOMSG) &&
11578 (ctx->options & E2F_OPT_PREEN))
11579 suppress++;
11580 if ((ptr->flags & PR_NO_NOMSG) &&
11581 (ctx->options & E2F_OPT_NO))
11582 suppress++;
11583 if (!suppress) {
11584 message = ptr->e2p_description;
11585 if ((ctx->options & E2F_OPT_PREEN) &&
11586 !(ptr->flags & PR_PREEN_NOHDR)) {
11587 printf("%s: ", ctx->device_name ?
11588 ctx->device_name : ctx->filesystem_name);
11589 }
11590 if (*message)
11591 print_e2fsck_message(ctx, _(message), pctx, 1);
11592 }
11593 if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
11594 preenhalt(ctx);
11595
11596 if (ptr->flags & PR_FATAL)
11597 fatal_error(ctx, 0);
11598
11599 if (ptr->prompt == PROMPT_NONE) {
11600 if (ptr->flags & PR_NOCOLLATE)
11601 answer = -1;
11602 else
11603 answer = def_yn;
11604 } else {
11605 if (ctx->options & E2F_OPT_PREEN) {
11606 answer = def_yn;
11607 if (!(ptr->flags & PR_PREEN_NOMSG))
11608 print_answer = 1;
11609 } else if ((ptr->flags & PR_LATCH_MASK) &&
11610 (ldesc->flags & (PRL_YES | PRL_NO))) {
11611 if (!suppress)
11612 print_answer = 1;
11613 if (ldesc->flags & PRL_YES)
11614 answer = 1;
11615 else
11616 answer = 0;
11617 } else
11618 answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
11619 if (!answer && !(ptr->flags & PR_NO_OK))
11620 ext2fs_unmark_valid(fs);
11621
11622 if (print_answer)
11623 printf("%s.\n", answer ?
11624 _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
11625
11626 }
11627
11628 if ((ptr->prompt == PROMPT_ABORT) && answer)
11629 fatal_error(ctx, 0);
11630
11631 if (ptr->flags & PR_AFTER_CODE)
11632 answer = fix_problem(ctx, ptr->second_code, pctx);
11633
11634 return answer;
11635}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011636
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011637/*
11638 * linux/fs/recovery.c
11639 *
11640 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011641 */
11642
11643/*
11644 * Maintain information about the progress of the recovery job, so that
11645 * the different passes can carry information between them.
11646 */
11647struct recovery_info
11648{
11649 tid_t start_transaction;
11650 tid_t end_transaction;
11651
11652 int nr_replays;
11653 int nr_revokes;
11654 int nr_revoke_hits;
11655};
11656
11657enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
11658static int do_one_pass(journal_t *journal,
11659 struct recovery_info *info, enum passtype pass);
11660static int scan_revoke_records(journal_t *, struct buffer_head *,
11661 tid_t, struct recovery_info *);
11662
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011663/*
11664 * Read a block from the journal
11665 */
11666
11667static int jread(struct buffer_head **bhp, journal_t *journal,
11668 unsigned int offset)
11669{
11670 int err;
11671 unsigned long blocknr;
11672 struct buffer_head *bh;
11673
11674 *bhp = NULL;
11675
11676 J_ASSERT (offset < journal->j_maxlen);
11677
11678 err = journal_bmap(journal, offset, &blocknr);
11679
11680 if (err) {
11681 printk (KERN_ERR "JBD: bad block at offset %u\n",
11682 offset);
11683 return err;
11684 }
11685
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011686 bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011687 if (!bh)
11688 return -ENOMEM;
11689
11690 if (!buffer_uptodate(bh)) {
11691 /* If this is a brand new buffer, start readahead.
11692 Otherwise, we assume we are already reading it. */
11693 if (!buffer_req(bh))
11694 do_readahead(journal, offset);
11695 wait_on_buffer(bh);
11696 }
11697
11698 if (!buffer_uptodate(bh)) {
11699 printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
11700 offset);
11701 brelse(bh);
11702 return -EIO;
11703 }
11704
11705 *bhp = bh;
11706 return 0;
11707}
11708
11709
11710/*
11711 * Count the number of in-use tags in a journal descriptor block.
11712 */
11713
11714static int count_tags(struct buffer_head *bh, int size)
11715{
11716 char * tagp;
11717 journal_block_tag_t * tag;
11718 int nr = 0;
11719
11720 tagp = &bh->b_data[sizeof(journal_header_t)];
11721
11722 while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
11723 tag = (journal_block_tag_t *) tagp;
11724
11725 nr++;
11726 tagp += sizeof(journal_block_tag_t);
11727 if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
11728 tagp += 16;
11729
11730 if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
11731 break;
11732 }
11733
11734 return nr;
11735}
11736
11737
11738/* Make sure we wrap around the log correctly! */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000011739#define wrap(journal, var) \
11740do { \
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011741 if (var >= (journal)->j_last) \
11742 var -= ((journal)->j_last - (journal)->j_first); \
11743} while (0)
11744
11745/**
11746 * int journal_recover(journal_t *journal) - recovers a on-disk journal
11747 * @journal: the journal to recover
11748 *
11749 * The primary function for recovering the log contents when mounting a
11750 * journaled device.
11751 *
11752 * Recovery is done in three passes. In the first pass, we look for the
11753 * end of the log. In the second, we assemble the list of revoke
11754 * blocks. In the third and final pass, we replay any un-revoked blocks
11755 * in the log.
11756 */
11757int journal_recover(journal_t *journal)
11758{
11759 int err;
11760 journal_superblock_t * sb;
11761
11762 struct recovery_info info;
11763
11764 memset(&info, 0, sizeof(info));
11765 sb = journal->j_superblock;
11766
11767 /*
11768 * The journal superblock's s_start field (the current log head)
11769 * is always zero if, and only if, the journal was cleanly
11770 * unmounted.
11771 */
11772
11773 if (!sb->s_start) {
11774 jbd_debug(1, "No recovery required, last transaction %d\n",
11775 ntohl(sb->s_sequence));
11776 journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
11777 return 0;
11778 }
11779
11780 err = do_one_pass(journal, &info, PASS_SCAN);
11781 if (!err)
11782 err = do_one_pass(journal, &info, PASS_REVOKE);
11783 if (!err)
11784 err = do_one_pass(journal, &info, PASS_REPLAY);
11785
11786 jbd_debug(0, "JBD: recovery, exit status %d, "
11787 "recovered transactions %u to %u\n",
11788 err, info.start_transaction, info.end_transaction);
11789 jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
11790 info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
11791
11792 /* Restart the log at the next transaction ID, thus invalidating
11793 * any existing commit records in the log. */
11794 journal->j_transaction_sequence = ++info.end_transaction;
11795
11796 journal_clear_revoke(journal);
11797 sync_blockdev(journal->j_fs_dev);
11798 return err;
11799}
11800
11801static int do_one_pass(journal_t *journal,
11802 struct recovery_info *info, enum passtype pass)
11803{
11804 unsigned int first_commit_ID, next_commit_ID;
11805 unsigned long next_log_block;
11806 int err, success = 0;
11807 journal_superblock_t * sb;
11808 journal_header_t * tmp;
11809 struct buffer_head * bh;
11810 unsigned int sequence;
11811 int blocktype;
11812
11813 /* Precompute the maximum metadata descriptors in a descriptor block */
11814 int MAX_BLOCKS_PER_DESC;
11815 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
11816 / sizeof(journal_block_tag_t));
11817
11818 /*
11819 * First thing is to establish what we expect to find in the log
11820 * (in terms of transaction IDs), and where (in terms of log
11821 * block offsets): query the superblock.
11822 */
11823
11824 sb = journal->j_superblock;
11825 next_commit_ID = ntohl(sb->s_sequence);
11826 next_log_block = ntohl(sb->s_start);
11827
11828 first_commit_ID = next_commit_ID;
11829 if (pass == PASS_SCAN)
11830 info->start_transaction = first_commit_ID;
11831
11832 jbd_debug(1, "Starting recovery pass %d\n", pass);
11833
11834 /*
11835 * Now we walk through the log, transaction by transaction,
11836 * making sure that each transaction has a commit block in the
11837 * expected place. Each complete transaction gets replayed back
11838 * into the main filesystem.
11839 */
11840
11841 while (1) {
11842 int flags;
11843 char * tagp;
11844 journal_block_tag_t * tag;
11845 struct buffer_head * obh;
11846 struct buffer_head * nbh;
11847
11848 /* If we already know where to stop the log traversal,
11849 * check right now that we haven't gone past the end of
11850 * the log. */
11851
11852 if (pass != PASS_SCAN)
11853 if (tid_geq(next_commit_ID, info->end_transaction))
11854 break;
11855
11856 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
11857 next_commit_ID, next_log_block, journal->j_last);
11858
11859 /* Skip over each chunk of the transaction looking
11860 * either the next descriptor block or the final commit
11861 * record. */
11862
11863 jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
11864 err = jread(&bh, journal, next_log_block);
11865 if (err)
11866 goto failed;
11867
11868 next_log_block++;
11869 wrap(journal, next_log_block);
11870
11871 /* What kind of buffer is it?
11872 *
11873 * If it is a descriptor block, check that it has the
11874 * expected sequence number. Otherwise, we're all done
11875 * here. */
11876
11877 tmp = (journal_header_t *)bh->b_data;
11878
11879 if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
11880 brelse(bh);
11881 break;
11882 }
11883
11884 blocktype = ntohl(tmp->h_blocktype);
11885 sequence = ntohl(tmp->h_sequence);
11886 jbd_debug(3, "Found magic %d, sequence %d\n",
11887 blocktype, sequence);
11888
11889 if (sequence != next_commit_ID) {
11890 brelse(bh);
11891 break;
11892 }
11893
11894 /* OK, we have a valid descriptor block which matches
11895 * all of the sequence number checks. What are we going
11896 * to do with it? That depends on the pass... */
11897
11898 switch(blocktype) {
11899 case JFS_DESCRIPTOR_BLOCK:
11900 /* If it is a valid descriptor block, replay it
11901 * in pass REPLAY; otherwise, just skip over the
11902 * blocks it describes. */
11903 if (pass != PASS_REPLAY) {
11904 next_log_block +=
11905 count_tags(bh, journal->j_blocksize);
11906 wrap(journal, next_log_block);
11907 brelse(bh);
11908 continue;
11909 }
11910
11911 /* A descriptor block: we can now write all of
11912 * the data blocks. Yay, useful work is finally
11913 * getting done here! */
11914
11915 tagp = &bh->b_data[sizeof(journal_header_t)];
11916 while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
11917 <= journal->j_blocksize) {
11918 unsigned long io_block;
11919
11920 tag = (journal_block_tag_t *) tagp;
11921 flags = ntohl(tag->t_flags);
11922
11923 io_block = next_log_block++;
11924 wrap(journal, next_log_block);
11925 err = jread(&obh, journal, io_block);
11926 if (err) {
11927 /* Recover what we can, but
11928 * report failure at the end. */
11929 success = err;
11930 printk (KERN_ERR
11931 "JBD: IO error %d recovering "
11932 "block %ld in log\n",
11933 err, io_block);
11934 } else {
11935 unsigned long blocknr;
11936
11937 J_ASSERT(obh != NULL);
11938 blocknr = ntohl(tag->t_blocknr);
11939
11940 /* If the block has been
11941 * revoked, then we're all done
11942 * here. */
11943 if (journal_test_revoke
11944 (journal, blocknr,
11945 next_commit_ID)) {
11946 brelse(obh);
11947 ++info->nr_revoke_hits;
11948 goto skip_write;
11949 }
11950
11951 /* Find a buffer for the new
11952 * data being restored */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011953 nbh = getblk(journal->j_fs_dev,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011954 blocknr,
11955 journal->j_blocksize);
11956 if (nbh == NULL) {
11957 printk(KERN_ERR
11958 "JBD: Out of memory "
11959 "during recovery.\n");
11960 err = -ENOMEM;
11961 brelse(bh);
11962 brelse(obh);
11963 goto failed;
11964 }
11965
11966 lock_buffer(nbh);
11967 memcpy(nbh->b_data, obh->b_data,
11968 journal->j_blocksize);
11969 if (flags & JFS_FLAG_ESCAPE) {
11970 *((unsigned int *)bh->b_data) =
11971 htonl(JFS_MAGIC_NUMBER);
11972 }
11973
11974 BUFFER_TRACE(nbh, "marking dirty");
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011975 mark_buffer_uptodate(nbh, 1);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011976 mark_buffer_dirty(nbh);
11977 BUFFER_TRACE(nbh, "marking uptodate");
11978 ++info->nr_replays;
11979 /* ll_rw_block(WRITE, 1, &nbh); */
11980 unlock_buffer(nbh);
11981 brelse(obh);
11982 brelse(nbh);
11983 }
11984
11985 skip_write:
11986 tagp += sizeof(journal_block_tag_t);
11987 if (!(flags & JFS_FLAG_SAME_UUID))
11988 tagp += 16;
11989
11990 if (flags & JFS_FLAG_LAST_TAG)
11991 break;
11992 }
11993
11994 brelse(bh);
11995 continue;
11996
11997 case JFS_COMMIT_BLOCK:
11998 /* Found an expected commit block: not much to
11999 * do other than move on to the next sequence
12000 * number. */
12001 brelse(bh);
12002 next_commit_ID++;
12003 continue;
12004
12005 case JFS_REVOKE_BLOCK:
12006 /* If we aren't in the REVOKE pass, then we can
12007 * just skip over this block. */
12008 if (pass != PASS_REVOKE) {
12009 brelse(bh);
12010 continue;
12011 }
12012
12013 err = scan_revoke_records(journal, bh,
12014 next_commit_ID, info);
12015 brelse(bh);
12016 if (err)
12017 goto failed;
12018 continue;
12019
12020 default:
12021 jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
12022 blocktype);
12023 goto done;
12024 }
12025 }
12026
12027 done:
12028 /*
12029 * We broke out of the log scan loop: either we came to the
12030 * known end of the log or we found an unexpected block in the
12031 * log. If the latter happened, then we know that the "current"
12032 * transaction marks the end of the valid log.
12033 */
12034
12035 if (pass == PASS_SCAN)
12036 info->end_transaction = next_commit_ID;
12037 else {
12038 /* It's really bad news if different passes end up at
12039 * different places (but possible due to IO errors). */
12040 if (info->end_transaction != next_commit_ID) {
12041 printk (KERN_ERR "JBD: recovery pass %d ended at "
12042 "transaction %u, expected %u\n",
12043 pass, next_commit_ID, info->end_transaction);
12044 if (!success)
12045 success = -EIO;
12046 }
12047 }
12048
12049 return success;
12050
12051 failed:
12052 return err;
12053}
12054
12055
12056/* Scan a revoke record, marking all blocks mentioned as revoked. */
12057
12058static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
12059 tid_t sequence, struct recovery_info *info)
12060{
12061 journal_revoke_header_t *header;
12062 int offset, max;
12063
12064 header = (journal_revoke_header_t *) bh->b_data;
12065 offset = sizeof(journal_revoke_header_t);
12066 max = ntohl(header->r_count);
12067
12068 while (offset < max) {
12069 unsigned long blocknr;
12070 int err;
12071
12072 blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
12073 offset += 4;
12074 err = journal_set_revoke(journal, blocknr, sequence);
12075 if (err)
12076 return err;
12077 ++info->nr_revokes;
12078 }
12079 return 0;
12080}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012081
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012082
12083/*
12084 * rehash.c --- rebuild hash tree directories
12085 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012086 * This algorithm is designed for simplicity of implementation and to
12087 * pack the directory as much as possible. It however requires twice
12088 * as much memory as the size of the directory. The maximum size
12089 * directory supported using a 4k blocksize is roughly a gigabyte, and
12090 * so there may very well be problems with machines that don't have
12091 * virtual memory, and obscenely large directories.
12092 *
12093 * An alternate algorithm which is much more disk intensive could be
12094 * written, and probably will need to be written in the future. The
12095 * design goals of such an algorithm are: (a) use (roughly) constant
12096 * amounts of memory, no matter how large the directory, (b) the
12097 * directory must be safe at all times, even if e2fsck is interrupted
12098 * in the middle, (c) we must use minimal amounts of extra disk
12099 * blocks. This pretty much requires an incremental approach, where
12100 * we are reading from one part of the directory, and inserting into
12101 * the front half. So the algorithm will have to keep track of a
12102 * moving block boundary between the new tree and the old tree, and
12103 * files will need to be moved from the old directory and inserted
12104 * into the new tree. If the new directory requires space which isn't
12105 * yet available, blocks from the beginning part of the old directory
12106 * may need to be moved to the end of the directory to make room for
12107 * the new tree:
12108 *
12109 * --------------------------------------------------------
12110 * | new tree | | old tree |
12111 * --------------------------------------------------------
12112 * ^ ptr ^ptr
12113 * tail new head old
12114 *
12115 * This is going to be a pain in the tuckus to implement, and will
12116 * require a lot more disk accesses. So I'm going to skip it for now;
12117 * it's only really going to be an issue for really, really big
12118 * filesystems (when we reach the level of tens of millions of files
12119 * in a single directory). It will probably be easier to simply
12120 * require that e2fsck use VM first.
12121 */
12122
12123struct fill_dir_struct {
12124 char *buf;
12125 struct ext2_inode *inode;
12126 int err;
12127 e2fsck_t ctx;
12128 struct hash_entry *harray;
12129 int max_array, num_array;
12130 int dir_size;
12131 int compress;
12132 ino_t parent;
12133};
12134
12135struct hash_entry {
12136 ext2_dirhash_t hash;
12137 ext2_dirhash_t minor_hash;
12138 struct ext2_dir_entry *dir;
12139};
12140
12141struct out_dir {
12142 int num;
12143 int max;
12144 char *buf;
12145 ext2_dirhash_t *hashes;
12146};
12147
12148static int fill_dir_block(ext2_filsys fs,
12149 blk_t *block_nr,
12150 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000012151 blk_t ref_block FSCK_ATTR((unused)),
12152 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012153 void *priv_data)
12154{
12155 struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
12156 struct hash_entry *new_array, *ent;
12157 struct ext2_dir_entry *dirent;
12158 char *dir;
12159 unsigned int offset, dir_offset;
12160
12161 if (blockcnt < 0)
12162 return 0;
12163
12164 offset = blockcnt * fs->blocksize;
12165 if (offset + fs->blocksize > fd->inode->i_size) {
12166 fd->err = EXT2_ET_DIR_CORRUPTED;
12167 return BLOCK_ABORT;
12168 }
12169 dir = (fd->buf+offset);
12170 if (HOLE_BLKADDR(*block_nr)) {
12171 memset(dir, 0, fs->blocksize);
12172 dirent = (struct ext2_dir_entry *) dir;
12173 dirent->rec_len = fs->blocksize;
12174 } else {
12175 fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
12176 if (fd->err)
12177 return BLOCK_ABORT;
12178 }
12179 /* While the directory block is "hot", index it. */
12180 dir_offset = 0;
12181 while (dir_offset < fs->blocksize) {
12182 dirent = (struct ext2_dir_entry *) (dir + dir_offset);
12183 if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
12184 (dirent->rec_len < 8) ||
12185 ((dirent->rec_len % 4) != 0) ||
12186 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
12187 fd->err = EXT2_ET_DIR_CORRUPTED;
12188 return BLOCK_ABORT;
12189 }
12190 dir_offset += dirent->rec_len;
12191 if (dirent->inode == 0)
12192 continue;
12193 if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
12194 (dirent->name[0] == '.'))
12195 continue;
12196 if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
12197 (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
12198 fd->parent = dirent->inode;
12199 continue;
12200 }
12201 if (fd->num_array >= fd->max_array) {
12202 new_array = realloc(fd->harray,
12203 sizeof(struct hash_entry) * (fd->max_array+500));
12204 if (!new_array) {
12205 fd->err = ENOMEM;
12206 return BLOCK_ABORT;
12207 }
12208 fd->harray = new_array;
12209 fd->max_array += 500;
12210 }
12211 ent = fd->harray + fd->num_array++;
12212 ent->dir = dirent;
12213 fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
12214 if (fd->compress)
12215 ent->hash = ent->minor_hash = 0;
12216 else {
12217 fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
12218 dirent->name,
12219 dirent->name_len & 0xFF,
12220 fs->super->s_hash_seed,
12221 &ent->hash, &ent->minor_hash);
12222 if (fd->err)
12223 return BLOCK_ABORT;
12224 }
12225 }
12226
12227 return 0;
12228}
12229
12230/* Used for sorting the hash entry */
12231static EXT2_QSORT_TYPE name_cmp(const void *a, const void *b)
12232{
12233 const struct hash_entry *he_a = (const struct hash_entry *) a;
12234 const struct hash_entry *he_b = (const struct hash_entry *) b;
12235 int ret;
12236 int min_len;
12237
12238 min_len = he_a->dir->name_len;
12239 if (min_len > he_b->dir->name_len)
12240 min_len = he_b->dir->name_len;
12241
12242 ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
12243 if (ret == 0) {
12244 if (he_a->dir->name_len > he_b->dir->name_len)
12245 ret = 1;
12246 else if (he_a->dir->name_len < he_b->dir->name_len)
12247 ret = -1;
12248 else
12249 ret = he_b->dir->inode - he_a->dir->inode;
12250 }
12251 return ret;
12252}
12253
12254/* Used for sorting the hash entry */
12255static EXT2_QSORT_TYPE hash_cmp(const void *a, const void *b)
12256{
12257 const struct hash_entry *he_a = (const struct hash_entry *) a;
12258 const struct hash_entry *he_b = (const struct hash_entry *) b;
12259 int ret;
12260
12261 if (he_a->hash > he_b->hash)
12262 ret = 1;
12263 else if (he_a->hash < he_b->hash)
12264 ret = -1;
12265 else {
12266 if (he_a->minor_hash > he_b->minor_hash)
12267 ret = 1;
12268 else if (he_a->minor_hash < he_b->minor_hash)
12269 ret = -1;
12270 else
12271 ret = name_cmp(a, b);
12272 }
12273 return ret;
12274}
12275
12276static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
12277 int blocks)
12278{
12279 void *new_mem;
12280
12281 if (outdir->max) {
12282 new_mem = realloc(outdir->buf, blocks * fs->blocksize);
12283 if (!new_mem)
12284 return ENOMEM;
12285 outdir->buf = new_mem;
12286 new_mem = realloc(outdir->hashes,
12287 blocks * sizeof(ext2_dirhash_t));
12288 if (!new_mem)
12289 return ENOMEM;
12290 outdir->hashes = new_mem;
12291 } else {
12292 outdir->buf = malloc(blocks * fs->blocksize);
12293 outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
12294 outdir->num = 0;
12295 }
12296 outdir->max = blocks;
12297 return 0;
12298}
12299
12300static void free_out_dir(struct out_dir *outdir)
12301{
Rob Landleye7c43b62006-03-01 16:39:45 +000012302 free(outdir->buf);
12303 free(outdir->hashes);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012304 outdir->max = 0;
12305 outdir->num =0;
12306}
12307
12308static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
12309 char ** ret)
12310{
12311 errcode_t retval;
12312
12313 if (outdir->num >= outdir->max) {
12314 retval = alloc_size_dir(fs, outdir, outdir->max + 50);
12315 if (retval)
12316 return retval;
12317 }
12318 *ret = outdir->buf + (outdir->num++ * fs->blocksize);
12319 memset(*ret, 0, fs->blocksize);
12320 return 0;
12321}
12322
12323/*
12324 * This function is used to make a unique filename. We do this by
12325 * appending ~0, and then incrementing the number. However, we cannot
12326 * expand the length of the filename beyond the padding available in
12327 * the directory entry.
12328 */
12329static void mutate_name(char *str, __u16 *len)
12330{
12331 int i;
12332 __u16 l = *len & 0xFF, h = *len & 0xff00;
12333
12334 /*
12335 * First check to see if it looks the name has been mutated
12336 * already
12337 */
12338 for (i = l-1; i > 0; i--) {
12339 if (!isdigit(str[i]))
12340 break;
12341 }
12342 if ((i == l-1) || (str[i] != '~')) {
12343 if (((l-1) & 3) < 2)
12344 l += 2;
12345 else
12346 l = (l+3) & ~3;
12347 str[l-2] = '~';
12348 str[l-1] = '0';
12349 *len = l | h;
12350 return;
12351 }
12352 for (i = l-1; i >= 0; i--) {
12353 if (isdigit(str[i])) {
12354 if (str[i] == '9')
12355 str[i] = '0';
12356 else {
12357 str[i]++;
12358 return;
12359 }
12360 continue;
12361 }
12362 if (i == 1) {
12363 if (str[0] == 'z')
12364 str[0] = 'A';
12365 else if (str[0] == 'Z') {
12366 str[0] = '~';
12367 str[1] = '0';
12368 } else
12369 str[0]++;
12370 } else if (i > 0) {
12371 str[i] = '1';
12372 str[i-1] = '~';
12373 } else {
12374 if (str[0] == '~')
12375 str[0] = 'a';
12376 else
12377 str[0]++;
12378 }
12379 break;
12380 }
12381}
12382
12383static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
12384 ext2_ino_t ino,
12385 struct fill_dir_struct *fd)
12386{
12387 struct problem_context pctx;
12388 struct hash_entry *ent, *prev;
12389 int i, j;
12390 int fixed = 0;
12391 char new_name[256];
12392 __u16 new_len;
12393
12394 clear_problem_context(&pctx);
12395 pctx.ino = ino;
12396
12397 for (i=1; i < fd->num_array; i++) {
12398 ent = fd->harray + i;
12399 prev = ent - 1;
12400 if (!ent->dir->inode ||
12401 ((ent->dir->name_len & 0xFF) !=
12402 (prev->dir->name_len & 0xFF)) ||
12403 (strncmp(ent->dir->name, prev->dir->name,
12404 ent->dir->name_len & 0xFF)))
12405 continue;
12406 pctx.dirent = ent->dir;
12407 if ((ent->dir->inode == prev->dir->inode) &&
12408 fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
12409 e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
12410 ent->dir->inode = 0;
12411 fixed++;
12412 continue;
12413 }
12414 memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
12415 new_len = ent->dir->name_len;
12416 mutate_name(new_name, &new_len);
12417 for (j=0; j < fd->num_array; j++) {
12418 if ((i==j) ||
12419 ((ent->dir->name_len & 0xFF) !=
12420 (fd->harray[j].dir->name_len & 0xFF)) ||
12421 (strncmp(new_name, fd->harray[j].dir->name,
12422 new_len & 0xFF)))
12423 continue;
12424 mutate_name(new_name, &new_len);
12425
12426 j = -1;
12427 }
12428 new_name[new_len & 0xFF] = 0;
12429 pctx.str = new_name;
12430 if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
12431 memcpy(ent->dir->name, new_name, new_len & 0xFF);
12432 ent->dir->name_len = new_len;
12433 ext2fs_dirhash(fs->super->s_def_hash_version,
12434 ent->dir->name,
12435 ent->dir->name_len & 0xFF,
12436 fs->super->s_hash_seed,
12437 &ent->hash, &ent->minor_hash);
12438 fixed++;
12439 }
12440 }
12441 return fixed;
12442}
12443
12444
12445static errcode_t copy_dir_entries(ext2_filsys fs,
12446 struct fill_dir_struct *fd,
12447 struct out_dir *outdir)
12448{
12449 errcode_t retval;
12450 char *block_start;
12451 struct hash_entry *ent;
12452 struct ext2_dir_entry *dirent;
12453 int i, rec_len, left;
12454 ext2_dirhash_t prev_hash;
12455 int offset;
12456
12457 outdir->max = 0;
12458 retval = alloc_size_dir(fs, outdir,
12459 (fd->dir_size / fs->blocksize) + 2);
12460 if (retval)
12461 return retval;
12462 outdir->num = fd->compress ? 0 : 1;
12463 offset = 0;
12464 outdir->hashes[0] = 0;
12465 prev_hash = 1;
12466 if ((retval = get_next_block(fs, outdir, &block_start)))
12467 return retval;
12468 dirent = (struct ext2_dir_entry *) block_start;
12469 left = fs->blocksize;
12470 for (i=0; i < fd->num_array; i++) {
12471 ent = fd->harray + i;
12472 if (ent->dir->inode == 0)
12473 continue;
12474 rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
12475 if (rec_len > left) {
12476 if (left)
12477 dirent->rec_len += left;
12478 if ((retval = get_next_block(fs, outdir,
12479 &block_start)))
12480 return retval;
12481 offset = 0;
12482 }
12483 left = fs->blocksize - offset;
12484 dirent = (struct ext2_dir_entry *) (block_start + offset);
12485 if (offset == 0) {
12486 if (ent->hash == prev_hash)
12487 outdir->hashes[outdir->num-1] = ent->hash | 1;
12488 else
12489 outdir->hashes[outdir->num-1] = ent->hash;
12490 }
12491 dirent->inode = ent->dir->inode;
12492 dirent->name_len = ent->dir->name_len;
12493 dirent->rec_len = rec_len;
12494 memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
12495 offset += rec_len;
12496 left -= rec_len;
12497 if (left < 12) {
12498 dirent->rec_len += left;
12499 offset += left;
12500 left = 0;
12501 }
12502 prev_hash = ent->hash;
12503 }
12504 if (left)
12505 dirent->rec_len += left;
12506
12507 return 0;
12508}
12509
12510
12511static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
12512 ext2_ino_t ino, ext2_ino_t parent)
12513{
12514 struct ext2_dir_entry *dir;
12515 struct ext2_dx_root_info *root;
12516 struct ext2_dx_countlimit *limits;
12517 int filetype = 0;
12518
12519 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
12520 filetype = EXT2_FT_DIR << 8;
12521
12522 memset(buf, 0, fs->blocksize);
12523 dir = (struct ext2_dir_entry *) buf;
12524 dir->inode = ino;
12525 dir->name[0] = '.';
12526 dir->name_len = 1 | filetype;
12527 dir->rec_len = 12;
12528 dir = (struct ext2_dir_entry *) (buf + 12);
12529 dir->inode = parent;
12530 dir->name[0] = '.';
12531 dir->name[1] = '.';
12532 dir->name_len = 2 | filetype;
12533 dir->rec_len = fs->blocksize - 12;
12534
12535 root = (struct ext2_dx_root_info *) (buf+24);
12536 root->reserved_zero = 0;
12537 root->hash_version = fs->super->s_def_hash_version;
12538 root->info_length = 8;
12539 root->indirect_levels = 0;
12540 root->unused_flags = 0;
12541
12542 limits = (struct ext2_dx_countlimit *) (buf+32);
12543 limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
12544 limits->count = 0;
12545
12546 return root;
12547}
12548
12549
12550static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
12551{
12552 struct ext2_dir_entry *dir;
12553 struct ext2_dx_countlimit *limits;
12554
12555 memset(buf, 0, fs->blocksize);
12556 dir = (struct ext2_dir_entry *) buf;
12557 dir->inode = 0;
12558 dir->rec_len = fs->blocksize;
12559
12560 limits = (struct ext2_dx_countlimit *) (buf+8);
12561 limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
12562 limits->count = 0;
12563
12564 return (struct ext2_dx_entry *) limits;
12565}
12566
12567/*
12568 * This function takes the leaf nodes which have been written in
12569 * outdir, and populates the root node and any necessary interior nodes.
12570 */
12571static errcode_t calculate_tree(ext2_filsys fs,
12572 struct out_dir *outdir,
12573 ext2_ino_t ino,
12574 ext2_ino_t parent)
12575{
12576 struct ext2_dx_root_info *root_info;
12577 struct ext2_dx_entry *root, *dx_ent = 0;
12578 struct ext2_dx_countlimit *root_limit, *limit;
12579 errcode_t retval;
12580 char * block_start;
12581 int i, c1, c2, nblks;
12582 int limit_offset, root_offset;
12583
12584 root_info = set_root_node(fs, outdir->buf, ino, parent);
12585 root_offset = limit_offset = ((char *) root_info - outdir->buf) +
12586 root_info->info_length;
12587 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
12588 c1 = root_limit->limit;
12589 nblks = outdir->num;
12590
12591 /* Write out the pointer blocks */
12592 if (nblks-1 <= c1) {
12593 /* Just write out the root block, and we're done */
12594 root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
12595 for (i=1; i < nblks; i++) {
12596 root->block = ext2fs_cpu_to_le32(i);
12597 if (i != 1)
12598 root->hash =
12599 ext2fs_cpu_to_le32(outdir->hashes[i]);
12600 root++;
12601 c1--;
12602 }
12603 } else {
12604 c2 = 0;
12605 limit = 0;
12606 root_info->indirect_levels = 1;
12607 for (i=1; i < nblks; i++) {
12608 if (c1 == 0)
12609 return ENOSPC;
12610 if (c2 == 0) {
12611 if (limit)
12612 limit->limit = limit->count =
12613 ext2fs_cpu_to_le16(limit->limit);
12614 root = (struct ext2_dx_entry *)
12615 (outdir->buf + root_offset);
12616 root->block = ext2fs_cpu_to_le32(outdir->num);
12617 if (i != 1)
12618 root->hash =
12619 ext2fs_cpu_to_le32(outdir->hashes[i]);
12620 if ((retval = get_next_block(fs, outdir,
12621 &block_start)))
12622 return retval;
12623 dx_ent = set_int_node(fs, block_start);
12624 limit = (struct ext2_dx_countlimit *) dx_ent;
12625 c2 = limit->limit;
12626 root_offset += sizeof(struct ext2_dx_entry);
12627 c1--;
12628 }
12629 dx_ent->block = ext2fs_cpu_to_le32(i);
12630 if (c2 != limit->limit)
12631 dx_ent->hash =
12632 ext2fs_cpu_to_le32(outdir->hashes[i]);
12633 dx_ent++;
12634 c2--;
12635 }
12636 limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
12637 limit->limit = ext2fs_cpu_to_le16(limit->limit);
12638 }
12639 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
12640 root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
12641 root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
12642
12643 return 0;
12644}
12645
12646struct write_dir_struct {
12647 struct out_dir *outdir;
12648 errcode_t err;
12649 e2fsck_t ctx;
12650 int cleared;
12651};
12652
12653/*
12654 * Helper function which writes out a directory block.
12655 */
12656static int write_dir_block(ext2_filsys fs,
12657 blk_t *block_nr,
12658 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000012659 blk_t ref_block FSCK_ATTR((unused)),
12660 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012661 void *priv_data)
12662{
12663 struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
12664 blk_t blk;
12665 char *dir;
12666
12667 if (*block_nr == 0)
12668 return 0;
12669 if (blockcnt >= wd->outdir->num) {
12670 e2fsck_read_bitmaps(wd->ctx);
12671 blk = *block_nr;
12672 ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
12673 ext2fs_block_alloc_stats(fs, blk, -1);
12674 *block_nr = 0;
12675 wd->cleared++;
12676 return BLOCK_CHANGED;
12677 }
12678 if (blockcnt < 0)
12679 return 0;
12680
12681 dir = wd->outdir->buf + (blockcnt * fs->blocksize);
12682 wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
12683 if (wd->err)
12684 return BLOCK_ABORT;
12685 return 0;
12686}
12687
12688static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
12689 struct out_dir *outdir,
12690 ext2_ino_t ino, int compress)
12691{
12692 struct write_dir_struct wd;
12693 errcode_t retval;
12694 struct ext2_inode inode;
12695
12696 retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
12697 if (retval)
12698 return retval;
12699
12700 wd.outdir = outdir;
12701 wd.err = 0;
12702 wd.ctx = ctx;
12703 wd.cleared = 0;
12704
12705 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
12706 write_dir_block, &wd);
12707 if (retval)
12708 return retval;
12709 if (wd.err)
12710 return wd.err;
12711
12712 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
12713 if (compress)
12714 inode.i_flags &= ~EXT2_INDEX_FL;
12715 else
12716 inode.i_flags |= EXT2_INDEX_FL;
12717 inode.i_size = outdir->num * fs->blocksize;
12718 inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
12719 e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
12720
12721 return 0;
12722}
12723
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012724static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012725{
12726 ext2_filsys fs = ctx->fs;
12727 errcode_t retval;
12728 struct ext2_inode inode;
12729 char *dir_buf = 0;
12730 struct fill_dir_struct fd;
12731 struct out_dir outdir;
12732
12733 outdir.max = outdir.num = 0;
12734 outdir.buf = 0;
12735 outdir.hashes = 0;
12736 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
12737
12738 retval = ENOMEM;
12739 fd.harray = 0;
12740 dir_buf = malloc(inode.i_size);
12741 if (!dir_buf)
12742 goto errout;
12743
12744 fd.max_array = inode.i_size / 32;
12745 fd.num_array = 0;
12746 fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
12747 if (!fd.harray)
12748 goto errout;
12749
12750 fd.ctx = ctx;
12751 fd.buf = dir_buf;
12752 fd.inode = &inode;
12753 fd.err = 0;
12754 fd.dir_size = 0;
12755 fd.compress = 0;
12756 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
12757 (inode.i_size / fs->blocksize) < 2)
12758 fd.compress = 1;
12759 fd.parent = 0;
12760
12761 /* Read in the entire directory into memory */
12762 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
12763 fill_dir_block, &fd);
12764 if (fd.err) {
12765 retval = fd.err;
12766 goto errout;
12767 }
12768
12769#if 0
12770 printf("%d entries (%d bytes) found in inode %d\n",
12771 fd.num_array, fd.dir_size, ino);
12772#endif
12773
12774 /* Sort the list */
12775resort:
12776 if (fd.compress)
12777 qsort(fd.harray+2, fd.num_array-2,
12778 sizeof(struct hash_entry), name_cmp);
12779 else
12780 qsort(fd.harray, fd.num_array,
12781 sizeof(struct hash_entry), hash_cmp);
12782
12783 /*
12784 * Look for duplicates
12785 */
12786 if (duplicate_search_and_fix(ctx, fs, ino, &fd))
12787 goto resort;
12788
12789 if (ctx->options & E2F_OPT_NO) {
12790 retval = 0;
12791 goto errout;
12792 }
12793
12794 /*
12795 * Copy the directory entries. In a htree directory these
12796 * will become the leaf nodes.
12797 */
12798 retval = copy_dir_entries(fs, &fd, &outdir);
12799 if (retval)
12800 goto errout;
12801
12802 free(dir_buf); dir_buf = 0;
12803
12804 if (!fd.compress) {
12805 /* Calculate the interior nodes */
12806 retval = calculate_tree(fs, &outdir, ino, fd.parent);
12807 if (retval)
12808 goto errout;
12809 }
12810
12811 retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012812
12813errout:
Rob Landleye7c43b62006-03-01 16:39:45 +000012814 free(dir_buf);
12815 free(fd.harray);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012816
12817 free_out_dir(&outdir);
12818 return retval;
12819}
12820
12821void e2fsck_rehash_directories(e2fsck_t ctx)
12822{
12823 struct problem_context pctx;
12824#ifdef RESOURCE_TRACK
12825 struct resource_track rtrack;
12826#endif
12827 struct dir_info *dir;
12828 ext2_u32_iterate iter;
12829 ext2_ino_t ino;
12830 errcode_t retval;
12831 int i, cur, max, all_dirs, dir_index, first = 1;
12832
12833#ifdef RESOURCE_TRACK
12834 init_resource_track(&rtrack);
12835#endif
12836
12837 all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
12838
12839 if (!ctx->dirs_to_hash && !all_dirs)
12840 return;
12841
12842 e2fsck_get_lost_and_found(ctx, 0);
12843
12844 clear_problem_context(&pctx);
12845
12846 dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
12847 cur = 0;
12848 if (all_dirs) {
12849 i = 0;
12850 max = e2fsck_get_num_dirinfo(ctx);
12851 } else {
12852 retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
12853 &iter);
12854 if (retval) {
12855 pctx.errcode = retval;
12856 fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
12857 return;
12858 }
12859 max = ext2fs_u32_list_count(ctx->dirs_to_hash);
12860 }
12861 while (1) {
12862 if (all_dirs) {
12863 if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
12864 break;
12865 ino = dir->ino;
12866 } else {
12867 if (!ext2fs_u32_list_iterate(iter, &ino))
12868 break;
12869 }
12870 if (ino == ctx->lost_and_found)
12871 continue;
12872 pctx.dir = ino;
12873 if (first) {
12874 fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
12875 first = 0;
12876 }
12877#if 0
12878 fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx);
12879#endif
12880 pctx.errcode = e2fsck_rehash_dir(ctx, ino);
12881 if (pctx.errcode) {
12882 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
12883 fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
12884 }
12885 if (ctx->progress && !ctx->progress_fd)
12886 e2fsck_simple_progress(ctx, "Rebuilding directory",
12887 100.0 * (float) (++cur) / (float) max, ino);
12888 }
12889 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
12890 if (!all_dirs)
12891 ext2fs_u32_list_iterate_end(iter);
12892
Rob Landleye7c43b62006-03-01 16:39:45 +000012893 ext2fs_u32_list_free(ctx->dirs_to_hash);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012894 ctx->dirs_to_hash = 0;
12895
12896#ifdef RESOURCE_TRACK
12897 if (ctx->options & E2F_OPT_TIME2) {
12898 e2fsck_clear_progbar(ctx);
12899 print_resource_track("Pass 3A", &rtrack);
12900 }
12901#endif
12902}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012903
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012904/*
12905 * linux/fs/revoke.c
12906 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012907 * Journal revoke routines for the generic filesystem journaling code;
12908 * part of the ext2fs journaling system.
12909 *
12910 * Revoke is the mechanism used to prevent old log records for deleted
12911 * metadata from being replayed on top of newer data using the same
12912 * blocks. The revoke mechanism is used in two separate places:
12913 *
12914 * + Commit: during commit we write the entire list of the current
12915 * transaction's revoked blocks to the journal
12916 *
12917 * + Recovery: during recovery we record the transaction ID of all
12918 * revoked blocks. If there are multiple revoke records in the log
12919 * for a single block, only the last one counts, and if there is a log
12920 * entry for a block beyond the last revoke, then that log entry still
12921 * gets replayed.
12922 *
12923 * We can get interactions between revokes and new log data within a
12924 * single transaction:
12925 *
12926 * Block is revoked and then journaled:
12927 * The desired end result is the journaling of the new block, so we
12928 * cancel the revoke before the transaction commits.
12929 *
12930 * Block is journaled and then revoked:
12931 * The revoke must take precedence over the write of the block, so we
12932 * need either to cancel the journal entry or to write the revoke
12933 * later in the log than the log block. In this case, we choose the
12934 * latter: journaling a block cancels any revoke record for that block
12935 * in the current transaction, so any revoke for that block in the
12936 * transaction must have happened after the block was journaled and so
12937 * the revoke must take precedence.
12938 *
12939 * Block is revoked and then written as data:
12940 * The data write is allowed to succeed, but the revoke is _not_
12941 * cancelled. We still need to prevent old log records from
12942 * overwriting the new data. We don't even need to clear the revoke
12943 * bit here.
12944 *
12945 * Revoke information on buffers is a tri-state value:
12946 *
12947 * RevokeValid clear: no cached revoke status, need to look it up
12948 * RevokeValid set, Revoked clear:
12949 * buffer has not been revoked, and cancel_revoke
12950 * need do nothing.
12951 * RevokeValid set, Revoked set:
12952 * buffer has been revoked.
12953 */
12954
12955static kmem_cache_t *revoke_record_cache;
12956static kmem_cache_t *revoke_table_cache;
12957
12958/* Each revoke record represents one single revoked block. During
12959 journal replay, this involves recording the transaction ID of the
12960 last transaction to revoke this block. */
12961
12962struct jbd_revoke_record_s
12963{
12964 struct list_head hash;
12965 tid_t sequence; /* Used for recovery only */
12966 unsigned long blocknr;
12967};
12968
12969
12970/* The revoke table is just a simple hash table of revoke records. */
12971struct jbd_revoke_table_s
12972{
12973 /* It is conceivable that we might want a larger hash table
12974 * for recovery. Must be a power of two. */
12975 int hash_size;
12976 int hash_shift;
12977 struct list_head *hash_table;
12978};
12979
12980
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012981/* Utility functions to maintain the revoke table */
12982
12983/* Borrowed from buffer.c: this is a tried and tested block hash function */
12984static inline int hash(journal_t *journal, unsigned long block)
12985{
12986 struct jbd_revoke_table_s *table = journal->j_revoke;
12987 int hash_shift = table->hash_shift;
12988
12989 return ((block << (hash_shift - 6)) ^
12990 (block >> 13) ^
12991 (block << (hash_shift - 12))) & (table->hash_size - 1);
12992}
12993
12994static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
12995 tid_t seq)
12996{
12997 struct list_head *hash_list;
12998 struct jbd_revoke_record_s *record;
12999
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013000 record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
13001 if (!record)
13002 goto oom;
13003
13004 record->sequence = seq;
13005 record->blocknr = blocknr;
13006 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13007 list_add(&record->hash, hash_list);
13008 return 0;
13009
13010oom:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013011 return -ENOMEM;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013012}
13013
13014/* Find a revoke record in the journal's hash table. */
13015
13016static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
13017 unsigned long blocknr)
13018{
13019 struct list_head *hash_list;
13020 struct jbd_revoke_record_s *record;
13021
13022 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13023
13024 record = (struct jbd_revoke_record_s *) hash_list->next;
13025 while (&(record->hash) != hash_list) {
13026 if (record->blocknr == blocknr)
13027 return record;
13028 record = (struct jbd_revoke_record_s *) record->hash.next;
13029 }
13030 return NULL;
13031}
13032
13033int journal_init_revoke_caches(void)
13034{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013035 revoke_record_cache = do_cache_create(sizeof(struct jbd_revoke_record_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013036 if (revoke_record_cache == 0)
13037 return -ENOMEM;
13038
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013039 revoke_table_cache = do_cache_create(sizeof(struct jbd_revoke_table_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013040 if (revoke_table_cache == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013041 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013042 revoke_record_cache = NULL;
13043 return -ENOMEM;
13044 }
13045 return 0;
13046}
13047
13048void journal_destroy_revoke_caches(void)
13049{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013050 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013051 revoke_record_cache = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013052 do_cache_destroy(revoke_table_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013053 revoke_table_cache = 0;
13054}
13055
13056/* Initialise the revoke table for a given journal to a given size. */
13057
13058int journal_init_revoke(journal_t *journal, int hash_size)
13059{
13060 int shift, tmp;
13061
13062 J_ASSERT (journal->j_revoke == NULL);
13063
13064 journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
13065 if (!journal->j_revoke)
13066 return -ENOMEM;
13067
13068 /* Check that the hash_size is a power of two */
13069 J_ASSERT ((hash_size & (hash_size-1)) == 0);
13070
13071 journal->j_revoke->hash_size = hash_size;
13072
13073 shift = 0;
13074 tmp = hash_size;
13075 while((tmp >>= 1UL) != 0UL)
13076 shift++;
13077 journal->j_revoke->hash_shift = shift;
13078
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013079 journal->j_revoke->hash_table = malloc(hash_size * sizeof(struct list_head));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013080 if (!journal->j_revoke->hash_table) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013081 free(journal->j_revoke);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013082 journal->j_revoke = NULL;
13083 return -ENOMEM;
13084 }
13085
13086 for (tmp = 0; tmp < hash_size; tmp++)
13087 INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
13088
13089 return 0;
13090}
13091
13092/* Destoy a journal's revoke table. The table must already be empty! */
13093
13094void journal_destroy_revoke(journal_t *journal)
13095{
13096 struct jbd_revoke_table_s *table;
13097 struct list_head *hash_list;
13098 int i;
13099
13100 table = journal->j_revoke;
13101 if (!table)
13102 return;
13103
13104 for (i=0; i<table->hash_size; i++) {
13105 hash_list = &table->hash_table[i];
13106 J_ASSERT (list_empty(hash_list));
13107 }
13108
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013109 free(table->hash_table);
13110 free(table);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013111 journal->j_revoke = NULL;
13112}
13113
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013114/*
13115 * Revoke support for recovery.
13116 *
13117 * Recovery needs to be able to:
13118 *
13119 * record all revoke records, including the tid of the latest instance
13120 * of each revoke in the journal
13121 *
13122 * check whether a given block in a given transaction should be replayed
13123 * (ie. has not been revoked by a revoke record in that or a subsequent
13124 * transaction)
13125 *
13126 * empty the revoke table after recovery.
13127 */
13128
13129/*
13130 * First, setting revoke records. We create a new revoke record for
13131 * every block ever revoked in the log as we scan it for recovery, and
13132 * we update the existing records if we find multiple revokes for a
13133 * single block.
13134 */
13135
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013136int journal_set_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013137 tid_t sequence)
13138{
13139 struct jbd_revoke_record_s *record;
13140
13141 record = find_revoke_record(journal, blocknr);
13142 if (record) {
13143 /* If we have multiple occurences, only record the
13144 * latest sequence number in the hashed record */
13145 if (tid_gt(sequence, record->sequence))
13146 record->sequence = sequence;
13147 return 0;
13148 }
13149 return insert_revoke_hash(journal, blocknr, sequence);
13150}
13151
13152/*
13153 * Test revoke records. For a given block referenced in the log, has
13154 * that block been revoked? A revoke record with a given transaction
13155 * sequence number revokes all blocks in that transaction and earlier
13156 * ones, but later transactions still need replayed.
13157 */
13158
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013159int journal_test_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013160 tid_t sequence)
13161{
13162 struct jbd_revoke_record_s *record;
13163
13164 record = find_revoke_record(journal, blocknr);
13165 if (!record)
13166 return 0;
13167 if (tid_gt(sequence, record->sequence))
13168 return 0;
13169 return 1;
13170}
13171
13172/*
13173 * Finally, once recovery is over, we need to clear the revoke table so
13174 * that it can be reused by the running filesystem.
13175 */
13176
13177void journal_clear_revoke(journal_t *journal)
13178{
13179 int i;
13180 struct list_head *hash_list;
13181 struct jbd_revoke_record_s *record;
13182 struct jbd_revoke_table_s *revoke_var;
13183
13184 revoke_var = journal->j_revoke;
13185
13186 for (i = 0; i < revoke_var->hash_size; i++) {
13187 hash_list = &revoke_var->hash_table[i];
13188 while (!list_empty(hash_list)) {
13189 record = (struct jbd_revoke_record_s*) hash_list->next;
13190 list_del(&record->hash);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013191 free(record);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013192 }
13193 }
13194}
13195
13196/*
13197 * e2fsck.c - superblock checks
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013198 */
13199
13200#define MIN_CHECK 1
13201#define MAX_CHECK 2
13202
13203static void check_super_value(e2fsck_t ctx, const char *descr,
13204 unsigned long value, int flags,
13205 unsigned long min_val, unsigned long max_val)
13206{
13207 struct problem_context pctx;
13208
13209 if (((flags & MIN_CHECK) && (value < min_val)) ||
13210 ((flags & MAX_CHECK) && (value > max_val))) {
13211 clear_problem_context(&pctx);
13212 pctx.num = value;
13213 pctx.str = descr;
13214 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
13215 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
13216 }
13217}
13218
13219/*
13220 * This routine may get stubbed out in special compilations of the
13221 * e2fsck code..
13222 */
13223#ifndef EXT2_SPECIAL_DEVICE_SIZE
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013224static errcode_t e2fsck_get_device_size(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013225{
13226 return (ext2fs_get_device_size(ctx->filesystem_name,
13227 EXT2_BLOCK_SIZE(ctx->fs->super),
13228 &ctx->num_blocks));
13229}
13230#endif
13231
13232/*
13233 * helper function to release an inode
13234 */
13235struct process_block_struct {
13236 e2fsck_t ctx;
13237 char *buf;
13238 struct problem_context *pctx;
13239 int truncating;
13240 int truncate_offset;
13241 e2_blkcnt_t truncate_block;
13242 int truncated_blocks;
13243 int abort;
13244 errcode_t errcode;
13245};
13246
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013247static int release_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013248 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000013249 blk_t ref_blk FSCK_ATTR((unused)),
13250 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013251 void *priv_data)
13252{
13253 struct process_block_struct *pb;
13254 e2fsck_t ctx;
13255 struct problem_context *pctx;
13256 blk_t blk = *block_nr;
13257 int retval = 0;
13258
13259 pb = (struct process_block_struct *) priv_data;
13260 ctx = pb->ctx;
13261 pctx = pb->pctx;
13262
13263 pctx->blk = blk;
13264 pctx->blkcount = blockcnt;
13265
13266 if (HOLE_BLKADDR(blk))
13267 return 0;
13268
13269 if ((blk < fs->super->s_first_data_block) ||
13270 (blk >= fs->super->s_blocks_count)) {
13271 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
13272 return_abort:
13273 pb->abort = 1;
13274 return BLOCK_ABORT;
13275 }
13276
13277 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
13278 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
13279 goto return_abort;
13280 }
13281
13282 /*
13283 * If we are deleting an orphan, then we leave the fields alone.
13284 * If we are truncating an orphan, then update the inode fields
13285 * and clean up any partial block data.
13286 */
13287 if (pb->truncating) {
13288 /*
13289 * We only remove indirect blocks if they are
13290 * completely empty.
13291 */
13292 if (blockcnt < 0) {
13293 int i, limit;
13294 blk_t *bp;
13295
13296 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
13297 pb->buf);
13298 if (pb->errcode)
13299 goto return_abort;
13300
13301 limit = fs->blocksize >> 2;
13302 for (i = 0, bp = (blk_t *) pb->buf;
13303 i < limit; i++, bp++)
13304 if (*bp)
13305 return 0;
13306 }
13307 /*
13308 * We don't remove direct blocks until we've reached
13309 * the truncation block.
13310 */
13311 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
13312 return 0;
13313 /*
13314 * If part of the last block needs truncating, we do
13315 * it here.
13316 */
13317 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
13318 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
13319 pb->buf);
13320 if (pb->errcode)
13321 goto return_abort;
13322 memset(pb->buf + pb->truncate_offset, 0,
13323 fs->blocksize - pb->truncate_offset);
13324 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
13325 pb->buf);
13326 if (pb->errcode)
13327 goto return_abort;
13328 }
13329 pb->truncated_blocks++;
13330 *block_nr = 0;
13331 retval |= BLOCK_CHANGED;
13332 }
13333
13334 ext2fs_block_alloc_stats(fs, blk, -1);
13335 return retval;
13336}
13337
13338/*
13339 * This function releases an inode. Returns 1 if an inconsistency was
13340 * found. If the inode has a link count, then it is being truncated and
13341 * not deleted.
13342 */
13343static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
13344 struct ext2_inode *inode, char *block_buf,
13345 struct problem_context *pctx)
13346{
13347 struct process_block_struct pb;
13348 ext2_filsys fs = ctx->fs;
13349 errcode_t retval;
13350 __u32 count;
13351
13352 if (!ext2fs_inode_has_valid_blocks(inode))
13353 return 0;
13354
13355 pb.buf = block_buf + 3 * ctx->fs->blocksize;
13356 pb.ctx = ctx;
13357 pb.abort = 0;
13358 pb.errcode = 0;
13359 pb.pctx = pctx;
13360 if (inode->i_links_count) {
13361 pb.truncating = 1;
13362 pb.truncate_block = (e2_blkcnt_t)
13363 ((((long long)inode->i_size_high << 32) +
13364 inode->i_size + fs->blocksize - 1) /
13365 fs->blocksize);
13366 pb.truncate_offset = inode->i_size % fs->blocksize;
13367 } else {
13368 pb.truncating = 0;
13369 pb.truncate_block = 0;
13370 pb.truncate_offset = 0;
13371 }
13372 pb.truncated_blocks = 0;
13373 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
13374 block_buf, release_inode_block, &pb);
13375 if (retval) {
13376 com_err("release_inode_blocks", retval,
13377 _("while calling ext2fs_block_iterate for inode %d"),
13378 ino);
13379 return 1;
13380 }
13381 if (pb.abort)
13382 return 1;
13383
13384 /* Refresh the inode since ext2fs_block_iterate may have changed it */
13385 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
13386
13387 if (pb.truncated_blocks)
13388 inode->i_blocks -= pb.truncated_blocks *
13389 (fs->blocksize / 512);
13390
13391 if (inode->i_file_acl) {
13392 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
13393 block_buf, -1, &count);
13394 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
13395 retval = 0;
13396 count = 1;
13397 }
13398 if (retval) {
13399 com_err("release_inode_blocks", retval,
13400 _("while calling ext2fs_adjust_ea_refocunt for inode %d"),
13401 ino);
13402 return 1;
13403 }
13404 if (count == 0)
13405 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
13406 inode->i_file_acl = 0;
13407 }
13408 return 0;
13409}
13410
13411/*
13412 * This function releases all of the orphan inodes. It returns 1 if
13413 * it hit some error, and 0 on success.
13414 */
13415static int release_orphan_inodes(e2fsck_t ctx)
13416{
13417 ext2_filsys fs = ctx->fs;
13418 ext2_ino_t ino, next_ino;
13419 struct ext2_inode inode;
13420 struct problem_context pctx;
13421 char *block_buf;
13422
13423 if ((ino = fs->super->s_last_orphan) == 0)
13424 return 0;
13425
13426 /*
13427 * Win or lose, we won't be using the head of the orphan inode
13428 * list again.
13429 */
13430 fs->super->s_last_orphan = 0;
13431 ext2fs_mark_super_dirty(fs);
13432
13433 /*
13434 * If the filesystem contains errors, don't run the orphan
13435 * list, since the orphan list can't be trusted; and we're
13436 * going to be running a full e2fsck run anyway...
13437 */
13438 if (fs->super->s_state & EXT2_ERROR_FS)
13439 return 0;
13440
13441 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
13442 (ino > fs->super->s_inodes_count)) {
13443 clear_problem_context(&pctx);
13444 pctx.ino = ino;
13445 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
13446 return 1;
13447 }
13448
13449 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
13450 "block iterate buffer");
13451 e2fsck_read_bitmaps(ctx);
13452
13453 while (ino) {
13454 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
13455 clear_problem_context(&pctx);
13456 pctx.ino = ino;
13457 pctx.inode = &inode;
13458 pctx.str = inode.i_links_count ? _("Truncating") :
13459 _("Clearing");
13460
13461 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
13462
13463 next_ino = inode.i_dtime;
13464 if (next_ino &&
13465 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
13466 (next_ino > fs->super->s_inodes_count))) {
13467 pctx.ino = next_ino;
13468 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
13469 goto return_abort;
13470 }
13471
13472 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
13473 goto return_abort;
13474
13475 if (!inode.i_links_count) {
13476 ext2fs_inode_alloc_stats2(fs, ino, -1,
13477 LINUX_S_ISDIR(inode.i_mode));
13478 inode.i_dtime = time(0);
13479 } else {
13480 inode.i_dtime = 0;
13481 }
13482 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
13483 ino = next_ino;
13484 }
13485 ext2fs_free_mem(&block_buf);
13486 return 0;
13487return_abort:
13488 ext2fs_free_mem(&block_buf);
13489 return 1;
13490}
13491
13492/*
13493 * Check the resize inode to make sure it is sane. We check both for
13494 * the case where on-line resizing is not enabled (in which case the
13495 * resize inode should be cleared) as well as the case where on-line
13496 * resizing is enabled.
13497 */
13498static void check_resize_inode(e2fsck_t ctx)
13499{
13500 ext2_filsys fs = ctx->fs;
13501 struct ext2_inode inode;
13502 struct problem_context pctx;
13503 int i, j, gdt_off, ind_off;
13504 blk_t blk, pblk, expect;
13505 __u32 *dind_buf = 0, *ind_buf;
13506 errcode_t retval;
13507
13508 clear_problem_context(&pctx);
13509
13510 /*
13511 * If the resize inode feature isn't set, then
13512 * s_reserved_gdt_blocks must be zero.
13513 */
13514 if (!(fs->super->s_feature_compat &
13515 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
13516 if (fs->super->s_reserved_gdt_blocks) {
13517 pctx.num = fs->super->s_reserved_gdt_blocks;
13518 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
13519 &pctx)) {
13520 fs->super->s_reserved_gdt_blocks = 0;
13521 ext2fs_mark_super_dirty(fs);
13522 }
13523 }
13524 }
13525
13526 /* Read the resizde inode */
13527 pctx.ino = EXT2_RESIZE_INO;
13528 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
13529 if (retval) {
13530 if (fs->super->s_feature_compat &
13531 EXT2_FEATURE_COMPAT_RESIZE_INODE)
13532 ctx->flags |= E2F_FLAG_RESIZE_INODE;
13533 return;
13534 }
13535
13536 /*
13537 * If the resize inode feature isn't set, check to make sure
13538 * the resize inode is cleared; then we're done.
13539 */
13540 if (!(fs->super->s_feature_compat &
13541 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
13542 for (i=0; i < EXT2_N_BLOCKS; i++) {
13543 if (inode.i_block[i])
13544 break;
13545 }
13546 if ((i < EXT2_N_BLOCKS) &&
13547 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
13548 memset(&inode, 0, sizeof(inode));
13549 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
13550 "clear_resize");
13551 }
13552 return;
13553 }
13554
13555 /*
13556 * The resize inode feature is enabled; check to make sure the
13557 * only block in use is the double indirect block
13558 */
13559 blk = inode.i_block[EXT2_DIND_BLOCK];
13560 for (i=0; i < EXT2_N_BLOCKS; i++) {
13561 if (i != EXT2_DIND_BLOCK && inode.i_block[i])
13562 break;
13563 }
13564 if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
13565 !(inode.i_mode & LINUX_S_IFREG) ||
13566 (blk < fs->super->s_first_data_block ||
13567 blk >= fs->super->s_blocks_count)) {
13568 resize_inode_invalid:
13569 if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
13570 memset(&inode, 0, sizeof(inode));
13571 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
13572 "clear_resize");
13573 ctx->flags |= E2F_FLAG_RESIZE_INODE;
13574 }
13575 if (!(ctx->options & E2F_OPT_READONLY)) {
13576 fs->super->s_state &= ~EXT2_VALID_FS;
13577 ext2fs_mark_super_dirty(fs);
13578 }
13579 goto cleanup;
13580 }
13581 dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
13582 "resize dind buffer");
13583 ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
13584
13585 retval = ext2fs_read_ind_block(fs, blk, dind_buf);
13586 if (retval)
13587 goto resize_inode_invalid;
13588
13589 gdt_off = fs->desc_blocks;
13590 pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
13591 for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
13592 i++, gdt_off++, pblk++) {
13593 gdt_off %= fs->blocksize/4;
13594 if (dind_buf[gdt_off] != pblk)
13595 goto resize_inode_invalid;
13596 retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
13597 if (retval)
13598 goto resize_inode_invalid;
13599 ind_off = 0;
13600 for (j = 1; j < fs->group_desc_count; j++) {
13601 if (!ext2fs_bg_has_super(fs, j))
13602 continue;
13603 expect = pblk + (j * fs->super->s_blocks_per_group);
13604 if (ind_buf[ind_off] != expect)
13605 goto resize_inode_invalid;
13606 ind_off++;
13607 }
13608 }
13609
13610cleanup:
Rob Landleye7c43b62006-03-01 16:39:45 +000013611 ext2fs_free_mem(&dind_buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013612
13613 }
13614
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013615static void check_super_block(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013616{
13617 ext2_filsys fs = ctx->fs;
13618 blk_t first_block, last_block;
13619 struct ext2_super_block *sb = fs->super;
13620 struct ext2_group_desc *gd;
13621 blk_t blocks_per_group = fs->super->s_blocks_per_group;
13622 blk_t bpg_max;
13623 int inodes_per_block;
13624 int ipg_max;
13625 int inode_size;
13626 dgrp_t i;
13627 blk_t should_be;
13628 struct problem_context pctx;
13629 __u32 free_blocks = 0, free_inodes = 0;
13630
13631 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
13632 ipg_max = inodes_per_block * (blocks_per_group - 4);
13633 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
13634 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
13635 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
13636 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
13637 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
13638
13639 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
13640 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
13641 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
13642 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
13643 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
13644 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
13645
13646 clear_problem_context(&pctx);
13647
13648 /*
13649 * Verify the super block constants...
13650 */
13651 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
13652 MIN_CHECK, 1, 0);
13653 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
13654 MIN_CHECK, 1, 0);
13655 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
13656 MAX_CHECK, 0, sb->s_blocks_count);
13657 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
13658 MIN_CHECK | MAX_CHECK, 0,
13659 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
13660 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
13661 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
13662 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
13663 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
13664 bpg_max);
13665 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
13666 MIN_CHECK | MAX_CHECK, 8, bpg_max);
13667 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
13668 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
13669 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
13670 MAX_CHECK, 0, sb->s_blocks_count / 2);
13671 check_super_value(ctx, "reserved_gdt_blocks",
13672 sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
13673 fs->blocksize/4);
13674 inode_size = EXT2_INODE_SIZE(sb);
13675 check_super_value(ctx, "inode_size",
13676 inode_size, MIN_CHECK | MAX_CHECK,
13677 EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
13678 if (inode_size & (inode_size - 1)) {
13679 pctx.num = inode_size;
13680 pctx.str = "inode_size";
13681 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
13682 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
13683 return;
13684 }
13685
13686 if (!ctx->num_blocks) {
13687 pctx.errcode = e2fsck_get_device_size(ctx);
13688 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
13689 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
13690 ctx->flags |= E2F_FLAG_ABORT;
13691 return;
13692 }
13693 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
13694 (ctx->num_blocks < sb->s_blocks_count)) {
13695 pctx.blk = sb->s_blocks_count;
13696 pctx.blk2 = ctx->num_blocks;
13697 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
13698 ctx->flags |= E2F_FLAG_ABORT;
13699 return;
13700 }
13701 }
13702 }
13703
13704 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
13705 pctx.blk = EXT2_BLOCK_SIZE(sb);
13706 pctx.blk2 = EXT2_FRAG_SIZE(sb);
13707 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
13708 ctx->flags |= E2F_FLAG_ABORT;
13709 return;
13710 }
13711
13712 should_be = sb->s_frags_per_group >>
13713 (sb->s_log_block_size - sb->s_log_frag_size);
13714 if (sb->s_blocks_per_group != should_be) {
13715 pctx.blk = sb->s_blocks_per_group;
13716 pctx.blk2 = should_be;
13717 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
13718 ctx->flags |= E2F_FLAG_ABORT;
13719 return;
13720 }
13721
13722 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
13723 if (sb->s_first_data_block != should_be) {
13724 pctx.blk = sb->s_first_data_block;
13725 pctx.blk2 = should_be;
13726 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
13727 ctx->flags |= E2F_FLAG_ABORT;
13728 return;
13729 }
13730
13731 should_be = sb->s_inodes_per_group * fs->group_desc_count;
13732 if (sb->s_inodes_count != should_be) {
13733 pctx.ino = sb->s_inodes_count;
13734 pctx.ino2 = should_be;
13735 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
13736 sb->s_inodes_count = should_be;
13737 ext2fs_mark_super_dirty(fs);
13738 }
13739 }
13740
13741 /*
13742 * Verify the group descriptors....
13743 */
13744 first_block = sb->s_first_data_block;
13745 last_block = first_block + blocks_per_group;
13746
13747 for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
13748 pctx.group = i;
13749
13750 if (i == fs->group_desc_count - 1)
13751 last_block = sb->s_blocks_count;
13752 if ((gd->bg_block_bitmap < first_block) ||
13753 (gd->bg_block_bitmap >= last_block)) {
13754 pctx.blk = gd->bg_block_bitmap;
13755 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
13756 gd->bg_block_bitmap = 0;
13757 }
13758 if (gd->bg_block_bitmap == 0) {
13759 ctx->invalid_block_bitmap_flag[i]++;
13760 ctx->invalid_bitmaps++;
13761 }
13762 if ((gd->bg_inode_bitmap < first_block) ||
13763 (gd->bg_inode_bitmap >= last_block)) {
13764 pctx.blk = gd->bg_inode_bitmap;
13765 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
13766 gd->bg_inode_bitmap = 0;
13767 }
13768 if (gd->bg_inode_bitmap == 0) {
13769 ctx->invalid_inode_bitmap_flag[i]++;
13770 ctx->invalid_bitmaps++;
13771 }
13772 if ((gd->bg_inode_table < first_block) ||
13773 ((gd->bg_inode_table +
13774 fs->inode_blocks_per_group - 1) >= last_block)) {
13775 pctx.blk = gd->bg_inode_table;
13776 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
13777 gd->bg_inode_table = 0;
13778 }
13779 if (gd->bg_inode_table == 0) {
13780 ctx->invalid_inode_table_flag[i]++;
13781 ctx->invalid_bitmaps++;
13782 }
13783 free_blocks += gd->bg_free_blocks_count;
13784 free_inodes += gd->bg_free_inodes_count;
13785 first_block += sb->s_blocks_per_group;
13786 last_block += sb->s_blocks_per_group;
13787
13788 if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
13789 (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
13790 (gd->bg_used_dirs_count > sb->s_inodes_per_group))
13791 ext2fs_unmark_valid(fs);
13792
13793 }
13794
13795 /*
13796 * Update the global counts from the block group counts. This
13797 * is needed for an experimental patch which eliminates
13798 * locking the entire filesystem when allocating blocks or
13799 * inodes; if the filesystem is not unmounted cleanly, the
13800 * global counts may not be accurate.
13801 */
13802 if ((free_blocks != sb->s_free_blocks_count) ||
13803 (free_inodes != sb->s_free_inodes_count)) {
13804 if (ctx->options & E2F_OPT_READONLY)
13805 ext2fs_unmark_valid(fs);
13806 else {
13807 sb->s_free_blocks_count = free_blocks;
13808 sb->s_free_inodes_count = free_inodes;
13809 ext2fs_mark_super_dirty(fs);
13810 }
13811 }
13812
13813 if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
13814 (sb->s_free_inodes_count > sb->s_inodes_count))
13815 ext2fs_unmark_valid(fs);
13816
13817
13818 /*
13819 * If we have invalid bitmaps, set the error state of the
13820 * filesystem.
13821 */
13822 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
13823 sb->s_state &= ~EXT2_VALID_FS;
13824 ext2fs_mark_super_dirty(fs);
13825 }
13826
13827 clear_problem_context(&pctx);
13828
13829#ifndef EXT2_SKIP_UUID
13830 /*
13831 * If the UUID field isn't assigned, assign it.
13832 */
13833 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
13834 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
13835 uuid_generate(sb->s_uuid);
13836 ext2fs_mark_super_dirty(fs);
13837 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
13838 }
13839 }
13840#endif
13841
13842 /*
13843 * For the Hurd, check to see if the filetype option is set,
13844 * since it doesn't support it.
13845 */
13846 if (!(ctx->options & E2F_OPT_READONLY) &&
13847 fs->super->s_creator_os == EXT2_OS_HURD &&
13848 (fs->super->s_feature_incompat &
13849 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
13850 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
13851 fs->super->s_feature_incompat &=
13852 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
13853 ext2fs_mark_super_dirty(fs);
13854
13855 }
13856 }
13857
13858 /*
13859 * If we have any of the compatibility flags set, we need to have a
13860 * revision 1 filesystem. Most kernels will not check the flags on
13861 * a rev 0 filesystem and we may have corruption issues because of
13862 * the incompatible changes to the filesystem.
13863 */
13864 if (!(ctx->options & E2F_OPT_READONLY) &&
13865 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
13866 (fs->super->s_feature_compat ||
13867 fs->super->s_feature_ro_compat ||
13868 fs->super->s_feature_incompat) &&
13869 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
13870 ext2fs_update_dynamic_rev(fs);
13871 ext2fs_mark_super_dirty(fs);
13872 }
13873
13874 check_resize_inode(ctx);
13875
13876 /*
13877 * Clean up any orphan inodes, if present.
13878 */
13879 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
13880 fs->super->s_state &= ~EXT2_VALID_FS;
13881 ext2fs_mark_super_dirty(fs);
13882 }
13883
13884 /*
13885 * Move the ext3 journal file, if necessary.
13886 */
13887 e2fsck_move_ext3_journal(ctx);
13888 return;
13889}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013890
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013891/*
13892 * swapfs.c --- byte-swap an ext2 filesystem
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013893 */
13894
13895#ifdef ENABLE_SWAPFS
13896
13897struct swap_block_struct {
13898 ext2_ino_t ino;
13899 int isdir;
13900 errcode_t errcode;
13901 char *dir_buf;
13902 struct ext2_inode *inode;
13903};
13904
13905/*
13906 * This is a helper function for block_iterate. We mark all of the
13907 * indirect and direct blocks as changed, so that block_iterate will
13908 * write them out.
13909 */
13910static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
13911 void *priv_data)
13912{
13913 errcode_t retval;
13914
13915 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
13916
13917 if (sb->isdir && (blockcnt >= 0) && *block_nr) {
13918 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
13919 if (retval) {
13920 sb->errcode = retval;
13921 return BLOCK_ABORT;
13922 }
13923 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
13924 if (retval) {
13925 sb->errcode = retval;
13926 return BLOCK_ABORT;
13927 }
13928 }
13929 if (blockcnt >= 0) {
13930 if (blockcnt < EXT2_NDIR_BLOCKS)
13931 return 0;
13932 return BLOCK_CHANGED;
13933 }
13934 if (blockcnt == BLOCK_COUNT_IND) {
13935 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
13936 return 0;
13937 return BLOCK_CHANGED;
13938 }
13939 if (blockcnt == BLOCK_COUNT_DIND) {
13940 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
13941 return 0;
13942 return BLOCK_CHANGED;
13943 }
13944 if (blockcnt == BLOCK_COUNT_TIND) {
13945 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
13946 return 0;
13947 return BLOCK_CHANGED;
13948 }
13949 return BLOCK_CHANGED;
13950}
13951
13952/*
13953 * This function is responsible for byte-swapping all of the indirect,
13954 * block pointers. It is also responsible for byte-swapping directories.
13955 */
13956static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
13957 struct ext2_inode *inode)
13958{
13959 errcode_t retval;
13960 struct swap_block_struct sb;
13961
13962 sb.ino = ino;
13963 sb.inode = inode;
13964 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
13965 sb.errcode = 0;
13966 sb.isdir = 0;
13967 if (LINUX_S_ISDIR(inode->i_mode))
13968 sb.isdir = 1;
13969
13970 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
13971 swap_block, &sb);
13972 if (retval) {
13973 com_err("swap_inode_blocks", retval,
13974 _("while calling ext2fs_block_iterate"));
13975 ctx->flags |= E2F_FLAG_ABORT;
13976 return;
13977 }
13978 if (sb.errcode) {
13979 com_err("swap_inode_blocks", sb.errcode,
13980 _("while calling iterator function"));
13981 ctx->flags |= E2F_FLAG_ABORT;
13982 return;
13983 }
13984}
13985
13986static void swap_inodes(e2fsck_t ctx)
13987{
13988 ext2_filsys fs = ctx->fs;
13989 dgrp_t group;
13990 unsigned int i;
13991 ext2_ino_t ino = 1;
13992 char *buf, *block_buf;
13993 errcode_t retval;
13994 struct ext2_inode * inode;
13995
13996 e2fsck_use_inode_shortcuts(ctx, 1);
13997
13998 retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
13999 &buf);
14000 if (retval) {
14001 com_err("swap_inodes", retval,
14002 _("while allocating inode buffer"));
14003 ctx->flags |= E2F_FLAG_ABORT;
14004 return;
14005 }
14006 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
14007 "block interate buffer");
14008 for (group = 0; group < fs->group_desc_count; group++) {
14009 retval = io_channel_read_blk(fs->io,
14010 fs->group_desc[group].bg_inode_table,
14011 fs->inode_blocks_per_group, buf);
14012 if (retval) {
14013 com_err("swap_inodes", retval,
14014 _("while reading inode table (group %d)"),
14015 group);
14016 ctx->flags |= E2F_FLAG_ABORT;
14017 return;
14018 }
14019 inode = (struct ext2_inode *) buf;
14020 for (i=0; i < fs->super->s_inodes_per_group;
14021 i++, ino++, inode++) {
14022 ctx->stashed_ino = ino;
14023 ctx->stashed_inode = inode;
14024
14025 if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
14026 ext2fs_swap_inode(fs, inode, inode, 0);
14027
14028 /*
14029 * Skip deleted files.
14030 */
14031 if (inode->i_links_count == 0)
14032 continue;
14033
14034 if (LINUX_S_ISDIR(inode->i_mode) ||
14035 ((inode->i_block[EXT2_IND_BLOCK] ||
14036 inode->i_block[EXT2_DIND_BLOCK] ||
14037 inode->i_block[EXT2_TIND_BLOCK]) &&
14038 ext2fs_inode_has_valid_blocks(inode)))
14039 swap_inode_blocks(ctx, ino, block_buf, inode);
14040
14041 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14042 return;
14043
14044 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14045 ext2fs_swap_inode(fs, inode, inode, 1);
14046 }
14047 retval = io_channel_write_blk(fs->io,
14048 fs->group_desc[group].bg_inode_table,
14049 fs->inode_blocks_per_group, buf);
14050 if (retval) {
14051 com_err("swap_inodes", retval,
14052 _("while writing inode table (group %d)"),
14053 group);
14054 ctx->flags |= E2F_FLAG_ABORT;
14055 return;
14056 }
14057 }
14058 ext2fs_free_mem(&buf);
14059 ext2fs_free_mem(&block_buf);
14060 e2fsck_use_inode_shortcuts(ctx, 0);
14061 ext2fs_flush_icache(fs);
14062}
14063
14064#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
14065/*
14066 * On the PowerPC, the big-endian variant of the ext2 filesystem
14067 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
14068 * of each word. Thus a bitmap with only bit 0 set would be, as
14069 * a string of bytes, 00 00 00 01 00 ...
14070 * To cope with this, we byte-reverse each word of a bitmap if
14071 * we have a big-endian filesystem, that is, if we are *not*
14072 * byte-swapping other word-sized numbers.
14073 */
14074#define EXT2_BIG_ENDIAN_BITMAPS
14075#endif
14076
14077#ifdef EXT2_BIG_ENDIAN_BITMAPS
14078static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
14079{
14080 __u32 *p = (__u32 *) bmap->bitmap;
14081 int n, nbytes = (bmap->end - bmap->start + 7) / 8;
14082
14083 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
14084 *p = ext2fs_swab32(*p);
14085}
14086#endif
14087
14088
14089#ifdef ENABLE_SWAPFS
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014090static void swap_filesys(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014091{
14092 ext2_filsys fs = ctx->fs;
14093#ifdef RESOURCE_TRACK
14094 struct resource_track rtrack;
14095
14096 init_resource_track(&rtrack);
14097#endif
14098
14099 if (!(ctx->options & E2F_OPT_PREEN))
14100 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
14101
14102#ifdef MTRACE
14103 mtrace_print("Byte swap");
14104#endif
14105
14106 if (fs->super->s_mnt_count) {
14107 fprintf(stderr, _("%s: the filesystem must be freshly "
14108 "checked using fsck\n"
14109 "and not mounted before trying to "
14110 "byte-swap it.\n"), ctx->device_name);
14111 ctx->flags |= E2F_FLAG_ABORT;
14112 return;
14113 }
14114 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
14115 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
14116 EXT2_FLAG_SWAP_BYTES_WRITE);
14117 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
14118 } else {
14119 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
14120 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
14121 }
14122 swap_inodes(ctx);
14123 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14124 return;
14125 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14126 fs->flags |= EXT2_FLAG_SWAP_BYTES;
14127 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
14128 EXT2_FLAG_SWAP_BYTES_WRITE);
14129
14130#ifdef EXT2_BIG_ENDIAN_BITMAPS
14131 e2fsck_read_bitmaps(ctx);
14132 ext2fs_swap_bitmap(fs->inode_map);
14133 ext2fs_swap_bitmap(fs->block_map);
14134 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
14135#endif
14136 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
14137 ext2fs_flush(fs);
14138 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
14139
14140#ifdef RESOURCE_TRACK
14141 if (ctx->options & E2F_OPT_TIME2)
14142 print_resource_track(_("Byte swap"), &rtrack);
14143#endif
14144}
14145#endif /* ENABLE_SWAPFS */
14146
14147#endif
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014148
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014149/*
14150 * util.c --- miscellaneous utilities
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014151 */
14152
14153#ifdef HAVE_CONIO_H
14154#undef HAVE_TERMIOS_H
14155#include <conio.h>
14156#define read_a_char() getch()
14157#else
14158#ifdef HAVE_TERMIOS_H
14159#include <termios.h>
14160#endif
14161#endif
14162
14163#if 0
14164void fatal_error(e2fsck_t ctx, const char *msg)
14165{
14166 if (msg)
14167 fprintf (stderr, "e2fsck: %s\n", msg);
14168 if (ctx->fs && ctx->fs->io) {
14169 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
14170 io_channel_flush(ctx->fs->io);
14171 else
14172 fprintf(stderr, "e2fsck: io manager magic bad!\n");
14173 }
14174 ctx->flags |= E2F_FLAG_ABORT;
14175 if (ctx->flags & E2F_FLAG_SETJMP_OK)
14176 longjmp(ctx->abort_loc, 1);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014177 exit(EXIT_ERROR);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014178}
14179#endif
14180
14181void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
14182 const char *description)
14183{
14184 void *ret;
14185 char buf[256];
14186
14187#ifdef DEBUG_ALLOCATE_MEMORY
14188 printf("Allocating %d bytes for %s...\n", size, description);
14189#endif
14190 ret = malloc(size);
14191 if (!ret) {
14192 sprintf(buf, "Can't allocate %s\n", description);
14193 fatal_error(ctx, buf);
14194 }
14195 memset(ret, 0, size);
14196 return ret;
14197}
14198
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014199static char *string_copy(const char *str, int len)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014200{
14201 char *ret;
14202
14203 if (!str)
14204 return NULL;
14205 if (!len)
14206 len = strlen(str);
14207 ret = malloc(len+1);
14208 if (ret) {
14209 strncpy(ret, str, len);
14210 ret[len] = 0;
14211 }
14212 return ret;
14213}
14214
14215#ifndef HAVE_CONIO_H
14216static int read_a_char(void)
14217{
14218 char c;
14219 int r;
14220 int fail = 0;
14221
14222 while(1) {
14223 if (e2fsck_global_ctx &&
14224 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
14225 return 3;
14226 }
14227 r = read(0, &c, 1);
14228 if (r == 1)
14229 return c;
14230 if (fail++ > 100)
14231 break;
14232 }
14233 return EOF;
14234}
14235#endif
14236
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014237static int ask_yn(const char * string, int def)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014238{
14239 int c;
14240 const char *defstr;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014241 static const char short_yes[] = "yY";
14242 static const char short_no[] = "nN";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014243
14244#ifdef HAVE_TERMIOS_H
14245 struct termios termios, tmp;
14246
14247 tcgetattr (0, &termios);
14248 tmp = termios;
14249 tmp.c_lflag &= ~(ICANON | ECHO);
14250 tmp.c_cc[VMIN] = 1;
14251 tmp.c_cc[VTIME] = 0;
14252 tcsetattr (0, TCSANOW, &tmp);
14253#endif
14254
14255 if (def == 1)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014256 defstr = "<y>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014257 else if (def == 0)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014258 defstr = "<n>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014259 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014260 defstr = " (y/n)";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014261 printf("%s%s? ", string, defstr);
14262 while (1) {
14263 fflush (stdout);
14264 if ((c = read_a_char()) == EOF)
14265 break;
14266 if (c == 3) {
14267#ifdef HAVE_TERMIOS_H
14268 tcsetattr (0, TCSANOW, &termios);
14269#endif
14270 if (e2fsck_global_ctx &&
14271 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
14272 puts("\n");
14273 longjmp(e2fsck_global_ctx->abort_loc, 1);
14274 }
14275 puts(_("cancelled!\n"));
14276 return 0;
14277 }
14278 if (strchr(short_yes, (char) c)) {
14279 def = 1;
14280 break;
14281 }
14282 else if (strchr(short_no, (char) c)) {
14283 def = 0;
14284 break;
14285 }
14286 else if ((c == ' ' || c == '\n') && (def != -1))
14287 break;
14288 }
14289 if (def)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014290 puts("yes\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014291 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014292 puts ("no\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014293#ifdef HAVE_TERMIOS_H
14294 tcsetattr (0, TCSANOW, &termios);
14295#endif
14296 return def;
14297}
14298
14299int ask (e2fsck_t ctx, const char * string, int def)
14300{
14301 if (ctx->options & E2F_OPT_NO) {
14302 printf (_("%s? no\n\n"), string);
14303 return 0;
14304 }
14305 if (ctx->options & E2F_OPT_YES) {
14306 printf (_("%s? yes\n\n"), string);
14307 return 1;
14308 }
14309 if (ctx->options & E2F_OPT_PREEN) {
14310 printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
14311 return def;
14312 }
14313 return ask_yn(string, def);
14314}
14315
14316void e2fsck_read_bitmaps(e2fsck_t ctx)
14317{
14318 ext2_filsys fs = ctx->fs;
14319 errcode_t retval;
14320
14321 if (ctx->invalid_bitmaps) {
14322 com_err(ctx->program_name, 0,
14323 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
14324 ctx->device_name);
14325 fatal_error(ctx, 0);
14326 }
14327
14328 ehandler_operation(_("reading inode and block bitmaps"));
14329 retval = ext2fs_read_bitmaps(fs);
14330 ehandler_operation(0);
14331 if (retval) {
14332 com_err(ctx->program_name, retval,
14333 _("while retrying to read bitmaps for %s"),
14334 ctx->device_name);
14335 fatal_error(ctx, 0);
14336 }
14337}
14338
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014339static void e2fsck_write_bitmaps(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014340{
14341 ext2_filsys fs = ctx->fs;
14342 errcode_t retval;
14343
14344 if (ext2fs_test_bb_dirty(fs)) {
14345 ehandler_operation(_("writing block bitmaps"));
14346 retval = ext2fs_write_block_bitmap(fs);
14347 ehandler_operation(0);
14348 if (retval) {
14349 com_err(ctx->program_name, retval,
14350 _("while retrying to write block bitmaps for %s"),
14351 ctx->device_name);
14352 fatal_error(ctx, 0);
14353 }
14354 }
14355
14356 if (ext2fs_test_ib_dirty(fs)) {
14357 ehandler_operation(_("writing inode bitmaps"));
14358 retval = ext2fs_write_inode_bitmap(fs);
14359 ehandler_operation(0);
14360 if (retval) {
14361 com_err(ctx->program_name, retval,
14362 _("while retrying to write inode bitmaps for %s"),
14363 ctx->device_name);
14364 fatal_error(ctx, 0);
14365 }
14366 }
14367}
14368
14369void preenhalt(e2fsck_t ctx)
14370{
14371 ext2_filsys fs = ctx->fs;
14372
14373 if (!(ctx->options & E2F_OPT_PREEN))
14374 return;
14375 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
14376 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
14377 ctx->device_name);
14378 if (fs != NULL) {
14379 fs->super->s_state |= EXT2_ERROR_FS;
14380 ext2fs_mark_super_dirty(fs);
14381 ext2fs_close(fs);
14382 }
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014383 exit(EXIT_UNCORRECTED);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014384}
14385
14386#ifdef RESOURCE_TRACK
14387void init_resource_track(struct resource_track *track)
14388{
14389#ifdef HAVE_GETRUSAGE
14390 struct rusage r;
14391#endif
14392
14393 track->brk_start = sbrk(0);
14394 gettimeofday(&track->time_start, 0);
14395#ifdef HAVE_GETRUSAGE
14396#ifdef sun
14397 memset(&r, 0, sizeof(struct rusage));
14398#endif
14399 getrusage(RUSAGE_SELF, &r);
14400 track->user_start = r.ru_utime;
14401 track->system_start = r.ru_stime;
14402#else
14403 track->user_start.tv_sec = track->user_start.tv_usec = 0;
14404 track->system_start.tv_sec = track->system_start.tv_usec = 0;
14405#endif
14406}
14407
14408static _INLINE_ float timeval_subtract(struct timeval *tv1,
14409 struct timeval *tv2)
14410{
14411 return ((tv1->tv_sec - tv2->tv_sec) +
14412 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
14413}
14414
14415void print_resource_track(const char *desc, struct resource_track *track)
14416{
14417#ifdef HAVE_GETRUSAGE
14418 struct rusage r;
14419#endif
14420#ifdef HAVE_MALLINFO
14421 struct mallinfo malloc_info;
14422#endif
14423 struct timeval time_end;
14424
14425 gettimeofday(&time_end, 0);
14426
14427 if (desc)
14428 printf("%s: ", desc);
14429
14430#ifdef HAVE_MALLINFO
14431#define kbytes(x) (((x) + 1023) / 1024)
14432
14433 malloc_info = mallinfo();
14434 printf(_("Memory used: %dk/%dk (%dk/%dk), "),
14435 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
14436 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
14437#else
14438 printf(_("Memory used: %d, "),
14439 (int) (((char *) sbrk(0)) - ((char *) track->brk_start)));
14440#endif
14441#ifdef HAVE_GETRUSAGE
14442 getrusage(RUSAGE_SELF, &r);
14443
14444 printf(_("time: %5.2f/%5.2f/%5.2f\n"),
14445 timeval_subtract(&time_end, &track->time_start),
14446 timeval_subtract(&r.ru_utime, &track->user_start),
14447 timeval_subtract(&r.ru_stime, &track->system_start));
14448#else
14449 printf(_("elapsed time: %6.3f\n"),
14450 timeval_subtract(&time_end, &track->time_start));
14451#endif
14452}
14453#endif /* RESOURCE_TRACK */
14454
14455void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
14456 struct ext2_inode * inode, const char *proc)
14457{
14458 int retval;
14459
14460 retval = ext2fs_read_inode(ctx->fs, ino, inode);
14461 if (retval) {
14462 com_err("ext2fs_read_inode", retval,
14463 _("while reading inode %ld in %s"), ino, proc);
14464 fatal_error(ctx, 0);
14465 }
14466}
14467
14468extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
14469 struct ext2_inode * inode, int bufsize,
14470 const char *proc)
14471{
14472 int retval;
14473
14474 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
14475 if (retval) {
14476 com_err("ext2fs_write_inode", retval,
14477 _("while writing inode %ld in %s"), ino, proc);
14478 fatal_error(ctx, 0);
14479 }
14480}
14481
14482extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
14483 struct ext2_inode * inode, const char *proc)
14484{
14485 int retval;
14486
14487 retval = ext2fs_write_inode(ctx->fs, ino, inode);
14488 if (retval) {
14489 com_err("ext2fs_write_inode", retval,
14490 _("while writing inode %ld in %s"), ino, proc);
14491 fatal_error(ctx, 0);
14492 }
14493}
14494
14495#ifdef MTRACE
14496void mtrace_print(char *mesg)
14497{
14498 FILE *malloc_get_mallstream();
14499 FILE *f = malloc_get_mallstream();
14500
14501 if (f)
14502 fprintf(f, "============= %s\n", mesg);
14503}
14504#endif
14505
14506blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
14507 io_manager manager)
14508{
14509 struct ext2_super_block *sb;
14510 io_channel io = NULL;
14511 void *buf = NULL;
14512 int blocksize;
14513 blk_t superblock, ret_sb = 8193;
14514
14515 if (fs && fs->super) {
14516 ret_sb = (fs->super->s_blocks_per_group +
14517 fs->super->s_first_data_block);
14518 if (ctx) {
14519 ctx->superblock = ret_sb;
14520 ctx->blocksize = fs->blocksize;
14521 }
14522 return ret_sb;
14523 }
14524
14525 if (ctx) {
14526 if (ctx->blocksize) {
14527 ret_sb = ctx->blocksize * 8;
14528 if (ctx->blocksize == 1024)
14529 ret_sb++;
14530 ctx->superblock = ret_sb;
14531 return ret_sb;
14532 }
14533 ctx->superblock = ret_sb;
14534 ctx->blocksize = 1024;
14535 }
14536
14537 if (!name || !manager)
14538 goto cleanup;
14539
14540 if (manager->open(name, 0, &io) != 0)
14541 goto cleanup;
14542
14543 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
14544 goto cleanup;
14545 sb = (struct ext2_super_block *) buf;
14546
14547 for (blocksize = EXT2_MIN_BLOCK_SIZE;
14548 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
14549 superblock = blocksize*8;
14550 if (blocksize == 1024)
14551 superblock++;
14552 io_channel_set_blksize(io, blocksize);
14553 if (io_channel_read_blk(io, superblock,
14554 -SUPERBLOCK_SIZE, buf))
14555 continue;
14556#ifdef EXT2FS_ENABLE_SWAPFS
14557 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
14558 ext2fs_swap_super(sb);
14559#endif
14560 if (sb->s_magic == EXT2_SUPER_MAGIC) {
14561 ret_sb = superblock;
14562 if (ctx) {
14563 ctx->superblock = superblock;
14564 ctx->blocksize = blocksize;
14565 }
14566 break;
14567 }
14568 }
14569
14570cleanup:
14571 if (io)
14572 io_channel_close(io);
Rob Landleye7c43b62006-03-01 16:39:45 +000014573 ext2fs_free_mem(&buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014574 return (ret_sb);
14575}
14576
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014577
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014578/*
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014579 * This function runs through the e2fsck passes and calls them all,
14580 * returning restart, abort, or cancel as necessary...
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014581 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014582typedef void (*pass_t)(e2fsck_t ctx);
14583
14584static const pass_t e2fsck_passes[] = {
14585 e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
14586 e2fsck_pass5, 0 };
14587
14588#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
14589
14590static int e2fsck_run(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014591{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014592 int i;
14593 pass_t e2fsck_pass;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014594
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014595 if (setjmp(ctx->abort_loc)) {
14596 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
14597 return (ctx->flags & E2F_FLAG_RUN_RETURN);
14598 }
14599 ctx->flags |= E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014600
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014601 for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
14602 if (ctx->flags & E2F_FLAG_RUN_RETURN)
14603 break;
14604 e2fsck_pass(ctx);
14605 if (ctx->progress)
14606 (void) (ctx->progress)(ctx, 0, 0, 0);
14607 }
14608 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014609
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014610 if (ctx->flags & E2F_FLAG_RUN_RETURN)
14611 return (ctx->flags & E2F_FLAG_RUN_RETURN);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014612 return 0;
14613}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014614
14615
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014616/*
14617 * unix.c - The unix-specific code for e2fsck
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014618 */
14619
14620
Mike Frysinger51a43b42005-09-24 07:11:16 +000014621/* Command line options */
14622static int swapfs;
14623#ifdef ENABLE_SWAPFS
14624static int normalize_swapfs;
14625#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014626static int cflag; /* check disk */
Mike Frysinger51a43b42005-09-24 07:11:16 +000014627static int show_version_only;
14628static int verbose;
14629
14630static int replace_bad_blocks;
14631static int keep_bad_blocks;
14632static char *bad_blocks_file;
14633
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014634#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
Mike Frysinger51a43b42005-09-24 07:11:16 +000014635int journal_enable_debug = -1;
14636#endif
14637
14638#if 0
14639static void usage(e2fsck_t ctx)
14640{
14641 fprintf(stderr,
14642 _("Usage: %s [-panyrcdfvstDFSV] [-b superblock] [-B blocksize]\n"
14643 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
14644 "\t\t[-l|-L bad_blocks_file] [-C fd] [-j ext-journal]\n"
14645 "\t\t[-E extended-options] device\n"),
14646 ctx->program_name);
14647
14648 fprintf(stderr, _("\nEmergency help:\n"
14649 " -p Automatic repair (no questions)\n"
14650 " -n Make no changes to the filesystem\n"
14651 " -y Assume \"yes\" to all questions\n"
14652 " -c Check for bad blocks and add them to the badblock list\n"
14653 " -f Force checking even if filesystem is marked clean\n"));
14654 fprintf(stderr, _(""
14655 " -v Be verbose\n"
14656 " -b superblock Use alternative superblock\n"
14657 " -B blocksize Force blocksize when looking for superblock\n"
14658 " -j external-journal Set location of the external journal\n"
14659 " -l bad_blocks_file Add to badblocks list\n"
14660 " -L bad_blocks_file Set badblocks list\n"
14661 ));
14662
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014663 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014664}
14665#endif
14666
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014667#define P_E2(singular, plural, n) n, ((n) == 1 ? singular : plural)
14668
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014669static void show_stats(e2fsck_t ctx)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014670{
14671 ext2_filsys fs = ctx->fs;
14672 int inodes, inodes_used, blocks, blocks_used;
14673 int dir_links;
14674 int num_files, num_links;
14675 int frag_percent;
14676
14677 dir_links = 2 * ctx->fs_directory_count - 1;
14678 num_files = ctx->fs_total_count - dir_links;
14679 num_links = ctx->fs_links_count - dir_links;
14680 inodes = fs->super->s_inodes_count;
14681 inodes_used = (fs->super->s_inodes_count -
14682 fs->super->s_free_inodes_count);
14683 blocks = fs->super->s_blocks_count;
14684 blocks_used = (fs->super->s_blocks_count -
14685 fs->super->s_free_blocks_count);
14686
14687 frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
14688 frag_percent = (frag_percent + 5) / 10;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014689
Mike Frysinger51a43b42005-09-24 07:11:16 +000014690 if (!verbose) {
14691 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
14692 ctx->device_name, inodes_used, inodes,
14693 frag_percent / 10, frag_percent % 10,
14694 blocks_used, blocks);
14695 return;
14696 }
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014697 printf ("\n%8d inode%s used (%d%%)\n", P_E2("", "s", inodes_used),
14698 100 * inodes_used / inodes);
14699 printf ("%8d non-contiguous inode%s (%0d.%d%%)\n",
14700 P_E2("", "s", ctx->fs_fragmented),
14701 frag_percent / 10, frag_percent % 10);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014702 printf (_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"),
14703 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014704 printf ("%8d block%s used (%d%%)\n", P_E2("", "s", blocks_used),
14705 (int) ((long long) 100 * blocks_used / blocks));
14706 printf ("%8d bad block%s\n", P_E2("", "s", ctx->fs_badblocks_count));
14707 printf ("%8d large file%s\n", P_E2("", "s", ctx->large_files));
14708 printf ("\n%8d regular file%s\n", P_E2("", "s", ctx->fs_regular_count));
14709 printf ("%8d director%s\n", P_E2("y", "ies", ctx->fs_directory_count));
14710 printf ("%8d character device file%s\n", P_E2("", "s", ctx->fs_chardev_count));
14711 printf ("%8d block device file%s\n", P_E2("", "s", ctx->fs_blockdev_count));
14712 printf ("%8d fifo%s\n", P_E2("", "s", ctx->fs_fifo_count));
14713 printf ("%8d link%s\n", P_E2("", "s", ctx->fs_links_count - dir_links));
14714 printf ("%8d symbolic link%s", P_E2("", "s", ctx->fs_symlinks_count));
14715 printf (" (%d fast symbolic link%s)\n", P_E2("", "s", ctx->fs_fast_symlinks_count));
14716 printf ("%8d socket%s--------\n\n", P_E2("", "s", ctx->fs_sockets_count));
14717 printf ("%8d file%s\n", P_E2("", "s", ctx->fs_total_count - dir_links));
Mike Frysinger51a43b42005-09-24 07:11:16 +000014718}
14719
14720static void check_mount(e2fsck_t ctx)
14721{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014722 errcode_t retval;
14723 int cont;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014724
14725 retval = ext2fs_check_if_mounted(ctx->filesystem_name,
14726 &ctx->mount_flags);
14727 if (retval) {
14728 com_err("ext2fs_check_if_mount", retval,
14729 _("while determining whether %s is mounted."),
14730 ctx->filesystem_name);
14731 return;
14732 }
14733
14734 /*
14735 * If the filesystem isn't mounted, or it's the root filesystem
14736 * and it's mounted read-only, then everything's fine.
14737 */
14738 if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) ||
14739 ((ctx->mount_flags & EXT2_MF_ISROOT) &&
14740 (ctx->mount_flags & EXT2_MF_READONLY)))
14741 return;
14742
14743 if (ctx->options & E2F_OPT_READONLY) {
14744 printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name);
14745 return;
14746 }
14747
14748 printf(_("%s is mounted. "), ctx->filesystem_name);
14749 if (!ctx->interactive)
14750 fatal_error(ctx, _("Cannot continue, aborting.\n\n"));
14751 printf(_("\n\n\007\007\007\007WARNING!!! "
14752 "Running e2fsck on a mounted filesystem may cause\n"
14753 "SEVERE filesystem damage.\007\007\007\n\n"));
14754 cont = ask_yn(_("Do you really want to continue"), -1);
14755 if (!cont) {
14756 printf (_("check aborted.\n"));
14757 exit (0);
14758 }
14759 return;
14760}
14761
14762static int is_on_batt(void)
14763{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014764 FILE *f;
14765 DIR *d;
14766 char tmp[80], tmp2[80], fname[80];
14767 unsigned int acflag;
14768 struct dirent* de;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014769
14770 f = fopen("/proc/apm", "r");
14771 if (f) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014772 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014773 acflag = 1;
14774 fclose(f);
14775 return (acflag != 1);
14776 }
14777 d = opendir("/proc/acpi/ac_adapter");
14778 if (d) {
14779 while ((de=readdir(d)) != NULL) {
14780 if (!strncmp(".", de->d_name, 1))
14781 continue;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014782 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state",
Mike Frysinger51a43b42005-09-24 07:11:16 +000014783 de->d_name);
14784 f = fopen(fname, "r");
14785 if (!f)
14786 continue;
14787 if (fscanf(f, "%s %s", tmp2, tmp) != 2)
14788 tmp[0] = 0;
14789 fclose(f);
14790 if (strncmp(tmp, "off-line", 8) == 0) {
14791 closedir(d);
14792 return 1;
14793 }
14794 }
14795 closedir(d);
14796 }
14797 return 0;
14798}
14799
14800/*
14801 * This routine checks to see if a filesystem can be skipped; if so,
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014802 * it will exit with EXIT_OK. Under some conditions it will print a
Mike Frysinger51a43b42005-09-24 07:11:16 +000014803 * message explaining why a check is being forced.
14804 */
14805static void check_if_skip(e2fsck_t ctx)
14806{
14807 ext2_filsys fs = ctx->fs;
14808 const char *reason = NULL;
14809 unsigned int reason_arg = 0;
14810 long next_check;
14811 int batt = is_on_batt();
14812 time_t now = time(0);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014813
Mike Frysinger51a43b42005-09-24 07:11:16 +000014814 if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file ||
14815 cflag || swapfs)
14816 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014817
Mike Frysinger51a43b42005-09-24 07:11:16 +000014818 if ((fs->super->s_state & EXT2_ERROR_FS) ||
14819 !ext2fs_test_valid(fs))
14820 reason = _(" contains a file system with errors");
14821 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
14822 reason = _(" was not cleanly unmounted");
14823 else if ((fs->super->s_max_mnt_count > 0) &&
14824 (fs->super->s_mnt_count >=
14825 (unsigned) fs->super->s_max_mnt_count)) {
14826 reason = _(" has been mounted %u times without being checked");
14827 reason_arg = fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014828 if (batt && (fs->super->s_mnt_count <
Mike Frysinger51a43b42005-09-24 07:11:16 +000014829 (unsigned) fs->super->s_max_mnt_count*2))
14830 reason = 0;
14831 } else if (fs->super->s_checkinterval &&
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014832 ((now - fs->super->s_lastcheck) >=
Mike Frysinger51a43b42005-09-24 07:11:16 +000014833 fs->super->s_checkinterval)) {
14834 reason = _(" has gone %u days without being checked");
14835 reason_arg = (now - fs->super->s_lastcheck)/(3600*24);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014836 if (batt && ((now - fs->super->s_lastcheck) <
Mike Frysinger51a43b42005-09-24 07:11:16 +000014837 fs->super->s_checkinterval*2))
14838 reason = 0;
14839 }
14840 if (reason) {
14841 fputs(ctx->device_name, stdout);
14842 printf(reason, reason_arg);
14843 fputs(_(", check forced.\n"), stdout);
14844 return;
14845 }
14846 printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name,
14847 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
14848 fs->super->s_inodes_count,
14849 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
14850 fs->super->s_blocks_count);
14851 next_check = 100000;
14852 if (fs->super->s_max_mnt_count > 0) {
14853 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014854 if (next_check <= 0)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014855 next_check = 1;
14856 }
14857 if (fs->super->s_checkinterval &&
14858 ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval))
14859 next_check = 1;
14860 if (next_check <= 5) {
14861 if (next_check == 1)
14862 fputs(_(" (check after next mount)"), stdout);
14863 else
14864 printf(_(" (check in %ld mounts)"), next_check);
14865 }
14866 fputc('\n', stdout);
14867 ext2fs_close(fs);
14868 ctx->fs = NULL;
14869 e2fsck_free_context(ctx);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014870 exit(EXIT_OK);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014871}
14872
14873/*
14874 * For completion notice
14875 */
14876struct percent_tbl {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014877 int max_pass;
14878 int table[32];
Mike Frysinger51a43b42005-09-24 07:11:16 +000014879};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014880static const struct percent_tbl e2fsck_tbl = {
Mike Frysinger51a43b42005-09-24 07:11:16 +000014881 5, { 0, 70, 90, 92, 95, 100 }
14882};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014883
Mike Frysinger51a43b42005-09-24 07:11:16 +000014884static char bar[128], spaces[128];
14885
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014886static float calc_percent(const struct percent_tbl *tbl, int pass, int curr,
Mike Frysinger51a43b42005-09-24 07:11:16 +000014887 int max)
14888{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014889 float percent;
14890
Mike Frysinger51a43b42005-09-24 07:11:16 +000014891 if (pass <= 0)
14892 return 0.0;
14893 if (pass > tbl->max_pass || max == 0)
14894 return 100.0;
14895 percent = ((float) curr) / ((float) max);
14896 return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
14897 + tbl->table[pass-1]);
14898}
14899
14900extern void e2fsck_clear_progbar(e2fsck_t ctx)
14901{
14902 if (!(ctx->flags & E2F_FLAG_PROG_BAR))
14903 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014904
Mike Frysinger51a43b42005-09-24 07:11:16 +000014905 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80),
14906 ctx->stop_meta);
14907 fflush(stdout);
14908 ctx->flags &= ~E2F_FLAG_PROG_BAR;
14909}
14910
14911int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
14912 unsigned int dpynum)
14913{
14914 static const char spinner[] = "\\|/-";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014915 int i;
14916 unsigned int tick;
14917 struct timeval tv;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014918 int dpywidth;
14919 int fixed_percent;
14920
14921 if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
14922 return 0;
14923
14924 /*
14925 * Calculate the new progress position. If the
14926 * percentage hasn't changed, then we skip out right
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014927 * away.
Mike Frysinger51a43b42005-09-24 07:11:16 +000014928 */
14929 fixed_percent = (int) ((10 * percent) + 0.5);
14930 if (ctx->progress_last_percent == fixed_percent)
14931 return 0;
14932 ctx->progress_last_percent = fixed_percent;
14933
14934 /*
14935 * If we've already updated the spinner once within
14936 * the last 1/8th of a second, no point doing it
14937 * again.
14938 */
14939 gettimeofday(&tv, NULL);
14940 tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8));
14941 if ((tick == ctx->progress_last_time) &&
14942 (fixed_percent != 0) && (fixed_percent != 1000))
14943 return 0;
14944 ctx->progress_last_time = tick;
14945
14946 /*
14947 * Advance the spinner, and note that the progress bar
14948 * will be on the screen
14949 */
14950 ctx->progress_pos = (ctx->progress_pos+1) & 3;
14951 ctx->flags |= E2F_FLAG_PROG_BAR;
14952
14953 dpywidth = 66 - strlen(label);
14954 dpywidth = 8 * (dpywidth / 8);
14955 if (dpynum)
14956 dpywidth -= 8;
14957
14958 i = ((percent * dpywidth) + 50) / 100;
14959 printf("%s%s: |%s%s", ctx->start_meta, label,
14960 bar + (sizeof(bar) - (i+1)),
14961 spaces + (sizeof(spaces) - (dpywidth - i + 1)));
14962 if (fixed_percent == 1000)
14963 fputc('|', stdout);
14964 else
14965 fputc(spinner[ctx->progress_pos & 3], stdout);
14966 printf(" %4.1f%% ", percent);
14967 if (dpynum)
14968 printf("%u\r", dpynum);
14969 else
14970 fputs(" \r", stdout);
14971 fputs(ctx->stop_meta, stdout);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014972
Mike Frysinger51a43b42005-09-24 07:11:16 +000014973 if (fixed_percent == 1000)
14974 e2fsck_clear_progbar(ctx);
14975 fflush(stdout);
14976
14977 return 0;
14978}
14979
14980static int e2fsck_update_progress(e2fsck_t ctx, int pass,
14981 unsigned long cur, unsigned long max)
14982{
14983 char buf[80];
14984 float percent;
14985
14986 if (pass == 0)
14987 return 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014988
Mike Frysinger51a43b42005-09-24 07:11:16 +000014989 if (ctx->progress_fd) {
14990 sprintf(buf, "%d %lu %lu\n", pass, cur, max);
14991 write(ctx->progress_fd, buf, strlen(buf));
14992 } else {
14993 percent = calc_percent(&e2fsck_tbl, pass, cur, max);
14994 e2fsck_simple_progress(ctx, ctx->device_name,
14995 percent, 0);
14996 }
14997 return 0;
14998}
14999
Mike Frysinger51a43b42005-09-24 07:11:16 +000015000static void reserve_stdio_fds(void)
15001{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015002 int fd;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015003
15004 while (1) {
"Vladimir N. Oleynik"6c35c7c2005-10-12 15:34:25 +000015005 fd = open(bb_dev_null, O_RDWR);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015006 if (fd > 2)
15007 break;
15008 if (fd < 0) {
15009 fprintf(stderr, _("ERROR: Couldn't open "
15010 "/dev/null (%s)\n"),
15011 strerror(errno));
15012 break;
15013 }
15014 }
15015 close(fd);
15016}
15017
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000015018static void signal_progress_on(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000015019{
15020 e2fsck_t ctx = e2fsck_global_ctx;
15021
15022 if (!ctx)
15023 return;
15024
15025 ctx->progress = e2fsck_update_progress;
15026 ctx->progress_fd = 0;
15027}
15028
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000015029static void signal_progress_off(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000015030{
15031 e2fsck_t ctx = e2fsck_global_ctx;
15032
15033 if (!ctx)
15034 return;
15035
15036 e2fsck_clear_progbar(ctx);
15037 ctx->progress = 0;
15038}
15039
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000015040static void signal_cancel(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000015041{
15042 e2fsck_t ctx = e2fsck_global_ctx;
15043
15044 if (!ctx)
15045 exit(FSCK_CANCELED);
15046
15047 ctx->flags |= E2F_FLAG_CANCEL;
15048}
Mike Frysinger51a43b42005-09-24 07:11:16 +000015049
15050static void parse_extended_opts(e2fsck_t ctx, const char *opts)
15051{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015052 char *buf, *token, *next, *p, *arg;
15053 int ea_ver;
15054 int extended_usage = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015055
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015056 buf = string_copy(opts, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015057 for (token = buf; token && *token; token = next) {
15058 p = strchr(token, ',');
15059 next = 0;
15060 if (p) {
15061 *p = 0;
15062 next = p+1;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015063 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000015064 arg = strchr(token, '=');
15065 if (arg) {
15066 *arg = 0;
15067 arg++;
15068 }
15069 if (strcmp(token, "ea_ver") == 0) {
15070 if (!arg) {
15071 extended_usage++;
15072 continue;
15073 }
15074 ea_ver = strtoul(arg, &p, 0);
15075 if (*p ||
15076 ((ea_ver != 1) && (ea_ver != 2))) {
15077 fprintf(stderr,
15078 _("Invalid EA version.\n"));
15079 extended_usage++;
15080 continue;
15081 }
15082 ctx->ext_attr_ver = ea_ver;
15083 } else
15084 extended_usage++;
15085 }
15086 if (extended_usage) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015087 bb_error_msg_and_die(
15088 "Extended options are separated by commas, "
Mike Frysinger51a43b42005-09-24 07:11:16 +000015089 "and may take an argument which\n"
15090 "is set off by an equals ('=') sign. "
15091 "Valid raid options are:\n"
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015092 "\tea_ver=<ea_version (1 or 2)\n\n");
Mike Frysinger51a43b42005-09-24 07:11:16 +000015093 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015094}
Mike Frysinger51a43b42005-09-24 07:11:16 +000015095
15096
15097static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
15098{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015099 int flush = 0;
15100 int c, fd;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015101#ifdef MTRACE
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015102 extern void *mallwatch;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015103#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015104 e2fsck_t ctx;
15105 errcode_t retval;
15106 struct sigaction sa;
15107 char *extended_opts = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015108
15109 retval = e2fsck_allocate_context(&ctx);
15110 if (retval)
15111 return retval;
15112
15113 *ret_ctx = ctx;
15114
15115 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
15116 setvbuf(stderr, NULL, _IONBF, BUFSIZ);
15117 if (isatty(0) && isatty(1)) {
15118 ctx->interactive = 1;
15119 } else {
15120 ctx->start_meta[0] = '\001';
15121 ctx->stop_meta[0] = '\002';
15122 }
15123 memset(bar, '=', sizeof(bar)-1);
15124 memset(spaces, ' ', sizeof(spaces)-1);
15125 blkid_get_cache(&ctx->blkid, NULL);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015126
Mike Frysinger51a43b42005-09-24 07:11:16 +000015127 if (argc && *argv)
15128 ctx->program_name = *argv;
15129 else
15130 ctx->program_name = "e2fsck";
15131 while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
15132 switch (c) {
15133 case 'C':
15134 ctx->progress = e2fsck_update_progress;
15135 ctx->progress_fd = atoi(optarg);
15136 if (!ctx->progress_fd)
15137 break;
15138 /* Validate the file descriptor to avoid disasters */
15139 fd = dup(ctx->progress_fd);
15140 if (fd < 0) {
15141 fprintf(stderr,
15142 _("Error validating file descriptor %d: %s\n"),
15143 ctx->progress_fd,
15144 error_message(errno));
15145 fatal_error(ctx,
15146 _("Invalid completion information file descriptor"));
15147 } else
15148 close(fd);
15149 break;
15150 case 'D':
15151 ctx->options |= E2F_OPT_COMPRESS_DIRS;
15152 break;
15153 case 'E':
15154 extended_opts = optarg;
15155 break;
15156 case 'p':
15157 case 'a':
15158 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) {
15159 conflict_opt:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015160 fatal_error(ctx,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015161 _("Only one the options -p/-a, -n or -y may be specified."));
15162 }
15163 ctx->options |= E2F_OPT_PREEN;
15164 break;
15165 case 'n':
15166 if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
15167 goto conflict_opt;
15168 ctx->options |= E2F_OPT_NO;
15169 break;
15170 case 'y':
15171 if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO))
15172 goto conflict_opt;
15173 ctx->options |= E2F_OPT_YES;
15174 break;
15175 case 't':
15176#ifdef RESOURCE_TRACK
15177 if (ctx->options & E2F_OPT_TIME)
15178 ctx->options |= E2F_OPT_TIME2;
15179 else
15180 ctx->options |= E2F_OPT_TIME;
15181#else
15182 fprintf(stderr, _("The -t option is not "
15183 "supported on this version of e2fsck.\n"));
15184#endif
15185 break;
15186 case 'c':
15187 if (cflag++)
15188 ctx->options |= E2F_OPT_WRITECHECK;
15189 ctx->options |= E2F_OPT_CHECKBLOCKS;
15190 break;
15191 case 'r':
15192 /* What we do by default, anyway! */
15193 break;
15194 case 'b':
15195 ctx->use_superblock = atoi(optarg);
15196 ctx->flags |= E2F_FLAG_SB_SPECIFIED;
15197 break;
15198 case 'B':
15199 ctx->blocksize = atoi(optarg);
15200 break;
15201 case 'I':
15202 ctx->inode_buffer_blocks = atoi(optarg);
15203 break;
15204 case 'j':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015205 ctx->journal_name = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015206 break;
15207 case 'P':
15208 ctx->process_inode_size = atoi(optarg);
15209 break;
15210 case 'L':
15211 replace_bad_blocks++;
15212 case 'l':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015213 bad_blocks_file = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015214 break;
15215 case 'd':
15216 ctx->options |= E2F_OPT_DEBUG;
15217 break;
15218 case 'f':
15219 ctx->options |= E2F_OPT_FORCE;
15220 break;
15221 case 'F':
15222 flush = 1;
15223 break;
15224 case 'v':
15225 verbose = 1;
15226 break;
15227 case 'V':
15228 show_version_only = 1;
15229 break;
15230#ifdef MTRACE
15231 case 'M':
15232 mallwatch = (void *) strtol(optarg, NULL, 0);
15233 break;
15234#endif
15235 case 'N':
15236 ctx->device_name = optarg;
15237 break;
15238#ifdef ENABLE_SWAPFS
15239 case 's':
15240 normalize_swapfs = 1;
15241 case 'S':
15242 swapfs = 1;
15243 break;
15244#else
15245 case 's':
15246 case 'S':
15247 fprintf(stderr, _("Byte-swapping filesystems "
15248 "not compiled in this version "
15249 "of e2fsck\n"));
15250 exit(1);
15251#endif
15252 case 'k':
15253 keep_bad_blocks++;
15254 break;
15255 default:
15256 usage();
15257 }
15258 if (show_version_only)
15259 return 0;
15260 if (optind != argc - 1)
15261 usage();
15262 if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
15263 !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
15264 ctx->options |= E2F_OPT_READONLY;
15265 ctx->io_options = strchr(argv[optind], '?');
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015266 if (ctx->io_options)
Mike Frysinger51a43b42005-09-24 07:11:16 +000015267 *ctx->io_options++ = 0;
15268 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
15269 if (!ctx->filesystem_name) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015270 com_err(ctx->program_name, 0, _("Unable to resolve '%s'"),
Mike Frysinger51a43b42005-09-24 07:11:16 +000015271 argv[optind]);
15272 fatal_error(ctx, 0);
15273 }
15274 if (extended_opts)
15275 parse_extended_opts(ctx, extended_opts);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015276
Mike Frysinger51a43b42005-09-24 07:11:16 +000015277 if (flush) {
15278 fd = open(ctx->filesystem_name, O_RDONLY, 0);
15279 if (fd < 0) {
15280 com_err("open", errno,
15281 _("while opening %s for flushing"),
15282 ctx->filesystem_name);
15283 fatal_error(ctx, 0);
15284 }
15285 if ((retval = ext2fs_sync_device(fd, 1))) {
15286 com_err("ext2fs_sync_device", retval,
15287 _("while trying to flush %s"),
15288 ctx->filesystem_name);
15289 fatal_error(ctx, 0);
15290 }
15291 close(fd);
15292 }
15293#ifdef ENABLE_SWAPFS
15294 if (swapfs) {
15295 if (cflag || bad_blocks_file) {
15296 fprintf(stderr, _("Incompatible options not "
15297 "allowed when byte-swapping.\n"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015298 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015299 }
15300 }
15301#endif
15302 if (cflag && bad_blocks_file) {
15303 fprintf(stderr, _("The -c and the -l/-L options may "
15304 "not be both used at the same time.\n"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015305 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015306 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000015307 /*
15308 * Set up signal action
15309 */
15310 memset(&sa, 0, sizeof(struct sigaction));
15311 sa.sa_handler = signal_cancel;
15312 sigaction(SIGINT, &sa, 0);
15313 sigaction(SIGTERM, &sa, 0);
15314#ifdef SA_RESTART
15315 sa.sa_flags = SA_RESTART;
15316#endif
15317 e2fsck_global_ctx = ctx;
15318 sa.sa_handler = signal_progress_on;
15319 sigaction(SIGUSR1, &sa, 0);
15320 sa.sa_handler = signal_progress_off;
15321 sigaction(SIGUSR2, &sa, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015322
15323 /* Update our PATH to include /sbin if we need to run badblocks */
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015324 if (cflag)
15325 e2fs_set_sbin_path();
Mike Frysinger51a43b42005-09-24 07:11:16 +000015326#ifdef __CONFIG_JBD_DEBUG__E2FS
15327 if (getenv("E2FSCK_JBD_DEBUG"))
15328 journal_enable_debug = atoi(getenv("E2FSCK_JBD_DEBUG"));
15329#endif
15330 return 0;
15331}
15332
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015333static const char my_ver_string[] = E2FSPROGS_VERSION;
15334static const char my_ver_date[] = E2FSPROGS_DATE;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015335
Mike Frysinger51a43b42005-09-24 07:11:16 +000015336int e2fsck_main (int argc, char *argv[])
15337{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015338 errcode_t retval;
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015339 int exit_value = EXIT_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015340 ext2_filsys fs = 0;
15341 io_manager io_ptr;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015342 struct ext2_super_block *sb;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015343 const char *lib_ver_date;
15344 int my_ver, lib_ver;
15345 e2fsck_t ctx;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015346 struct problem_context pctx;
15347 int flags, run_result;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015348
Mike Frysinger51a43b42005-09-24 07:11:16 +000015349 clear_problem_context(&pctx);
15350#ifdef MTRACE
15351 mtrace();
15352#endif
15353#ifdef MCHECK
15354 mcheck(0);
15355#endif
15356#ifdef ENABLE_NLS
15357 setlocale(LC_MESSAGES, "");
15358 setlocale(LC_CTYPE, "");
15359 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
15360 textdomain(NLS_CAT_NAME);
15361#endif
15362 my_ver = ext2fs_parse_version_string(my_ver_string);
15363 lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
15364 if (my_ver > lib_ver) {
15365 fprintf( stderr, _("Error: ext2fs library version "
15366 "out of date!\n"));
15367 show_version_only++;
15368 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015369
Mike Frysinger51a43b42005-09-24 07:11:16 +000015370 retval = PRS(argc, argv, &ctx);
15371 if (retval) {
15372 com_err("e2fsck", retval,
15373 _("while trying to initialize program"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015374 exit(EXIT_ERROR);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015375 }
15376 reserve_stdio_fds();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015377
Mike Frysinger51a43b42005-09-24 07:11:16 +000015378#ifdef RESOURCE_TRACK
15379 init_resource_track(&ctx->global_rtrack);
15380#endif
15381
15382 if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
15383 fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string,
15384 my_ver_date);
15385
15386 if (show_version_only) {
15387 fprintf(stderr, _("\tUsing %s, %s\n"),
15388 error_message(EXT2_ET_BASE), lib_ver_date);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015389 exit(EXIT_OK);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015390 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015391
Mike Frysinger51a43b42005-09-24 07:11:16 +000015392 check_mount(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015393
Mike Frysinger51a43b42005-09-24 07:11:16 +000015394 if (!(ctx->options & E2F_OPT_PREEN) &&
15395 !(ctx->options & E2F_OPT_NO) &&
15396 !(ctx->options & E2F_OPT_YES)) {
15397 if (!ctx->interactive)
15398 fatal_error(ctx,
15399 _("need terminal for interactive repairs"));
15400 }
15401 ctx->superblock = ctx->use_superblock;
15402restart:
15403#ifdef CONFIG_TESTIO_DEBUG
15404 io_ptr = test_io_manager;
15405 test_io_backing_manager = unix_io_manager;
15406#else
15407 io_ptr = unix_io_manager;
15408#endif
15409 flags = 0;
15410 if ((ctx->options & E2F_OPT_READONLY) == 0)
15411 flags |= EXT2_FLAG_RW;
15412
15413 if (ctx->superblock && ctx->blocksize) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015414 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015415 flags, ctx->superblock, ctx->blocksize,
15416 io_ptr, &fs);
15417 } else if (ctx->superblock) {
15418 int blocksize;
15419 for (blocksize = EXT2_MIN_BLOCK_SIZE;
15420 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015421 retval = ext2fs_open2(ctx->filesystem_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015422 ctx->io_options, flags,
15423 ctx->superblock, blocksize,
15424 io_ptr, &fs);
15425 if (!retval)
15426 break;
15427 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015428 } else
15429 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015430 flags, 0, 0, io_ptr, &fs);
15431 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
15432 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
15433 ((retval == EXT2_ET_BAD_MAGIC) ||
15434 ((retval == 0) && ext2fs_check_desc(fs)))) {
15435 if (!fs || (fs->group_desc_count > 1)) {
15436 printf(_("%s trying backup blocks...\n"),
15437 retval ? _("Couldn't find ext2 superblock,") :
15438 _("Group descriptors look bad..."));
15439 get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
15440 if (fs)
15441 ext2fs_close(fs);
15442 goto restart;
15443 }
15444 }
15445 if (retval) {
15446 com_err(ctx->program_name, retval, _("while trying to open %s"),
15447 ctx->filesystem_name);
15448 if (retval == EXT2_ET_REV_TOO_HIGH) {
15449 printf(_("The filesystem revision is apparently "
15450 "too high for this version of e2fsck.\n"
15451 "(Or the filesystem superblock "
15452 "is corrupt)\n\n"));
15453 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
15454 } else if (retval == EXT2_ET_SHORT_READ)
15455 printf(_("Could this be a zero-length partition?\n"));
15456 else if ((retval == EPERM) || (retval == EACCES))
15457 printf(_("You must have %s access to the "
15458 "filesystem or be root\n"),
15459 (ctx->options & E2F_OPT_READONLY) ?
15460 "r/o" : "r/w");
15461 else if (retval == ENXIO)
15462 printf(_("Possibly non-existent or swap device?\n"));
15463#ifdef EROFS
15464 else if (retval == EROFS)
15465 printf(_("Disk write-protected; use the -n option "
15466 "to do a read-only\n"
15467 "check of the device.\n"));
15468#endif
15469 else
15470 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
15471 fatal_error(ctx, 0);
15472 }
15473 ctx->fs = fs;
15474 fs->priv_data = ctx;
15475 sb = fs->super;
15476 if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
15477 com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH,
15478 _("while trying to open %s"),
15479 ctx->filesystem_name);
15480 get_newer:
15481 fatal_error(ctx, _("Get a newer version of e2fsck!"));
15482 }
15483
15484 /*
15485 * Set the device name, which is used whenever we print error
15486 * or informational messages to the user.
15487 */
15488 if (ctx->device_name == 0 &&
15489 (sb->s_volume_name[0] != 0)) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015490 ctx->device_name = string_copy(sb->s_volume_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015491 sizeof(sb->s_volume_name));
15492 }
15493 if (ctx->device_name == 0)
15494 ctx->device_name = ctx->filesystem_name;
15495
15496 /*
15497 * Make sure the ext3 superblock fields are consistent.
15498 */
15499 retval = e2fsck_check_ext3_journal(ctx);
15500 if (retval) {
15501 com_err(ctx->program_name, retval,
15502 _("while checking ext3 journal for %s"),
15503 ctx->device_name);
15504 fatal_error(ctx, 0);
15505 }
15506
15507 /*
15508 * Check to see if we need to do ext3-style recovery. If so,
15509 * do it, and then restart the fsck.
15510 */
15511 if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
15512 if (ctx->options & E2F_OPT_READONLY) {
15513 printf(_("Warning: skipping journal recovery "
15514 "because doing a read-only filesystem "
15515 "check.\n"));
15516 io_channel_flush(ctx->fs->io);
15517 } else {
15518 if (ctx->flags & E2F_FLAG_RESTARTED) {
15519 /*
15520 * Whoops, we attempted to run the
15521 * journal twice. This should never
15522 * happen, unless the hardware or
15523 * device driver is being bogus.
15524 */
15525 com_err(ctx->program_name, 0,
15526 _("unable to set superblock flags on %s\n"), ctx->device_name);
15527 fatal_error(ctx, 0);
15528 }
15529 retval = e2fsck_run_ext3_journal(ctx);
15530 if (retval) {
15531 com_err(ctx->program_name, retval,
15532 _("while recovering ext3 journal of %s"),
15533 ctx->device_name);
15534 fatal_error(ctx, 0);
15535 }
15536 ext2fs_close(ctx->fs);
15537 ctx->fs = 0;
15538 ctx->flags |= E2F_FLAG_RESTARTED;
15539 goto restart;
15540 }
15541 }
15542
15543 /*
15544 * Check for compatibility with the feature sets. We need to
15545 * be more stringent than ext2fs_open().
15546 */
15547 if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
15548 (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
15549 com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
15550 "(%s)", ctx->device_name);
15551 goto get_newer;
15552 }
15553 if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
15554 com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE,
15555 "(%s)", ctx->device_name);
15556 goto get_newer;
15557 }
15558#ifdef ENABLE_COMPRESSION
15559 if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
15560 com_err(ctx->program_name, 0,
15561 _("Warning: compression support is experimental.\n"));
15562#endif
15563#ifndef ENABLE_HTREE
15564 if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
15565 com_err(ctx->program_name, 0,
15566 _("E2fsck not compiled with HTREE support,\n\t"
15567 "but filesystem %s has HTREE directories.\n"),
15568 ctx->device_name);
15569 goto get_newer;
15570 }
15571#endif
15572
15573 /*
15574 * If the user specified a specific superblock, presumably the
15575 * master superblock has been trashed. So we mark the
15576 * superblock as dirty, so it can be written out.
15577 */
15578 if (ctx->superblock &&
15579 !(ctx->options & E2F_OPT_READONLY))
15580 ext2fs_mark_super_dirty(fs);
15581
15582 /*
15583 * We only update the master superblock because (a) paranoia;
15584 * we don't want to corrupt the backup superblocks, and (b) we
15585 * don't need to update the mount count and last checked
15586 * fields in the backup superblock (the kernel doesn't
15587 * update the backup superblocks anyway).
15588 */
15589 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
15590
15591 ehandler_init(fs->io);
15592
15593 if (ctx->superblock)
15594 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
15595 ext2fs_mark_valid(fs);
15596 check_super_block(ctx);
15597 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15598 fatal_error(ctx, 0);
15599 check_if_skip(ctx);
15600 if (bad_blocks_file)
15601 read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks);
15602 else if (cflag)
15603 read_bad_blocks_file(ctx, 0, !keep_bad_blocks); /* Test disk */
15604 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15605 fatal_error(ctx, 0);
15606#ifdef ENABLE_SWAPFS
Rob Landley391a9042006-01-23 21:38:06 +000015607
15608#ifdef WORDS_BIGENDIAN
Rob Landley8b606342006-01-24 02:38:28 +000015609#define NATIVE_FLAG EXT2_FLAG_SWAP_BYTES
Rob Landley391a9042006-01-23 21:38:06 +000015610#else
Rob Landley8b606342006-01-24 02:38:28 +000015611#define NATIVE_FLAG 0
Rob Landley391a9042006-01-23 21:38:06 +000015612#endif
15613
15614
Mike Frysinger51a43b42005-09-24 07:11:16 +000015615 if (normalize_swapfs) {
Rob Landley391a9042006-01-23 21:38:06 +000015616 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == NATIVE_FLAG) {
Mike Frysinger51a43b42005-09-24 07:11:16 +000015617 fprintf(stderr, _("%s: Filesystem byte order "
15618 "already normalized.\n"), ctx->device_name);
15619 fatal_error(ctx, 0);
15620 }
15621 }
15622 if (swapfs) {
15623 swap_filesys(ctx);
15624 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15625 fatal_error(ctx, 0);
15626 }
15627#endif
15628
15629 /*
15630 * Mark the system as valid, 'til proven otherwise
15631 */
15632 ext2fs_mark_valid(fs);
15633
15634 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
15635 if (retval) {
15636 com_err(ctx->program_name, retval,
15637 _("while reading bad blocks inode"));
15638 preenhalt(ctx);
15639 printf(_("This doesn't bode well,"
15640 " but we'll try to go on...\n"));
15641 }
15642
15643 run_result = e2fsck_run(ctx);
15644 e2fsck_clear_progbar(ctx);
15645 if (run_result == E2F_FLAG_RESTART) {
15646 printf(_("Restarting e2fsck from the beginning...\n"));
15647 retval = e2fsck_reset_context(ctx);
15648 if (retval) {
15649 com_err(ctx->program_name, retval,
15650 _("while resetting context"));
15651 fatal_error(ctx, 0);
15652 }
15653 ext2fs_close(fs);
15654 goto restart;
15655 }
15656 if (run_result & E2F_FLAG_CANCEL) {
15657 printf(_("%s: e2fsck canceled.\n"), ctx->device_name ?
15658 ctx->device_name : ctx->filesystem_name);
15659 exit_value |= FSCK_CANCELED;
15660 }
15661 if (run_result & E2F_FLAG_ABORT)
15662 fatal_error(ctx, _("aborted"));
15663
15664#ifdef MTRACE
15665 mtrace_print("Cleanup");
15666#endif
15667 if (ext2fs_test_changed(fs)) {
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015668 exit_value |= EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015669 if (!(ctx->options & E2F_OPT_PREEN))
15670 printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
15671 ctx->device_name);
15672 if (ctx->mount_flags & EXT2_MF_ISROOT) {
15673 printf(_("%s: ***** REBOOT LINUX *****\n"),
15674 ctx->device_name);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015675 exit_value |= EXIT_DESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015676 }
15677 }
15678 if (!ext2fs_test_valid(fs)) {
15679 printf(_("\n%s: ********** WARNING: Filesystem still has "
15680 "errors **********\n\n"), ctx->device_name);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015681 exit_value |= EXIT_UNCORRECTED;
15682 exit_value &= ~EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015683 }
15684 if (exit_value & FSCK_CANCELED)
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015685 exit_value &= ~EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015686 else {
15687 show_stats(ctx);
15688 if (!(ctx->options & E2F_OPT_READONLY)) {
15689 if (ext2fs_test_valid(fs)) {
15690 if (!(sb->s_state & EXT2_VALID_FS))
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015691 exit_value |= EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015692 sb->s_state = EXT2_VALID_FS;
15693 } else
15694 sb->s_state &= ~EXT2_VALID_FS;
15695 sb->s_mnt_count = 0;
15696 sb->s_lastcheck = time(NULL);
15697 ext2fs_mark_super_dirty(fs);
15698 }
15699 }
15700
15701 e2fsck_write_bitmaps(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015702
Mike Frysinger51a43b42005-09-24 07:11:16 +000015703 ext2fs_close(fs);
15704 ctx->fs = NULL;
15705 free(ctx->filesystem_name);
15706 free(ctx->journal_name);
15707 e2fsck_free_context(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015708
Mike Frysinger51a43b42005-09-24 07:11:16 +000015709#ifdef RESOURCE_TRACK
15710 if (ctx->options & E2F_OPT_TIME)
15711 print_resource_track(NULL, &ctx->global_rtrack);
15712#endif
15713
15714 return exit_value;
15715}