blob: fb1e772a45a79e440058371924a6a5e9490265f2 [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
Mike Frysinger874af852006-03-08 07:03:27 +00003715 * @m multiply-claimed
3716 * @n invalid
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003717 * @o orphaned
3718 * @p problem in
3719 * @r root inode
3720 * @s should be
3721 * @S superblock
3722 * @u unattached
3723 * @v device
3724 * @z zero-length
3725 */
3726
3727
3728/*
3729 * This structure defines the abbreviations used by the text strings
3730 * below. The first character in the string is the index letter. An
3731 * abbreviation of the form '@<i>' is expanded by looking up the index
3732 * letter <i> in the table below.
3733 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003734static const char * const abbrevs[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003735 N_("aextended attribute"),
3736 N_("Aerror allocating"),
3737 N_("bblock"),
3738 N_("Bbitmap"),
3739 N_("ccompress"),
3740 N_("Cconflicts with some other fs @b"),
3741 N_("iinode"),
3742 N_("Iillegal"),
3743 N_("jjournal"),
3744 N_("Ddeleted"),
3745 N_("ddirectory"),
3746 N_("eentry"),
3747 N_("E@e '%Dn' in %p (%i)"),
3748 N_("ffilesystem"),
3749 N_("Ffor @i %i (%Q) is"),
3750 N_("ggroup"),
3751 N_("hHTREE @d @i"),
3752 N_("llost+found"),
3753 N_("Lis a link"),
Mike Frysinger874af852006-03-08 07:03:27 +00003754 N_("mmultiply-claimed"),
3755 N_("ninvalid"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003756 N_("oorphaned"),
3757 N_("pproblem in"),
3758 N_("rroot @i"),
3759 N_("sshould be"),
3760 N_("Ssuper@b"),
3761 N_("uunattached"),
3762 N_("vdevice"),
3763 N_("zzero-length"),
3764 "@@",
3765 0
3766 };
3767
3768/*
3769 * Give more user friendly names to the "special" inodes.
3770 */
3771#define num_special_inodes 11
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003772static const char * const special_inode_name[] =
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003773{
3774 N_("<The NULL inode>"), /* 0 */
3775 N_("<The bad blocks inode>"), /* 1 */
3776 "/", /* 2 */
3777 N_("<The ACL index inode>"), /* 3 */
3778 N_("<The ACL data inode>"), /* 4 */
3779 N_("<The boot loader inode>"), /* 5 */
3780 N_("<The undelete directory inode>"), /* 6 */
3781 N_("<The group descriptor inode>"), /* 7 */
3782 N_("<The journal inode>"), /* 8 */
3783 N_("<Reserved inode 9>"), /* 9 */
3784 N_("<Reserved inode 10>"), /* 10 */
3785};
3786
3787/*
3788 * This function does "safe" printing. It will convert non-printable
3789 * ASCII characters using '^' and M- notation.
3790 */
3791static void safe_print(const char *cp, int len)
3792{
3793 unsigned char ch;
3794
3795 if (len < 0)
3796 len = strlen(cp);
3797
3798 while (len--) {
3799 ch = *cp++;
3800 if (ch > 128) {
3801 fputs("M-", stdout);
3802 ch -= 128;
3803 }
3804 if ((ch < 32) || (ch == 0x7f)) {
3805 fputc('^', stdout);
3806 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
3807 }
3808 fputc(ch, stdout);
3809 }
3810}
3811
3812
3813/*
3814 * This function prints a pathname, using the ext2fs_get_pathname
3815 * function
3816 */
3817static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
3818{
3819 errcode_t retval;
3820 char *path;
3821
3822 if (!dir && (ino < num_special_inodes)) {
3823 fputs(_(special_inode_name[ino]), stdout);
3824 return;
3825 }
3826
3827 retval = ext2fs_get_pathname(fs, dir, ino, &path);
3828 if (retval)
3829 fputs("???", stdout);
3830 else {
3831 safe_print(path, -1);
3832 ext2fs_free_mem(&path);
3833 }
3834}
3835
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003836static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
3837 struct problem_context *pctx, int first);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003838/*
3839 * This function handles the '@' expansion. We allow recursive
3840 * expansion; an @ expression can contain further '@' and '%'
3841 * expressions.
3842 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003843static void expand_at_expression(e2fsck_t ctx, char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003844 struct problem_context *pctx,
3845 int *first)
3846{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003847 const char * const *cpp;
3848 const char *str;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003849
3850 /* Search for the abbreviation */
3851 for (cpp = abbrevs; *cpp; cpp++) {
3852 if (ch == *cpp[0])
3853 break;
3854 }
3855 if (*cpp) {
3856 str = _(*cpp) + 1;
3857 if (*first && islower(*str)) {
3858 *first = 0;
3859 fputc(toupper(*str++), stdout);
3860 }
3861 print_e2fsck_message(ctx, str, pctx, *first);
3862 } else
3863 printf("@%c", ch);
3864}
3865
3866/*
3867 * This function expands '%IX' expressions
3868 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003869static void expand_inode_expression(char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003870 struct problem_context *ctx)
3871{
3872 struct ext2_inode *inode;
3873 struct ext2_inode_large *large_inode;
3874 char * time_str;
3875 time_t t;
3876 int do_gmt = -1;
3877
3878 if (!ctx || !ctx->inode)
3879 goto no_inode;
3880
3881 inode = ctx->inode;
3882 large_inode = (struct ext2_inode_large *) inode;
3883
3884 switch (ch) {
3885 case 's':
3886 if (LINUX_S_ISDIR(inode->i_mode))
3887 printf("%u", inode->i_size);
3888 else {
3889#ifdef EXT2_NO_64_TYPE
3890 if (inode->i_size_high)
3891 printf("0x%x%08x", inode->i_size_high,
3892 inode->i_size);
3893 else
3894 printf("%u", inode->i_size);
3895#else
3896 printf("%llu", (inode->i_size |
3897 ((__u64) inode->i_size_high << 32)));
3898#endif
3899 }
3900 break;
3901 case 'S':
3902 printf("%u", large_inode->i_extra_isize);
3903 break;
3904 case 'b':
3905 printf("%u", inode->i_blocks);
3906 break;
3907 case 'l':
3908 printf("%d", inode->i_links_count);
3909 break;
3910 case 'm':
3911 printf("0%o", inode->i_mode);
3912 break;
3913 case 'M':
3914 /* The diet libc doesn't respect the TZ environemnt variable */
3915 if (do_gmt == -1) {
3916 time_str = getenv("TZ");
3917 if (!time_str)
3918 time_str = "";
3919 do_gmt = !strcmp(time_str, "GMT");
3920 }
3921 t = inode->i_mtime;
3922 time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
3923 printf("%.24s", time_str);
3924 break;
3925 case 'F':
3926 printf("%u", inode->i_faddr);
3927 break;
3928 case 'f':
3929 printf("%u", inode->i_file_acl);
3930 break;
3931 case 'd':
3932 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
3933 inode->i_dir_acl : 0));
3934 break;
3935 case 'u':
3936 printf("%d", (inode->i_uid |
3937 (inode->osd2.linux2.l_i_uid_high << 16)));
3938 break;
3939 case 'g':
3940 printf("%d", (inode->i_gid |
3941 (inode->osd2.linux2.l_i_gid_high << 16)));
3942 break;
3943 default:
3944 no_inode:
3945 printf("%%I%c", ch);
3946 break;
3947 }
3948}
3949
3950/*
3951 * This function expands '%dX' expressions
3952 */
3953static _INLINE_ void expand_dirent_expression(char ch,
3954 struct problem_context *ctx)
3955{
3956 struct ext2_dir_entry *dirent;
3957 int len;
3958
3959 if (!ctx || !ctx->dirent)
3960 goto no_dirent;
3961
3962 dirent = ctx->dirent;
3963
3964 switch (ch) {
3965 case 'i':
3966 printf("%u", dirent->inode);
3967 break;
3968 case 'n':
3969 len = dirent->name_len & 0xFF;
3970 if (len > EXT2_NAME_LEN)
3971 len = EXT2_NAME_LEN;
3972 if (len > dirent->rec_len)
3973 len = dirent->rec_len;
3974 safe_print(dirent->name, len);
3975 break;
3976 case 'r':
3977 printf("%u", dirent->rec_len);
3978 break;
3979 case 'l':
3980 printf("%u", dirent->name_len & 0xFF);
3981 break;
3982 case 't':
3983 printf("%u", dirent->name_len >> 8);
3984 break;
3985 default:
3986 no_dirent:
3987 printf("%%D%c", ch);
3988 break;
3989 }
3990}
3991
3992static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
3993 struct problem_context *ctx)
3994{
3995 if (!ctx)
3996 goto no_context;
3997
3998 switch (ch) {
3999 case '%':
4000 fputc('%', stdout);
4001 break;
4002 case 'b':
4003 printf("%u", ctx->blk);
4004 break;
4005 case 'B':
4006#ifdef EXT2_NO_64_TYPE
4007 printf("%d", ctx->blkcount);
4008#else
4009 printf("%lld", ctx->blkcount);
4010#endif
4011 break;
4012 case 'c':
4013 printf("%u", ctx->blk2);
4014 break;
4015 case 'd':
4016 printf("%u", ctx->dir);
4017 break;
4018 case 'g':
4019 printf("%d", ctx->group);
4020 break;
4021 case 'i':
4022 printf("%u", ctx->ino);
4023 break;
4024 case 'j':
4025 printf("%u", ctx->ino2);
4026 break;
4027 case 'm':
4028 printf("%s", error_message(ctx->errcode));
4029 break;
4030 case 'N':
4031#ifdef EXT2_NO_64_TYPE
4032 printf("%u", ctx->num);
4033#else
4034 printf("%llu", ctx->num);
4035#endif
4036 break;
4037 case 'p':
4038 print_pathname(fs, ctx->ino, 0);
4039 break;
4040 case 'P':
4041 print_pathname(fs, ctx->ino2,
4042 ctx->dirent ? ctx->dirent->inode : 0);
4043 break;
4044 case 'q':
4045 print_pathname(fs, ctx->dir, 0);
4046 break;
4047 case 'Q':
4048 print_pathname(fs, ctx->dir, ctx->ino);
4049 break;
4050 case 'S':
4051 printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
4052 break;
4053 case 's':
4054 printf("%s", ctx->str ? ctx->str : "NULL");
4055 break;
4056 case 'X':
4057#ifdef EXT2_NO_64_TYPE
4058 printf("0x%x", ctx->num);
4059#else
4060 printf("0x%llx", ctx->num);
4061#endif
4062 break;
4063 default:
4064 no_context:
4065 printf("%%%c", ch);
4066 break;
4067 }
4068}
4069
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004070
4071static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004072 struct problem_context *pctx, int first)
4073{
4074 ext2_filsys fs = ctx->fs;
4075 const char * cp;
4076 int i;
4077
4078 e2fsck_clear_progbar(ctx);
4079 for (cp = msg; *cp; cp++) {
4080 if (cp[0] == '@') {
4081 cp++;
4082 expand_at_expression(ctx, *cp, pctx, &first);
4083 } else if (cp[0] == '%' && cp[1] == 'I') {
4084 cp += 2;
4085 expand_inode_expression(*cp, pctx);
4086 } else if (cp[0] == '%' && cp[1] == 'D') {
4087 cp += 2;
4088 expand_dirent_expression(*cp, pctx);
4089 } else if ((cp[0] == '%')) {
4090 cp++;
4091 expand_percent_expression(fs, *cp, pctx);
4092 } else {
4093 for (i=0; cp[i]; i++)
4094 if ((cp[i] == '@') || cp[i] == '%')
4095 break;
4096 printf("%.*s", i, cp);
4097 cp += i-1;
4098 }
4099 first = 0;
4100 }
4101}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004102
4103
4104/*
4105 * region.c --- code which manages allocations within a region.
4106 */
4107
4108struct region_el {
4109 region_addr_t start;
4110 region_addr_t end;
4111 struct region_el *next;
4112};
4113
4114struct region_struct {
4115 region_addr_t min;
4116 region_addr_t max;
4117 struct region_el *allocated;
4118};
4119
4120static region_t region_create(region_addr_t min, region_addr_t max)
4121{
4122 region_t region;
4123
4124 region = malloc(sizeof(struct region_struct));
4125 if (!region)
4126 return NULL;
4127 memset(region, 0, sizeof(struct region_struct));
4128 region->min = min;
4129 region->max = max;
4130 return region;
4131}
4132
4133static void region_free(region_t region)
4134{
4135 struct region_el *r, *next;
4136
4137 for (r = region->allocated; r; r = next) {
4138 next = r->next;
4139 free(r);
4140 }
4141 memset(region, 0, sizeof(struct region_struct));
4142 free(region);
4143}
4144
4145static int region_allocate(region_t region, region_addr_t start, int n)
4146{
4147 struct region_el *r, *new_region, *prev, *next;
4148 region_addr_t end;
4149
4150 end = start+n;
4151 if ((start < region->min) || (end > region->max))
4152 return -1;
4153 if (n == 0)
4154 return 1;
4155
4156 /*
4157 * Search through the linked list. If we find that it
4158 * conflicts witih something that's already allocated, return
4159 * 1; if we can find an existing region which we can grow, do
4160 * so. Otherwise, stop when we find the appropriate place
4161 * insert a new region element into the linked list.
4162 */
4163 for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
4164 if (((start >= r->start) && (start < r->end)) ||
4165 ((end > r->start) && (end <= r->end)) ||
4166 ((start <= r->start) && (end >= r->end)))
4167 return 1;
4168 if (end == r->start) {
4169 r->start = start;
4170 return 0;
4171 }
4172 if (start == r->end) {
4173 if ((next = r->next)) {
4174 if (end > next->start)
4175 return 1;
4176 if (end == next->start) {
4177 r->end = next->end;
4178 r->next = next->next;
4179 free(next);
4180 return 0;
4181 }
4182 }
4183 r->end = end;
4184 return 0;
4185 }
4186 if (start < r->start)
4187 break;
4188 }
4189 /*
4190 * Insert a new region element structure into the linked list
4191 */
4192 new_region = malloc(sizeof(struct region_el));
4193 if (!new_region)
4194 return -1;
4195 new_region->start = start;
4196 new_region->end = start + n;
4197 new_region->next = r;
4198 if (prev)
4199 prev->next = new_region;
4200 else
4201 region->allocated = new_region;
4202 return 0;
4203}
4204
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004205/*
4206 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
4207 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004208 * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
4209 * and applies the following tests to each inode:
4210 *
4211 * - The mode field of the inode must be legal.
4212 * - The size and block count fields of the inode are correct.
4213 * - A data block must not be used by another inode
4214 *
4215 * Pass 1 also gathers the collects the following information:
4216 *
4217 * - A bitmap of which inodes are in use. (inode_used_map)
4218 * - A bitmap of which inodes are directories. (inode_dir_map)
4219 * - A bitmap of which inodes are regular files. (inode_reg_map)
4220 * - A bitmap of which inodes have bad fields. (inode_bad_map)
4221 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
4222 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
4223 * - A bitmap of which blocks are in use. (block_found_map)
4224 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
4225 * - The data blocks of the directory inodes. (dir_map)
4226 *
4227 * Pass 1 is designed to stash away enough information so that the
4228 * other passes should not need to read in the inode information
4229 * during the normal course of a filesystem check. (Althogh if an
4230 * inconsistency is detected, other passes may need to read in an
4231 * inode to fix it.)
4232 *
4233 * Note that pass 1B will be invoked if there are any duplicate blocks
4234 * found.
4235 */
4236
4237
4238static int process_block(ext2_filsys fs, blk_t *blocknr,
4239 e2_blkcnt_t blockcnt, blk_t ref_blk,
4240 int ref_offset, void *priv_data);
4241static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
4242 e2_blkcnt_t blockcnt, blk_t ref_blk,
4243 int ref_offset, void *priv_data);
4244static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
4245 char *block_buf);
4246static void mark_table_blocks(e2fsck_t ctx);
4247static void alloc_bb_map(e2fsck_t ctx);
4248static void alloc_imagic_map(e2fsck_t ctx);
4249static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
4250static void handle_fs_bad_blocks(e2fsck_t ctx);
4251static void process_inodes(e2fsck_t ctx, char *block_buf);
4252static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
4253static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
4254 dgrp_t group, void * priv_data);
4255static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
4256 char *block_buf, int adjust_sign);
4257/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
4258
4259static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
4260 struct ext2_inode * inode, int bufsize,
4261 const char *proc);
4262
4263struct process_block_struct_1 {
4264 ext2_ino_t ino;
4265 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
4266 fragmented:1, compressed:1, bbcheck:1;
4267 blk_t num_blocks;
4268 blk_t max_blocks;
4269 e2_blkcnt_t last_block;
4270 int num_illegal_blocks;
4271 blk_t previous_block;
4272 struct ext2_inode *inode;
4273 struct problem_context *pctx;
4274 ext2fs_block_bitmap fs_meta_blocks;
4275 e2fsck_t ctx;
4276};
4277
4278struct process_inode_block {
4279 ext2_ino_t ino;
4280 struct ext2_inode inode;
4281};
4282
4283struct scan_callback_struct {
4284 e2fsck_t ctx;
4285 char *block_buf;
4286};
4287
4288/*
4289 * For the inodes to process list.
4290 */
4291static struct process_inode_block *inodes_to_process;
4292static int process_inode_count;
4293
4294static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
4295 EXT2_MIN_BLOCK_LOG_SIZE + 1];
4296
4297/*
4298 * Free all memory allocated by pass1 in preparation for restarting
4299 * things.
4300 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004301static void unwind_pass1(void)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004302{
4303 ext2fs_free_mem(&inodes_to_process);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004304}
4305
4306/*
4307 * Check to make sure a device inode is real. Returns 1 if the device
4308 * checks out, 0 if not.
4309 *
4310 * Note: this routine is now also used to check FIFO's and Sockets,
4311 * since they have the same requirement; the i_block fields should be
4312 * zero.
4313 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004314static int
4315e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004316{
4317 int i;
4318
4319 /*
4320 * If i_blocks is non-zero, or the index flag is set, then
4321 * this is a bogus device/fifo/socket
4322 */
4323 if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
4324 (inode->i_flags & EXT2_INDEX_FL))
4325 return 0;
4326
4327 /*
4328 * We should be able to do the test below all the time, but
4329 * because the kernel doesn't forcibly clear the device
4330 * inode's additional i_block fields, there are some rare
4331 * occasions when a legitimate device inode will have non-zero
4332 * additional i_block fields. So for now, we only complain
4333 * when the immutable flag is set, which should never happen
4334 * for devices. (And that's when the problem is caused, since
4335 * you can't set or clear immutable flags for devices.) Once
4336 * the kernel has been fixed we can change this...
4337 */
4338 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
4339 for (i=4; i < EXT2_N_BLOCKS; i++)
4340 if (inode->i_block[i])
4341 return 0;
4342 }
4343 return 1;
4344}
4345
4346/*
4347 * Check to make sure a symlink inode is real. Returns 1 if the symlink
4348 * checks out, 0 if not.
4349 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004350static int
4351e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, char *buf)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004352{
4353 unsigned int len;
4354 int i;
4355 blk_t blocks;
4356
4357 if ((inode->i_size_high || inode->i_size == 0) ||
4358 (inode->i_flags & EXT2_INDEX_FL))
4359 return 0;
4360
4361 blocks = ext2fs_inode_data_blocks(fs, inode);
4362 if (blocks) {
4363 if ((inode->i_size >= fs->blocksize) ||
4364 (blocks != fs->blocksize >> 9) ||
4365 (inode->i_block[0] < fs->super->s_first_data_block) ||
4366 (inode->i_block[0] >= fs->super->s_blocks_count))
4367 return 0;
4368
4369 for (i = 1; i < EXT2_N_BLOCKS; i++)
4370 if (inode->i_block[i])
4371 return 0;
4372
4373 if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
4374 return 0;
4375
4376 len = strnlen(buf, fs->blocksize);
4377 if (len == fs->blocksize)
4378 return 0;
4379 } else {
4380 if (inode->i_size >= sizeof(inode->i_block))
4381 return 0;
4382
4383 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
4384 if (len == sizeof(inode->i_block))
4385 return 0;
4386 }
4387 if (len != inode->i_size)
4388 return 0;
4389 return 1;
4390}
4391
4392/*
4393 * If the immutable (or append-only) flag is set on the inode, offer
4394 * to clear it.
4395 */
4396#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
4397static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
4398{
4399 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
4400 return;
4401
4402 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
4403 return;
4404
4405 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
4406 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4407}
4408
4409/*
4410 * If device, fifo or socket, check size is zero -- if not offer to
4411 * clear it
4412 */
4413static void check_size(e2fsck_t ctx, struct problem_context *pctx)
4414{
4415 struct ext2_inode *inode = pctx->inode;
4416
4417 if ((inode->i_size == 0) && (inode->i_size_high == 0))
4418 return;
4419
4420 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
4421 return;
4422
4423 inode->i_size = 0;
4424 inode->i_size_high = 0;
4425 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4426}
4427
4428static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
4429{
4430 struct ext2_super_block *sb = ctx->fs->super;
4431 struct ext2_inode_large *inode;
4432 struct ext2_ext_attr_entry *entry;
4433 char *start, *end;
4434 int storage_size, remain, offs;
4435 int problem = 0;
4436
4437 inode = (struct ext2_inode_large *) pctx->inode;
4438 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
4439 inode->i_extra_isize;
4440 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4441 inode->i_extra_isize + sizeof(__u32);
4442 end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
4443 entry = (struct ext2_ext_attr_entry *) start;
4444
4445 /* scan all entry's headers first */
4446
4447 /* take finish entry 0UL into account */
4448 remain = storage_size - sizeof(__u32);
4449 offs = end - start;
4450
4451 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
4452
4453 /* header eats this space */
4454 remain -= sizeof(struct ext2_ext_attr_entry);
4455
4456 /* is attribute name valid? */
4457 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
4458 pctx->num = entry->e_name_len;
4459 problem = PR_1_ATTR_NAME_LEN;
4460 goto fix;
4461 }
4462
4463 /* attribute len eats this space */
4464 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
4465
4466 /* check value size */
4467 if (entry->e_value_size == 0 || entry->e_value_size > remain) {
4468 pctx->num = entry->e_value_size;
4469 problem = PR_1_ATTR_VALUE_SIZE;
4470 goto fix;
4471 }
4472
4473 /* check value placement */
4474 if (entry->e_value_offs +
4475 EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
4476 printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
4477 pctx->num = entry->e_value_offs;
4478 problem = PR_1_ATTR_VALUE_OFFSET;
4479 goto fix;
4480 }
4481
4482 /* e_value_block must be 0 in inode's ea */
4483 if (entry->e_value_block != 0) {
4484 pctx->num = entry->e_value_block;
4485 problem = PR_1_ATTR_VALUE_BLOCK;
4486 goto fix;
4487 }
4488
4489 /* e_hash must be 0 in inode's ea */
4490 if (entry->e_hash != 0) {
4491 pctx->num = entry->e_hash;
4492 problem = PR_1_ATTR_HASH;
4493 goto fix;
4494 }
4495
4496 remain -= entry->e_value_size;
4497 offs -= EXT2_XATTR_SIZE(entry->e_value_size);
4498
4499 entry = EXT2_EXT_ATTR_NEXT(entry);
4500 }
4501fix:
4502 /*
4503 * it seems like a corruption. it's very unlikely we could repair
4504 * EA(s) in automatic fashion -bzzz
4505 */
4506#if 0
4507 problem = PR_1_ATTR_HASH;
4508#endif
4509 if (problem == 0 || !fix_problem(ctx, problem, pctx))
4510 return;
4511
4512 /* simple remove all possible EA(s) */
4513 *((__u32 *)start) = 0UL;
4514 e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
4515 EXT2_INODE_SIZE(sb), "pass1");
4516}
4517
4518static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
4519{
4520 struct ext2_super_block *sb = ctx->fs->super;
4521 struct ext2_inode_large *inode;
4522 __u32 *eamagic;
4523 int min, max;
4524
4525 inode = (struct ext2_inode_large *) pctx->inode;
4526 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
4527 /* this isn't large inode. so, nothing to check */
4528 return;
4529 }
4530
4531#if 0
4532 printf("inode #%u, i_extra_size %d\n", pctx->ino,
4533 inode->i_extra_isize);
4534#endif
4535 /* i_extra_isize must cover i_extra_isize + i_pad1 at least */
4536 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
4537 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
4538 /*
4539 * For now we will allow i_extra_isize to be 0, but really
4540 * implementations should never allow i_extra_isize to be 0
4541 */
4542 if (inode->i_extra_isize &&
4543 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
4544 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
4545 return;
4546 inode->i_extra_isize = min;
4547 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
4548 EXT2_INODE_SIZE(sb), "pass1");
4549 return;
4550 }
4551
4552 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4553 inode->i_extra_isize);
4554 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
4555 /* it seems inode has an extended attribute(s) in body */
4556 check_ea_in_inode(ctx, pctx);
4557 }
4558}
4559
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004560static void e2fsck_pass1(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004561{
4562 int i;
4563 __u64 max_sizes;
4564 ext2_filsys fs = ctx->fs;
4565 ext2_ino_t ino;
4566 struct ext2_inode *inode;
4567 ext2_inode_scan scan;
4568 char *block_buf;
4569#ifdef RESOURCE_TRACK
4570 struct resource_track rtrack;
4571#endif
4572 unsigned char frag, fsize;
4573 struct problem_context pctx;
4574 struct scan_callback_struct scan_struct;
4575 struct ext2_super_block *sb = ctx->fs->super;
4576 int imagic_fs;
4577 int busted_fs_time = 0;
4578 int inode_size;
4579
4580#ifdef RESOURCE_TRACK
4581 init_resource_track(&rtrack);
4582#endif
4583 clear_problem_context(&pctx);
4584
4585 if (!(ctx->options & E2F_OPT_PREEN))
4586 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
4587
4588 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
4589 !(ctx->options & E2F_OPT_NO)) {
4590 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
4591 ctx->dirs_to_hash = 0;
4592 }
4593
4594#ifdef MTRACE
4595 mtrace_print("Pass 1");
4596#endif
4597
4598#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
4599
4600 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
4601 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
4602 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
4603 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
4604 max_sizes = (max_sizes * (1UL << i)) - 1;
4605 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
4606 }
4607#undef EXT2_BPP
4608
4609 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
4610
4611 /*
4612 * Allocate bitmaps structures
4613 */
4614 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
4615 &ctx->inode_used_map);
4616 if (pctx.errcode) {
4617 pctx.num = 1;
4618 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4619 ctx->flags |= E2F_FLAG_ABORT;
4620 return;
4621 }
4622 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4623 _("directory inode map"), &ctx->inode_dir_map);
4624 if (pctx.errcode) {
4625 pctx.num = 2;
4626 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4627 ctx->flags |= E2F_FLAG_ABORT;
4628 return;
4629 }
4630 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4631 _("regular file inode map"), &ctx->inode_reg_map);
4632 if (pctx.errcode) {
4633 pctx.num = 6;
4634 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4635 ctx->flags |= E2F_FLAG_ABORT;
4636 return;
4637 }
4638 pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
4639 &ctx->block_found_map);
4640 if (pctx.errcode) {
4641 pctx.num = 1;
4642 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4643 ctx->flags |= E2F_FLAG_ABORT;
4644 return;
4645 }
4646 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
4647 &ctx->inode_link_info);
4648 if (pctx.errcode) {
4649 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
4650 ctx->flags |= E2F_FLAG_ABORT;
4651 return;
4652 }
4653 inode_size = EXT2_INODE_SIZE(fs->super);
4654 inode = (struct ext2_inode *)
4655 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
4656
4657 inodes_to_process = (struct process_inode_block *)
4658 e2fsck_allocate_memory(ctx,
4659 (ctx->process_inode_size *
4660 sizeof(struct process_inode_block)),
4661 "array of inodes to process");
4662 process_inode_count = 0;
4663
4664 pctx.errcode = ext2fs_init_dblist(fs, 0);
4665 if (pctx.errcode) {
4666 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
4667 ctx->flags |= E2F_FLAG_ABORT;
4668 return;
4669 }
4670
4671 /*
4672 * If the last orphan field is set, clear it, since the pass1
4673 * processing will automatically find and clear the orphans.
4674 * In the future, we may want to try using the last_orphan
4675 * linked list ourselves, but for now, we clear it so that the
4676 * ext3 mount code won't get confused.
4677 */
4678 if (!(ctx->options & E2F_OPT_READONLY)) {
4679 if (fs->super->s_last_orphan) {
4680 fs->super->s_last_orphan = 0;
4681 ext2fs_mark_super_dirty(fs);
4682 }
4683 }
4684
4685 mark_table_blocks(ctx);
4686 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
4687 "block interate buffer");
4688 e2fsck_use_inode_shortcuts(ctx, 1);
4689 ehandler_operation(_("doing inode scan"));
4690 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
4691 &scan);
4692 if (pctx.errcode) {
4693 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4694 ctx->flags |= E2F_FLAG_ABORT;
4695 return;
4696 }
4697 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
4698 ctx->stashed_inode = inode;
4699 scan_struct.ctx = ctx;
4700 scan_struct.block_buf = block_buf;
4701 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
4702 if (ctx->progress)
4703 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
4704 return;
Mike Frysinger874af852006-03-08 07:03:27 +00004705 if ((fs->super->s_wtime < fs->super->s_inodes_count) ||
4706 (fs->super->s_mtime < fs->super->s_inodes_count))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004707 busted_fs_time = 1;
4708
4709 while (1) {
4710 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
4711 inode, inode_size);
4712 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4713 return;
4714 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
4715 if (!ctx->inode_bb_map)
4716 alloc_bb_map(ctx);
4717 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
4718 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4719 continue;
4720 }
4721 if (pctx.errcode) {
4722 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4723 ctx->flags |= E2F_FLAG_ABORT;
4724 return;
4725 }
4726 if (!ino)
4727 break;
4728 pctx.ino = ino;
4729 pctx.inode = inode;
4730 ctx->stashed_ino = ino;
4731 if (inode->i_links_count) {
4732 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
4733 ino, inode->i_links_count);
4734 if (pctx.errcode) {
4735 pctx.num = inode->i_links_count;
4736 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
4737 ctx->flags |= E2F_FLAG_ABORT;
4738 return;
4739 }
4740 }
4741 if (ino == EXT2_BAD_INO) {
4742 struct process_block_struct_1 pb;
4743
4744 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
4745 &pb.fs_meta_blocks);
4746 if (pctx.errcode) {
4747 pctx.num = 4;
4748 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4749 ctx->flags |= E2F_FLAG_ABORT;
4750 return;
4751 }
4752 pb.ino = EXT2_BAD_INO;
4753 pb.num_blocks = pb.last_block = 0;
4754 pb.num_illegal_blocks = 0;
4755 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
4756 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
4757 pb.inode = inode;
4758 pb.pctx = &pctx;
4759 pb.ctx = ctx;
4760 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
4761 block_buf, process_bad_block, &pb);
4762 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
4763 if (pctx.errcode) {
4764 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
4765 ctx->flags |= E2F_FLAG_ABORT;
4766 return;
4767 }
4768 if (pb.bbcheck)
4769 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
4770 ctx->flags |= E2F_FLAG_ABORT;
4771 return;
4772 }
4773 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4774 clear_problem_context(&pctx);
4775 continue;
4776 } else if (ino == EXT2_ROOT_INO) {
4777 /*
4778 * Make sure the root inode is a directory; if
4779 * not, offer to clear it. It will be
4780 * regnerated in pass #3.
4781 */
4782 if (!LINUX_S_ISDIR(inode->i_mode)) {
4783 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
4784 inode->i_dtime = time(0);
4785 inode->i_links_count = 0;
4786 ext2fs_icount_store(ctx->inode_link_info,
4787 ino, 0);
4788 e2fsck_write_inode(ctx, ino, inode,
4789 "pass1");
4790 }
4791
4792 }
4793 /*
4794 * If dtime is set, offer to clear it. mke2fs
4795 * version 0.2b created filesystems with the
4796 * dtime field set for the root and lost+found
4797 * directories. We won't worry about
4798 * /lost+found, since that can be regenerated
4799 * easily. But we will fix the root directory
4800 * as a special case.
4801 */
4802 if (inode->i_dtime && inode->i_links_count) {
4803 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
4804 inode->i_dtime = 0;
4805 e2fsck_write_inode(ctx, ino, inode,
4806 "pass1");
4807 }
4808 }
4809 } else if (ino == EXT2_JOURNAL_INO) {
4810 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4811 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
4812 if (!LINUX_S_ISREG(inode->i_mode) &&
4813 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
4814 &pctx)) {
4815 inode->i_mode = LINUX_S_IFREG;
4816 e2fsck_write_inode(ctx, ino, inode,
4817 "pass1");
4818 }
4819 check_blocks(ctx, &pctx, block_buf);
4820 continue;
4821 }
4822 if ((inode->i_links_count || inode->i_blocks ||
4823 inode->i_blocks || inode->i_block[0]) &&
4824 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
4825 &pctx)) {
4826 memset(inode, 0, inode_size);
4827 ext2fs_icount_store(ctx->inode_link_info,
4828 ino, 0);
4829 e2fsck_write_inode_full(ctx, ino, inode,
4830 inode_size, "pass1");
4831 }
4832 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
4833 int problem = 0;
4834
4835 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4836 if (ino == EXT2_BOOT_LOADER_INO) {
4837 if (LINUX_S_ISDIR(inode->i_mode))
4838 problem = PR_1_RESERVED_BAD_MODE;
4839 } else if (ino == EXT2_RESIZE_INO) {
4840 if (inode->i_mode &&
4841 !LINUX_S_ISREG(inode->i_mode))
4842 problem = PR_1_RESERVED_BAD_MODE;
4843 } else {
4844 if (inode->i_mode != 0)
4845 problem = PR_1_RESERVED_BAD_MODE;
4846 }
4847 if (problem) {
4848 if (fix_problem(ctx, problem, &pctx)) {
4849 inode->i_mode = 0;
4850 e2fsck_write_inode(ctx, ino, inode,
4851 "pass1");
4852 }
4853 }
4854 check_blocks(ctx, &pctx, block_buf);
4855 continue;
4856 }
4857 /*
4858 * Check for inodes who might have been part of the
4859 * orphaned list linked list. They should have gotten
4860 * dealt with by now, unless the list had somehow been
4861 * corrupted.
4862 *
4863 * FIXME: In the future, inodes which are still in use
4864 * (and which are therefore) pending truncation should
4865 * be handled specially. Right now we just clear the
4866 * dtime field, and the normal e2fsck handling of
4867 * inodes where i_size and the inode blocks are
4868 * inconsistent is to fix i_size, instead of releasing
4869 * the extra blocks. This won't catch the inodes that
4870 * was at the end of the orphan list, but it's better
4871 * than nothing. The right answer is that there
4872 * shouldn't be any bugs in the orphan list handling. :-)
4873 */
4874 if (inode->i_dtime && !busted_fs_time &&
4875 inode->i_dtime < ctx->fs->super->s_inodes_count) {
4876 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
4877 inode->i_dtime = inode->i_links_count ?
4878 0 : time(0);
4879 e2fsck_write_inode(ctx, ino, inode,
4880 "pass1");
4881 }
4882 }
4883
4884 /*
4885 * This code assumes that deleted inodes have
4886 * i_links_count set to 0.
4887 */
4888 if (!inode->i_links_count) {
4889 if (!inode->i_dtime && inode->i_mode) {
4890 if (fix_problem(ctx,
4891 PR_1_ZERO_DTIME, &pctx)) {
4892 inode->i_dtime = time(0);
4893 e2fsck_write_inode(ctx, ino, inode,
4894 "pass1");
4895 }
4896 }
4897 continue;
4898 }
4899 /*
4900 * n.b. 0.3c ext2fs code didn't clear i_links_count for
4901 * deleted files. Oops.
4902 *
4903 * Since all new ext2 implementations get this right,
4904 * we now assume that the case of non-zero
4905 * i_links_count and non-zero dtime means that we
4906 * should keep the file, not delete it.
4907 *
4908 */
4909 if (inode->i_dtime) {
4910 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
4911 inode->i_dtime = 0;
4912 e2fsck_write_inode(ctx, ino, inode, "pass1");
4913 }
4914 }
4915
4916 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4917 switch (fs->super->s_creator_os) {
4918 case EXT2_OS_LINUX:
4919 frag = inode->osd2.linux2.l_i_frag;
4920 fsize = inode->osd2.linux2.l_i_fsize;
4921 break;
4922 case EXT2_OS_HURD:
4923 frag = inode->osd2.hurd2.h_i_frag;
4924 fsize = inode->osd2.hurd2.h_i_fsize;
4925 break;
4926 case EXT2_OS_MASIX:
4927 frag = inode->osd2.masix2.m_i_frag;
4928 fsize = inode->osd2.masix2.m_i_fsize;
4929 break;
4930 default:
4931 frag = fsize = 0;
4932 }
4933
4934 if (inode->i_faddr || frag || fsize ||
4935 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
4936 mark_inode_bad(ctx, ino);
4937 if (inode->i_flags & EXT2_IMAGIC_FL) {
4938 if (imagic_fs) {
4939 if (!ctx->inode_imagic_map)
4940 alloc_imagic_map(ctx);
4941 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
4942 ino);
4943 } else {
4944 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
4945 inode->i_flags &= ~EXT2_IMAGIC_FL;
4946 e2fsck_write_inode(ctx, ino,
4947 inode, "pass1");
4948 }
4949 }
4950 }
4951
4952 check_inode_extra_space(ctx, &pctx);
4953
4954 if (LINUX_S_ISDIR(inode->i_mode)) {
4955 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
4956 e2fsck_add_dir_info(ctx, ino, 0);
4957 ctx->fs_directory_count++;
4958 } else if (LINUX_S_ISREG (inode->i_mode)) {
4959 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
4960 ctx->fs_regular_count++;
4961 } else if (LINUX_S_ISCHR (inode->i_mode) &&
4962 e2fsck_pass1_check_device_inode(fs, inode)) {
4963 check_immutable(ctx, &pctx);
4964 check_size(ctx, &pctx);
4965 ctx->fs_chardev_count++;
4966 } else if (LINUX_S_ISBLK (inode->i_mode) &&
4967 e2fsck_pass1_check_device_inode(fs, inode)) {
4968 check_immutable(ctx, &pctx);
4969 check_size(ctx, &pctx);
4970 ctx->fs_blockdev_count++;
4971 } else if (LINUX_S_ISLNK (inode->i_mode) &&
4972 e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
4973 check_immutable(ctx, &pctx);
4974 ctx->fs_symlinks_count++;
4975 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
4976 ctx->fs_fast_symlinks_count++;
4977 check_blocks(ctx, &pctx, block_buf);
4978 continue;
4979 }
4980 }
4981 else if (LINUX_S_ISFIFO (inode->i_mode) &&
4982 e2fsck_pass1_check_device_inode(fs, inode)) {
4983 check_immutable(ctx, &pctx);
4984 check_size(ctx, &pctx);
4985 ctx->fs_fifo_count++;
4986 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
4987 e2fsck_pass1_check_device_inode(fs, inode)) {
4988 check_immutable(ctx, &pctx);
4989 check_size(ctx, &pctx);
4990 ctx->fs_sockets_count++;
4991 } else
4992 mark_inode_bad(ctx, ino);
4993 if (inode->i_block[EXT2_IND_BLOCK])
4994 ctx->fs_ind_count++;
4995 if (inode->i_block[EXT2_DIND_BLOCK])
4996 ctx->fs_dind_count++;
4997 if (inode->i_block[EXT2_TIND_BLOCK])
4998 ctx->fs_tind_count++;
4999 if (inode->i_block[EXT2_IND_BLOCK] ||
5000 inode->i_block[EXT2_DIND_BLOCK] ||
5001 inode->i_block[EXT2_TIND_BLOCK] ||
5002 inode->i_file_acl) {
5003 inodes_to_process[process_inode_count].ino = ino;
5004 inodes_to_process[process_inode_count].inode = *inode;
5005 process_inode_count++;
5006 } else
5007 check_blocks(ctx, &pctx, block_buf);
5008
5009 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5010 return;
5011
5012 if (process_inode_count >= ctx->process_inode_size) {
5013 process_inodes(ctx, block_buf);
5014
5015 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5016 return;
5017 }
5018 }
5019 process_inodes(ctx, block_buf);
5020 ext2fs_close_inode_scan(scan);
5021 ehandler_operation(0);
5022
5023 /*
5024 * If any extended attribute blocks' reference counts need to
5025 * be adjusted, either up (ctx->refcount_extra), or down
5026 * (ctx->refcount), then fix them.
5027 */
5028 if (ctx->refcount) {
5029 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
5030 ea_refcount_free(ctx->refcount);
5031 ctx->refcount = 0;
5032 }
5033 if (ctx->refcount_extra) {
5034 adjust_extattr_refcount(ctx, ctx->refcount_extra,
5035 block_buf, +1);
5036 ea_refcount_free(ctx->refcount_extra);
5037 ctx->refcount_extra = 0;
5038 }
5039
5040 if (ctx->invalid_bitmaps)
5041 handle_fs_bad_blocks(ctx);
5042
5043 /* We don't need the block_ea_map any more */
Rob Landleye7c43b62006-03-01 16:39:45 +00005044 ext2fs_free_block_bitmap(ctx->block_ea_map);
5045 ctx->block_ea_map = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005046
5047 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
5048 ext2fs_block_bitmap save_bmap;
5049
5050 save_bmap = fs->block_map;
5051 fs->block_map = ctx->block_found_map;
5052 clear_problem_context(&pctx);
5053 pctx.errcode = ext2fs_create_resize_inode(fs);
5054 if (pctx.errcode) {
5055 fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
5056 /* Should never get here */
5057 ctx->flags |= E2F_FLAG_ABORT;
5058 return;
5059 }
Mike Frysinger874af852006-03-08 07:03:27 +00005060 e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
5061 "recreate inode");
5062 inode->i_mtime = time(0);
5063 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
5064 "recreate inode");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005065 fs->block_map = save_bmap;
5066 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
5067 }
5068
5069 if (ctx->flags & E2F_FLAG_RESTART) {
5070 /*
5071 * Only the master copy of the superblock and block
5072 * group descriptors are going to be written during a
5073 * restart, so set the superblock to be used to be the
5074 * master superblock.
5075 */
5076 ctx->use_superblock = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00005077 unwind_pass1();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005078 goto endit;
5079 }
5080
5081 if (ctx->block_dup_map) {
5082 if (ctx->options & E2F_OPT_PREEN) {
5083 clear_problem_context(&pctx);
5084 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
5085 }
5086 e2fsck_pass1_dupblocks(ctx, block_buf);
5087 }
5088 ext2fs_free_mem(&inodes_to_process);
5089endit:
5090 e2fsck_use_inode_shortcuts(ctx, 0);
5091
5092 ext2fs_free_mem(&block_buf);
5093 ext2fs_free_mem(&inode);
5094
5095#ifdef RESOURCE_TRACK
5096 if (ctx->options & E2F_OPT_TIME2) {
5097 e2fsck_clear_progbar(ctx);
5098 print_resource_track(_("Pass 1"), &rtrack);
5099 }
5100#endif
5101}
5102
5103/*
5104 * When the inode_scan routines call this callback at the end of the
5105 * glock group, call process_inodes.
5106 */
5107static errcode_t scan_callback(ext2_filsys fs,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005108 ext2_inode_scan scan FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005109 dgrp_t group, void * priv_data)
5110{
5111 struct scan_callback_struct *scan_struct;
5112 e2fsck_t ctx;
5113
5114 scan_struct = (struct scan_callback_struct *) priv_data;
5115 ctx = scan_struct->ctx;
5116
5117 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
5118
5119 if (ctx->progress)
5120 if ((ctx->progress)(ctx, 1, group+1,
5121 ctx->fs->group_desc_count))
5122 return EXT2_ET_CANCEL_REQUESTED;
5123
5124 return 0;
5125}
5126
5127/*
5128 * Process the inodes in the "inodes to process" list.
5129 */
5130static void process_inodes(e2fsck_t ctx, char *block_buf)
5131{
5132 int i;
5133 struct ext2_inode *old_stashed_inode;
5134 ext2_ino_t old_stashed_ino;
5135 const char *old_operation;
5136 char buf[80];
5137 struct problem_context pctx;
5138
5139#if 0
5140 printf("begin process_inodes: ");
5141#endif
5142 if (process_inode_count == 0)
5143 return;
5144 old_operation = ehandler_operation(0);
5145 old_stashed_inode = ctx->stashed_inode;
5146 old_stashed_ino = ctx->stashed_ino;
5147 qsort(inodes_to_process, process_inode_count,
5148 sizeof(struct process_inode_block), process_inode_cmp);
5149 clear_problem_context(&pctx);
5150 for (i=0; i < process_inode_count; i++) {
5151 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
5152 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
5153
5154#if 0
5155 printf("%u ", pctx.ino);
5156#endif
5157 sprintf(buf, _("reading indirect blocks of inode %u"),
5158 pctx.ino);
5159 ehandler_operation(buf);
5160 check_blocks(ctx, &pctx, block_buf);
5161 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5162 break;
5163 }
5164 ctx->stashed_inode = old_stashed_inode;
5165 ctx->stashed_ino = old_stashed_ino;
5166 process_inode_count = 0;
5167#if 0
5168 printf("end process inodes\n");
5169#endif
5170 ehandler_operation(old_operation);
5171}
5172
5173static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
5174{
5175 const struct process_inode_block *ib_a =
5176 (const struct process_inode_block *) a;
5177 const struct process_inode_block *ib_b =
5178 (const struct process_inode_block *) b;
5179 int ret;
5180
5181 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
5182 ib_b->inode.i_block[EXT2_IND_BLOCK]);
5183 if (ret == 0)
5184 ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
5185 return ret;
5186}
5187
5188/*
5189 * Mark an inode as being bad in some what
5190 */
5191static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
5192{
5193 struct problem_context pctx;
5194
5195 if (!ctx->inode_bad_map) {
5196 clear_problem_context(&pctx);
5197
5198 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5199 _("bad inode map"), &ctx->inode_bad_map);
5200 if (pctx.errcode) {
5201 pctx.num = 3;
5202 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5203 /* Should never get here */
5204 ctx->flags |= E2F_FLAG_ABORT;
5205 return;
5206 }
5207 }
5208 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
5209}
5210
5211
5212/*
5213 * This procedure will allocate the inode "bb" (badblock) map table
5214 */
5215static void alloc_bb_map(e2fsck_t ctx)
5216{
5217 struct problem_context pctx;
5218
5219 clear_problem_context(&pctx);
5220 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5221 _("inode in bad block map"),
5222 &ctx->inode_bb_map);
5223 if (pctx.errcode) {
5224 pctx.num = 4;
5225 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5226 /* Should never get here */
5227 ctx->flags |= E2F_FLAG_ABORT;
5228 return;
5229 }
5230}
5231
5232/*
5233 * This procedure will allocate the inode imagic table
5234 */
5235static void alloc_imagic_map(e2fsck_t ctx)
5236{
5237 struct problem_context pctx;
5238
5239 clear_problem_context(&pctx);
5240 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5241 _("imagic inode map"),
5242 &ctx->inode_imagic_map);
5243 if (pctx.errcode) {
5244 pctx.num = 5;
5245 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5246 /* Should never get here */
5247 ctx->flags |= E2F_FLAG_ABORT;
5248 return;
5249 }
5250}
5251
5252/*
5253 * Marks a block as in use, setting the dup_map if it's been set
5254 * already. Called by process_block and process_bad_block.
5255 *
5256 * WARNING: Assumes checks have already been done to make sure block
5257 * is valid. This is true in both process_block and process_bad_block.
5258 */
5259static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
5260{
5261 struct problem_context pctx;
5262
5263 clear_problem_context(&pctx);
5264
5265 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
5266 if (!ctx->block_dup_map) {
5267 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
5268 _("multiply claimed block map"),
5269 &ctx->block_dup_map);
5270 if (pctx.errcode) {
5271 pctx.num = 3;
5272 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
5273 &pctx);
5274 /* Should never get here */
5275 ctx->flags |= E2F_FLAG_ABORT;
5276 return;
5277 }
5278 }
5279 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
5280 } else {
5281 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
5282 }
5283}
5284
5285/*
5286 * Adjust the extended attribute block's reference counts at the end
5287 * of pass 1, either by subtracting out references for EA blocks that
5288 * are still referenced in ctx->refcount, or by adding references for
5289 * EA blocks that had extra references as accounted for in
5290 * ctx->refcount_extra.
5291 */
5292static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
5293 char *block_buf, int adjust_sign)
5294{
5295 struct ext2_ext_attr_header *header;
5296 struct problem_context pctx;
5297 ext2_filsys fs = ctx->fs;
5298 blk_t blk;
5299 __u32 should_be;
5300 int count;
5301
5302 clear_problem_context(&pctx);
5303
5304 ea_refcount_intr_begin(refcount);
5305 while (1) {
5306 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
5307 break;
5308 pctx.blk = blk;
5309 pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5310 if (pctx.errcode) {
5311 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
5312 return;
5313 }
5314 header = (struct ext2_ext_attr_header *) block_buf;
5315 pctx.blkcount = header->h_refcount;
5316 should_be = header->h_refcount + adjust_sign * count;
5317 pctx.num = should_be;
5318 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
5319 header->h_refcount = should_be;
5320 pctx.errcode = ext2fs_write_ext_attr(fs, blk,
5321 block_buf);
5322 if (pctx.errcode) {
5323 fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
5324 continue;
5325 }
5326 }
5327 }
5328}
5329
5330/*
5331 * Handle processing the extended attribute blocks
5332 */
5333static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
5334 char *block_buf)
5335{
5336 ext2_filsys fs = ctx->fs;
5337 ext2_ino_t ino = pctx->ino;
5338 struct ext2_inode *inode = pctx->inode;
5339 blk_t blk;
5340 char * end;
5341 struct ext2_ext_attr_header *header;
5342 struct ext2_ext_attr_entry *entry;
5343 int count;
5344 region_t region;
5345
5346 blk = inode->i_file_acl;
5347 if (blk == 0)
5348 return 0;
5349
5350 /*
5351 * If the Extended attribute flag isn't set, then a non-zero
5352 * file acl means that the inode is corrupted.
5353 *
5354 * Or if the extended attribute block is an invalid block,
5355 * then the inode is also corrupted.
5356 */
5357 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
5358 (blk < fs->super->s_first_data_block) ||
5359 (blk >= fs->super->s_blocks_count)) {
5360 mark_inode_bad(ctx, ino);
5361 return 0;
5362 }
5363
5364 /* If ea bitmap hasn't been allocated, create it */
5365 if (!ctx->block_ea_map) {
5366 pctx->errcode = ext2fs_allocate_block_bitmap(fs,
5367 _("ext attr block map"),
5368 &ctx->block_ea_map);
5369 if (pctx->errcode) {
5370 pctx->num = 2;
5371 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
5372 ctx->flags |= E2F_FLAG_ABORT;
5373 return 0;
5374 }
5375 }
5376
5377 /* Create the EA refcount structure if necessary */
5378 if (!ctx->refcount) {
5379 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
5380 if (pctx->errcode) {
5381 pctx->num = 1;
5382 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5383 ctx->flags |= E2F_FLAG_ABORT;
5384 return 0;
5385 }
5386 }
5387
5388#if 0
5389 /* Debugging text */
5390 printf("Inode %u has EA block %u\n", ino, blk);
5391#endif
5392
5393 /* Have we seen this EA block before? */
5394 if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
5395 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
5396 return 1;
5397 /* Ooops, this EA was referenced more than it stated */
5398 if (!ctx->refcount_extra) {
5399 pctx->errcode = ea_refcount_create(0,
5400 &ctx->refcount_extra);
5401 if (pctx->errcode) {
5402 pctx->num = 2;
5403 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5404 ctx->flags |= E2F_FLAG_ABORT;
5405 return 0;
5406 }
5407 }
5408 ea_refcount_increment(ctx->refcount_extra, blk, 0);
5409 return 1;
5410 }
5411
5412 /*
5413 * OK, we haven't seen this EA block yet. So we need to
5414 * validate it
5415 */
5416 pctx->blk = blk;
5417 pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5418 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
5419 goto clear_extattr;
5420 header = (struct ext2_ext_attr_header *) block_buf;
5421 pctx->blk = inode->i_file_acl;
5422 if (((ctx->ext_attr_ver == 1) &&
5423 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
5424 ((ctx->ext_attr_ver == 2) &&
5425 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
5426 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
5427 goto clear_extattr;
5428 }
5429
5430 if (header->h_blocks != 1) {
5431 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
5432 goto clear_extattr;
5433 }
5434
5435 region = region_create(0, fs->blocksize);
5436 if (!region) {
5437 fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
5438 ctx->flags |= E2F_FLAG_ABORT;
5439 return 0;
5440 }
5441 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
5442 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5443 goto clear_extattr;
5444 }
5445
5446 entry = (struct ext2_ext_attr_entry *)(header+1);
5447 end = block_buf + fs->blocksize;
5448 while ((char *)entry < end && *(__u32 *)entry) {
5449 if (region_allocate(region, (char *)entry - (char *)header,
5450 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
5451 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5452 goto clear_extattr;
5453 }
5454 if ((ctx->ext_attr_ver == 1 &&
5455 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
5456 (ctx->ext_attr_ver == 2 &&
5457 entry->e_name_index == 0)) {
5458 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
5459 goto clear_extattr;
5460 }
5461 if (entry->e_value_block != 0) {
5462 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
5463 goto clear_extattr;
5464 }
5465 if (entry->e_value_size &&
5466 region_allocate(region, entry->e_value_offs,
5467 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
5468 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5469 goto clear_extattr;
5470 }
5471 entry = EXT2_EXT_ATTR_NEXT(entry);
5472 }
5473 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
5474 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5475 goto clear_extattr;
5476 }
5477 region_free(region);
5478
5479 count = header->h_refcount - 1;
5480 if (count)
5481 ea_refcount_store(ctx->refcount, blk, count);
5482 mark_block_used(ctx, blk);
5483 ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
5484
5485 return 1;
5486
5487clear_extattr:
5488 inode->i_file_acl = 0;
5489 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
5490 return 0;
5491}
5492
5493/* Returns 1 if bad htree, 0 if OK */
5494static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005495 ext2_ino_t ino FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005496 struct ext2_inode *inode,
5497 char *block_buf)
5498{
5499 struct ext2_dx_root_info *root;
5500 ext2_filsys fs = ctx->fs;
5501 errcode_t retval;
5502 blk_t blk;
5503
5504 if ((!LINUX_S_ISDIR(inode->i_mode) &&
5505 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
5506 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
5507 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
5508 return 1;
5509
5510 blk = inode->i_block[0];
5511 if (((blk == 0) ||
5512 (blk < fs->super->s_first_data_block) ||
5513 (blk >= fs->super->s_blocks_count)) &&
5514 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5515 return 1;
5516
5517 retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
5518 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5519 return 1;
5520
5521 /* XXX should check that beginning matches a directory */
5522 root = (struct ext2_dx_root_info *) (block_buf + 24);
5523
5524 if ((root->reserved_zero || root->info_length < 8) &&
5525 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5526 return 1;
5527
5528 pctx->num = root->hash_version;
5529 if ((root->hash_version != EXT2_HASH_LEGACY) &&
5530 (root->hash_version != EXT2_HASH_HALF_MD4) &&
5531 (root->hash_version != EXT2_HASH_TEA) &&
5532 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
5533 return 1;
5534
5535 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
5536 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
5537 return 1;
5538
5539 pctx->num = root->indirect_levels;
5540 if ((root->indirect_levels > 1) &&
5541 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
5542 return 1;
5543
5544 return 0;
5545}
5546
5547/*
5548 * This subroutine is called on each inode to account for all of the
5549 * blocks used by that inode.
5550 */
5551static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
5552 char *block_buf)
5553{
5554 ext2_filsys fs = ctx->fs;
5555 struct process_block_struct_1 pb;
5556 ext2_ino_t ino = pctx->ino;
5557 struct ext2_inode *inode = pctx->inode;
5558 int bad_size = 0;
5559 int dirty_inode = 0;
5560 __u64 size;
5561
5562 pb.ino = ino;
5563 pb.num_blocks = 0;
5564 pb.last_block = -1;
5565 pb.num_illegal_blocks = 0;
5566 pb.suppress = 0; pb.clear = 0;
5567 pb.fragmented = 0;
5568 pb.compressed = 0;
5569 pb.previous_block = 0;
5570 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
5571 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
5572 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
5573 pb.inode = inode;
5574 pb.pctx = pctx;
5575 pb.ctx = ctx;
5576 pctx->ino = ino;
5577 pctx->errcode = 0;
5578
5579 if (inode->i_flags & EXT2_COMPRBLK_FL) {
5580 if (fs->super->s_feature_incompat &
5581 EXT2_FEATURE_INCOMPAT_COMPRESSION)
5582 pb.compressed = 1;
5583 else {
5584 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
5585 inode->i_flags &= ~EXT2_COMPRBLK_FL;
5586 dirty_inode++;
5587 }
5588 }
5589 }
5590
5591 if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
5592 pb.num_blocks++;
5593
5594 if (ext2fs_inode_has_valid_blocks(inode))
5595 pctx->errcode = ext2fs_block_iterate2(fs, ino,
5596 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
5597 block_buf, process_block, &pb);
5598 end_problem_latch(ctx, PR_LATCH_BLOCK);
5599 end_problem_latch(ctx, PR_LATCH_TOOBIG);
5600 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5601 goto out;
5602 if (pctx->errcode)
5603 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
5604
5605 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
5606 ctx->fs_fragmented++;
5607
5608 if (pb.clear) {
5609 inode->i_links_count = 0;
5610 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5611 inode->i_dtime = time(0);
5612 dirty_inode++;
5613 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5614 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5615 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5616 /*
5617 * The inode was probably partially accounted for
5618 * before processing was aborted, so we need to
5619 * restart the pass 1 scan.
5620 */
5621 ctx->flags |= E2F_FLAG_RESTART;
5622 goto out;
5623 }
5624
5625 if (inode->i_flags & EXT2_INDEX_FL) {
5626 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
5627 inode->i_flags &= ~EXT2_INDEX_FL;
5628 dirty_inode++;
5629 } else {
5630#ifdef ENABLE_HTREE
5631 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
5632#endif
5633 }
5634 }
5635 if (ctx->dirs_to_hash && pb.is_dir &&
5636 !(inode->i_flags & EXT2_INDEX_FL) &&
5637 ((inode->i_size / fs->blocksize) >= 3))
5638 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
5639
5640 if (!pb.num_blocks && pb.is_dir) {
5641 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
5642 inode->i_links_count = 0;
5643 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5644 inode->i_dtime = time(0);
5645 dirty_inode++;
5646 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5647 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5648 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5649 ctx->fs_directory_count--;
5650 goto out;
5651 }
5652 }
5653
5654 pb.num_blocks *= (fs->blocksize / 512);
5655#if 0
5656 printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
5657 ino, inode->i_size, pb.last_block, inode->i_blocks,
5658 pb.num_blocks);
5659#endif
5660 if (pb.is_dir) {
5661 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
5662 if (nblock > (pb.last_block + 1))
5663 bad_size = 1;
5664 else if (nblock < (pb.last_block + 1)) {
5665 if (((pb.last_block + 1) - nblock) >
5666 fs->super->s_prealloc_dir_blocks)
5667 bad_size = 2;
5668 }
5669 } else {
5670 size = EXT2_I_SIZE(inode);
5671 if ((pb.last_block >= 0) &&
5672 (size < (__u64) pb.last_block * fs->blocksize))
5673 bad_size = 3;
5674 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
5675 bad_size = 4;
5676 }
5677 /* i_size for symlinks is checked elsewhere */
5678 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
5679 pctx->num = (pb.last_block+1) * fs->blocksize;
5680 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
5681 inode->i_size = pctx->num;
5682 if (!LINUX_S_ISDIR(inode->i_mode))
5683 inode->i_size_high = pctx->num >> 32;
5684 dirty_inode++;
5685 }
5686 pctx->num = 0;
5687 }
5688 if (LINUX_S_ISREG(inode->i_mode) &&
5689 (inode->i_size_high || inode->i_size & 0x80000000UL))
5690 ctx->large_files++;
5691 if (pb.num_blocks != inode->i_blocks) {
5692 pctx->num = pb.num_blocks;
5693 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
5694 inode->i_blocks = pb.num_blocks;
5695 dirty_inode++;
5696 }
5697 pctx->num = 0;
5698 }
5699out:
5700 if (dirty_inode)
5701 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
5702}
5703
5704#if 0
5705/*
5706 * Helper function called by process block when an illegal block is
5707 * found. It returns a description about why the block is illegal
5708 */
5709static char *describe_illegal_block(ext2_filsys fs, blk_t block)
5710{
5711 blk_t super;
5712 int i;
5713 static char problem[80];
5714
5715 super = fs->super->s_first_data_block;
5716 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
5717 if (block < super) {
5718 sprintf(problem, "< FIRSTBLOCK (%u)", super);
5719 return(problem);
5720 } else if (block >= fs->super->s_blocks_count) {
5721 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
5722 return(problem);
5723 }
5724 for (i = 0; i < fs->group_desc_count; i++) {
5725 if (block == super) {
5726 sprintf(problem, "is the superblock in group %d", i);
5727 break;
5728 }
5729 if (block > super &&
5730 block <= (super + fs->desc_blocks)) {
5731 sprintf(problem, "is in the group descriptors "
5732 "of group %d", i);
5733 break;
5734 }
5735 if (block == fs->group_desc[i].bg_block_bitmap) {
5736 sprintf(problem, "is the block bitmap of group %d", i);
5737 break;
5738 }
5739 if (block == fs->group_desc[i].bg_inode_bitmap) {
5740 sprintf(problem, "is the inode bitmap of group %d", i);
5741 break;
5742 }
5743 if (block >= fs->group_desc[i].bg_inode_table &&
5744 (block < fs->group_desc[i].bg_inode_table
5745 + fs->inode_blocks_per_group)) {
5746 sprintf(problem, "is in the inode table of group %d",
5747 i);
5748 break;
5749 }
5750 super += fs->super->s_blocks_per_group;
5751 }
5752 return(problem);
5753}
5754#endif
5755
5756/*
5757 * This is a helper function for check_blocks().
5758 */
5759static int process_block(ext2_filsys fs,
5760 blk_t *block_nr,
5761 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005762 blk_t ref_block FSCK_ATTR((unused)),
5763 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005764 void *priv_data)
5765{
5766 struct process_block_struct_1 *p;
5767 struct problem_context *pctx;
5768 blk_t blk = *block_nr;
5769 int ret_code = 0;
5770 int problem = 0;
5771 e2fsck_t ctx;
5772
5773 p = (struct process_block_struct_1 *) priv_data;
5774 pctx = p->pctx;
5775 ctx = p->ctx;
5776
5777 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
5778 /* todo: Check that the comprblk_fl is high, that the
5779 blkaddr pattern looks right (all non-holes up to
5780 first EXT2FS_COMPRESSED_BLKADDR, then all
5781 EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
5782 that the feature_incompat bit is high, and that the
5783 inode is a regular file. If we're doing a "full
5784 check" (a concept introduced to e2fsck by e2compr,
5785 meaning that we look at data blocks as well as
5786 metadata) then call some library routine that
5787 checks the compressed data. I'll have to think
5788 about this, because one particularly important
5789 problem to be able to fix is to recalculate the
5790 cluster size if necessary. I think that perhaps
5791 we'd better do most/all e2compr-specific checks
5792 separately, after the non-e2compr checks. If not
5793 doing a full check, it may be useful to test that
5794 the personality is linux; e.g. if it isn't then
5795 perhaps this really is just an illegal block. */
5796 return 0;
5797 }
5798
5799 if (blk == 0) {
5800 if (p->is_dir == 0) {
5801 /*
5802 * Should never happen, since only directories
5803 * get called with BLOCK_FLAG_HOLE
5804 */
5805#if DEBUG_E2FSCK
5806 printf("process_block() called with blk == 0, "
5807 "blockcnt=%d, inode %lu???\n",
5808 blockcnt, p->ino);
5809#endif
5810 return 0;
5811 }
5812 if (blockcnt < 0)
5813 return 0;
5814 if (blockcnt * fs->blocksize < p->inode->i_size) {
5815#if 0
5816 printf("Missing block (#%d) in directory inode %lu!\n",
5817 blockcnt, p->ino);
5818#endif
5819 goto mark_dir;
5820 }
5821 return 0;
5822 }
5823
5824#if 0
5825 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
5826 blockcnt);
5827#endif
5828
5829 /*
5830 * Simplistic fragmentation check. We merely require that the
5831 * file be contiguous. (Which can never be true for really
5832 * big files that are greater than a block group.)
5833 */
5834 if (!HOLE_BLKADDR(p->previous_block)) {
5835 if (p->previous_block+1 != blk)
5836 p->fragmented = 1;
5837 }
5838 p->previous_block = blk;
5839
5840 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
5841 problem = PR_1_TOOBIG_DIR;
5842 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
5843 problem = PR_1_TOOBIG_REG;
5844 if (!p->is_dir && !p->is_reg && blockcnt > 0)
5845 problem = PR_1_TOOBIG_SYMLINK;
5846
5847 if (blk < fs->super->s_first_data_block ||
5848 blk >= fs->super->s_blocks_count)
5849 problem = PR_1_ILLEGAL_BLOCK_NUM;
5850
5851 if (problem) {
5852 p->num_illegal_blocks++;
5853 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
5854 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
5855 p->clear = 1;
5856 return BLOCK_ABORT;
5857 }
5858 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
5859 p->suppress = 1;
5860 set_latch_flags(PR_LATCH_BLOCK,
5861 PRL_SUPPRESS, 0);
5862 }
5863 }
5864 pctx->blk = blk;
5865 pctx->blkcount = blockcnt;
5866 if (fix_problem(ctx, problem, pctx)) {
5867 blk = *block_nr = 0;
5868 ret_code = BLOCK_CHANGED;
5869 goto mark_dir;
5870 } else
5871 return 0;
5872 }
5873
5874 if (p->ino == EXT2_RESIZE_INO) {
5875 /*
5876 * The resize inode has already be sanity checked
5877 * during pass #0 (the superblock checks). All we
5878 * have to do is mark the double indirect block as
5879 * being in use; all of the other blocks are handled
5880 * by mark_table_blocks()).
5881 */
5882 if (blockcnt == BLOCK_COUNT_DIND)
5883 mark_block_used(ctx, blk);
5884 } else
5885 mark_block_used(ctx, blk);
5886 p->num_blocks++;
5887 if (blockcnt >= 0)
5888 p->last_block = blockcnt;
5889mark_dir:
5890 if (p->is_dir && (blockcnt >= 0)) {
5891 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
5892 blk, blockcnt);
5893 if (pctx->errcode) {
5894 pctx->blk = blk;
5895 pctx->num = blockcnt;
5896 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
5897 /* Should never get here */
5898 ctx->flags |= E2F_FLAG_ABORT;
5899 return BLOCK_ABORT;
5900 }
5901 }
5902 return ret_code;
5903}
5904
5905static int process_bad_block(ext2_filsys fs,
5906 blk_t *block_nr,
5907 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00005908 blk_t ref_block FSCK_ATTR((unused)),
5909 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005910 void *priv_data)
5911{
5912 struct process_block_struct_1 *p;
5913 blk_t blk = *block_nr;
5914 blk_t first_block;
5915 dgrp_t i;
5916 struct problem_context *pctx;
5917 e2fsck_t ctx;
5918
5919 /*
5920 * Note: This function processes blocks for the bad blocks
5921 * inode, which is never compressed. So we don't use HOLE_BLKADDR().
5922 */
5923
5924 if (!blk)
5925 return 0;
5926
5927 p = (struct process_block_struct_1 *) priv_data;
5928 ctx = p->ctx;
5929 pctx = p->pctx;
5930
5931 pctx->ino = EXT2_BAD_INO;
5932 pctx->blk = blk;
5933 pctx->blkcount = blockcnt;
5934
5935 if ((blk < fs->super->s_first_data_block) ||
5936 (blk >= fs->super->s_blocks_count)) {
5937 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
5938 *block_nr = 0;
5939 return BLOCK_CHANGED;
5940 } else
5941 return 0;
5942 }
5943
5944 if (blockcnt < 0) {
5945 if (ext2fs_test_block_bitmap(p->fs_meta_blocks, blk)) {
5946 p->bbcheck = 1;
5947 if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) {
5948 *block_nr = 0;
5949 return BLOCK_CHANGED;
5950 }
5951 } else if (ext2fs_test_block_bitmap(ctx->block_found_map,
5952 blk)) {
5953 p->bbcheck = 1;
5954 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
5955 pctx)) {
5956 *block_nr = 0;
5957 return BLOCK_CHANGED;
5958 }
5959 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5960 return BLOCK_ABORT;
5961 } else
5962 mark_block_used(ctx, blk);
5963 return 0;
5964 }
5965#if 0
5966 printf ("DEBUG: Marking %u as bad.\n", blk);
5967#endif
5968 ctx->fs_badblocks_count++;
5969 /*
5970 * If the block is not used, then mark it as used and return.
5971 * If it is already marked as found, this must mean that
5972 * there's an overlap between the filesystem table blocks
5973 * (bitmaps and inode table) and the bad block list.
5974 */
5975 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
5976 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
5977 return 0;
5978 }
5979 /*
5980 * Try to find the where the filesystem block was used...
5981 */
5982 first_block = fs->super->s_first_data_block;
5983
5984 for (i = 0; i < fs->group_desc_count; i++ ) {
5985 pctx->group = i;
5986 pctx->blk = blk;
5987 if (!ext2fs_bg_has_super(fs, i))
5988 goto skip_super;
5989 if (blk == first_block) {
5990 if (i == 0) {
5991 if (fix_problem(ctx,
5992 PR_1_BAD_PRIMARY_SUPERBLOCK,
5993 pctx)) {
5994 *block_nr = 0;
5995 return BLOCK_CHANGED;
5996 }
5997 return 0;
5998 }
5999 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
6000 return 0;
6001 }
6002 if ((blk > first_block) &&
6003 (blk <= first_block + fs->desc_blocks)) {
6004 if (i == 0) {
6005 pctx->blk = *block_nr;
6006 if (fix_problem(ctx,
6007 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
6008 *block_nr = 0;
6009 return BLOCK_CHANGED;
6010 }
6011 return 0;
6012 }
6013 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
6014 return 0;
6015 }
6016 skip_super:
6017 if (blk == fs->group_desc[i].bg_block_bitmap) {
6018 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
6019 ctx->invalid_block_bitmap_flag[i]++;
6020 ctx->invalid_bitmaps++;
6021 }
6022 return 0;
6023 }
6024 if (blk == fs->group_desc[i].bg_inode_bitmap) {
6025 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
6026 ctx->invalid_inode_bitmap_flag[i]++;
6027 ctx->invalid_bitmaps++;
6028 }
6029 return 0;
6030 }
6031 if ((blk >= fs->group_desc[i].bg_inode_table) &&
6032 (blk < (fs->group_desc[i].bg_inode_table +
6033 fs->inode_blocks_per_group))) {
6034 /*
6035 * If there are bad blocks in the inode table,
6036 * the inode scan code will try to do
6037 * something reasonable automatically.
6038 */
6039 return 0;
6040 }
6041 first_block += fs->super->s_blocks_per_group;
6042 }
6043 /*
6044 * If we've gotten to this point, then the only
6045 * possibility is that the bad block inode meta data
6046 * is using a bad block.
6047 */
6048 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
6049 (blk == p->inode->i_block[EXT2_DIND_BLOCK]) ||
6050 (blk == p->inode->i_block[EXT2_TIND_BLOCK])) {
6051 p->bbcheck = 1;
6052 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) {
6053 *block_nr = 0;
6054 return BLOCK_CHANGED;
6055 }
6056 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6057 return BLOCK_ABORT;
6058 return 0;
6059 }
6060
6061 pctx->group = -1;
6062
6063 /* Warn user that the block wasn't claimed */
6064 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
6065
6066 return 0;
6067}
6068
6069static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
6070 const char *name, int num, blk_t *new_block)
6071{
6072 ext2_filsys fs = ctx->fs;
6073 blk_t old_block = *new_block;
6074 int i;
6075 char *buf;
6076 struct problem_context pctx;
6077
6078 clear_problem_context(&pctx);
6079
6080 pctx.group = group;
6081 pctx.blk = old_block;
6082 pctx.str = name;
6083
6084 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
6085 first_block + fs->super->s_blocks_per_group,
6086 num, ctx->block_found_map, new_block);
6087 if (pctx.errcode) {
6088 pctx.num = num;
6089 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
6090 ext2fs_unmark_valid(fs);
6091 return;
6092 }
6093 pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf);
6094 if (pctx.errcode) {
6095 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
6096 ext2fs_unmark_valid(fs);
6097 return;
6098 }
6099 ext2fs_mark_super_dirty(fs);
6100 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
6101 pctx.blk2 = *new_block;
6102 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
6103 PR_1_RELOC_TO), &pctx);
6104 pctx.blk2 = 0;
6105 for (i = 0; i < num; i++) {
6106 pctx.blk = i;
6107 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
6108 if (old_block) {
6109 pctx.errcode = io_channel_read_blk(fs->io,
6110 old_block + i, 1, buf);
6111 if (pctx.errcode)
6112 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
6113 } else
6114 memset(buf, 0, fs->blocksize);
6115
6116 pctx.blk = (*new_block) + i;
6117 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
6118 1, buf);
6119 if (pctx.errcode)
6120 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
6121 }
6122 ext2fs_free_mem(&buf);
6123}
6124
6125/*
6126 * This routine gets called at the end of pass 1 if bad blocks are
6127 * detected in the superblock, group descriptors, inode_bitmaps, or
6128 * block bitmaps. At this point, all of the blocks have been mapped
6129 * out, so we can try to allocate new block(s) to replace the bad
6130 * blocks.
6131 */
6132static void handle_fs_bad_blocks(e2fsck_t ctx)
6133{
6134 ext2_filsys fs = ctx->fs;
6135 dgrp_t i;
6136 int first_block = fs->super->s_first_data_block;
6137
6138 for (i = 0; i < fs->group_desc_count; i++) {
6139 if (ctx->invalid_block_bitmap_flag[i]) {
6140 new_table_block(ctx, first_block, i, _("block bitmap"),
6141 1, &fs->group_desc[i].bg_block_bitmap);
6142 }
6143 if (ctx->invalid_inode_bitmap_flag[i]) {
6144 new_table_block(ctx, first_block, i, _("inode bitmap"),
6145 1, &fs->group_desc[i].bg_inode_bitmap);
6146 }
6147 if (ctx->invalid_inode_table_flag[i]) {
6148 new_table_block(ctx, first_block, i, _("inode table"),
6149 fs->inode_blocks_per_group,
6150 &fs->group_desc[i].bg_inode_table);
6151 ctx->flags |= E2F_FLAG_RESTART;
6152 }
6153 first_block += fs->super->s_blocks_per_group;
6154 }
6155 ctx->invalid_bitmaps = 0;
6156}
6157
6158/*
6159 * This routine marks all blocks which are used by the superblock,
6160 * group descriptors, inode bitmaps, and block bitmaps.
6161 */
6162static void mark_table_blocks(e2fsck_t ctx)
6163{
6164 ext2_filsys fs = ctx->fs;
6165 blk_t block, b;
6166 dgrp_t i;
6167 int j;
6168 struct problem_context pctx;
6169
6170 clear_problem_context(&pctx);
6171
6172 block = fs->super->s_first_data_block;
6173 for (i = 0; i < fs->group_desc_count; i++) {
6174 pctx.group = i;
6175
6176 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
6177
6178 /*
6179 * Mark the blocks used for the inode table
6180 */
6181 if (fs->group_desc[i].bg_inode_table) {
6182 for (j = 0, b = fs->group_desc[i].bg_inode_table;
6183 j < fs->inode_blocks_per_group;
6184 j++, b++) {
6185 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6186 b)) {
6187 pctx.blk = b;
6188 if (fix_problem(ctx,
6189 PR_1_ITABLE_CONFLICT, &pctx)) {
6190 ctx->invalid_inode_table_flag[i]++;
6191 ctx->invalid_bitmaps++;
6192 }
6193 } else {
6194 ext2fs_mark_block_bitmap(ctx->block_found_map,
6195 b);
6196 }
6197 }
6198 }
6199
6200 /*
6201 * Mark block used for the block bitmap
6202 */
6203 if (fs->group_desc[i].bg_block_bitmap) {
6204 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6205 fs->group_desc[i].bg_block_bitmap)) {
6206 pctx.blk = fs->group_desc[i].bg_block_bitmap;
6207 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
6208 ctx->invalid_block_bitmap_flag[i]++;
6209 ctx->invalid_bitmaps++;
6210 }
6211 } else {
6212 ext2fs_mark_block_bitmap(ctx->block_found_map,
6213 fs->group_desc[i].bg_block_bitmap);
6214 }
6215
6216 }
6217 /*
6218 * Mark block used for the inode bitmap
6219 */
6220 if (fs->group_desc[i].bg_inode_bitmap) {
6221 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6222 fs->group_desc[i].bg_inode_bitmap)) {
6223 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
6224 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
6225 ctx->invalid_inode_bitmap_flag[i]++;
6226 ctx->invalid_bitmaps++;
6227 }
6228 } else {
6229 ext2fs_mark_block_bitmap(ctx->block_found_map,
6230 fs->group_desc[i].bg_inode_bitmap);
6231 }
6232 }
6233 block += fs->super->s_blocks_per_group;
6234 }
6235}
6236
6237/*
6238 * Thes subroutines short circuits ext2fs_get_blocks and
6239 * ext2fs_check_directory; we use them since we already have the inode
6240 * structure, so there's no point in letting the ext2fs library read
6241 * the inode again.
6242 */
6243static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
6244 blk_t *blocks)
6245{
6246 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6247 int i;
6248
6249 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6250 return EXT2_ET_CALLBACK_NOTHANDLED;
6251
6252 for (i=0; i < EXT2_N_BLOCKS; i++)
6253 blocks[i] = ctx->stashed_inode->i_block[i];
6254 return 0;
6255}
6256
6257static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
6258 struct ext2_inode *inode)
6259{
6260 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6261
6262 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6263 return EXT2_ET_CALLBACK_NOTHANDLED;
6264 *inode = *ctx->stashed_inode;
6265 return 0;
6266}
6267
6268static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
6269 struct ext2_inode *inode)
6270{
6271 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6272
6273 if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
6274 *ctx->stashed_inode = *inode;
6275 return EXT2_ET_CALLBACK_NOTHANDLED;
6276}
6277
6278static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
6279{
6280 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6281
6282 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6283 return EXT2_ET_CALLBACK_NOTHANDLED;
6284
6285 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
6286 return EXT2_ET_NO_DIRECTORY;
6287 return 0;
6288}
6289
6290void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
6291{
6292 ext2_filsys fs = ctx->fs;
6293
6294 if (bool) {
6295 fs->get_blocks = pass1_get_blocks;
6296 fs->check_directory = pass1_check_directory;
6297 fs->read_inode = pass1_read_inode;
6298 fs->write_inode = pass1_write_inode;
6299 ctx->stashed_ino = 0;
6300 } else {
6301 fs->get_blocks = 0;
6302 fs->check_directory = 0;
6303 fs->read_inode = 0;
6304 fs->write_inode = 0;
6305 }
6306}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006307
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006308/*
6309 * pass1b.c --- Pass #1b of e2fsck
6310 *
6311 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
6312 * only invoked if pass 1 discovered blocks which are in use by more
6313 * than one inode.
6314 *
6315 * Pass1B scans the data blocks of all the inodes again, generating a
6316 * complete list of duplicate blocks and which inodes have claimed
6317 * them.
6318 *
6319 * Pass1C does a tree-traversal of the filesystem, to determine the
6320 * parent directories of these inodes. This step is necessary so that
6321 * e2fsck can print out the pathnames of affected inodes.
6322 *
6323 * Pass1D is a reconciliation pass. For each inode with duplicate
6324 * blocks, the user is prompted if s/he would like to clone the file
6325 * (so that the file gets a fresh copy of the duplicated blocks) or
6326 * simply to delete the file.
6327 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006328 */
6329
6330
6331/* Needed for architectures where sizeof(int) != sizeof(void *) */
6332#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
6333#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
6334
6335/* Define an extension to the ext2 library's block count information */
6336#define BLOCK_COUNT_EXTATTR (-5)
6337
6338struct block_el {
6339 blk_t block;
6340 struct block_el *next;
6341};
6342
6343struct inode_el {
6344 ext2_ino_t inode;
6345 struct inode_el *next;
6346};
6347
6348struct dup_block {
6349 int num_bad;
6350 struct inode_el *inode_list;
6351};
6352
6353/*
6354 * This structure stores information about a particular inode which
6355 * is sharing blocks with other inodes. This information is collected
6356 * to display to the user, so that the user knows what files he or she
6357 * is dealing with, when trying to decide how to resolve the conflict
6358 * of multiply-claimed blocks.
6359 */
6360struct dup_inode {
6361 ext2_ino_t dir;
6362 int num_dupblocks;
6363 struct ext2_inode inode;
6364 struct block_el *block_list;
6365};
6366
6367static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
6368 e2_blkcnt_t blockcnt, blk_t ref_blk,
6369 int ref_offset, void *priv_data);
6370static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
6371 struct dup_inode *dp, char *block_buf);
6372static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
6373 struct dup_inode *dp, char* block_buf);
6374static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
6375
6376static void pass1b(e2fsck_t ctx, char *block_buf);
6377static void pass1c(e2fsck_t ctx, char *block_buf);
6378static void pass1d(e2fsck_t ctx, char *block_buf);
6379
6380static int dup_inode_count = 0;
6381
6382static dict_t blk_dict, ino_dict;
6383
6384static ext2fs_inode_bitmap inode_dup_map;
6385
6386static int dict_int_cmp(const void *a, const void *b)
6387{
6388 intptr_t ia, ib;
6389
6390 ia = (intptr_t)a;
6391 ib = (intptr_t)b;
6392
6393 return (ia-ib);
6394}
6395
6396/*
6397 * Add a duplicate block record
6398 */
6399static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
6400 struct ext2_inode *inode)
6401{
6402 dnode_t *n;
6403 struct dup_block *db;
6404 struct dup_inode *di;
6405 struct block_el *blk_el;
6406 struct inode_el *ino_el;
6407
6408 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
6409 if (n)
6410 db = (struct dup_block *) dnode_get(n);
6411 else {
6412 db = (struct dup_block *) e2fsck_allocate_memory(ctx,
6413 sizeof(struct dup_block), "duplicate block header");
6414 db->num_bad = 0;
6415 db->inode_list = 0;
6416 dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
6417 }
6418 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
6419 sizeof(struct inode_el), "inode element");
6420 ino_el->inode = ino;
6421 ino_el->next = db->inode_list;
6422 db->inode_list = ino_el;
6423 db->num_bad++;
6424
6425 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
6426 if (n)
6427 di = (struct dup_inode *) dnode_get(n);
6428 else {
6429 di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
6430 sizeof(struct dup_inode), "duplicate inode header");
6431 di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0 ;
6432 di->num_dupblocks = 0;
6433 di->block_list = 0;
6434 di->inode = *inode;
6435 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
6436 }
6437 blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
6438 sizeof(struct block_el), "block element");
6439 blk_el->block = blk;
6440 blk_el->next = di->block_list;
6441 di->block_list = blk_el;
6442 di->num_dupblocks++;
6443}
6444
6445/*
6446 * Free a duplicate inode record
6447 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006448static void inode_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006449{
6450 struct dup_inode *di;
6451 struct block_el *p, *next;
6452
6453 di = (struct dup_inode *) dnode_get(node);
6454 for (p = di->block_list; p; p = next) {
6455 next = p->next;
6456 free(p);
6457 }
6458 free(node);
6459}
6460
6461/*
6462 * Free a duplicate block record
6463 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006464static void block_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006465{
6466 struct dup_block *db;
6467 struct inode_el *p, *next;
6468
6469 db = (struct dup_block *) dnode_get(node);
6470 for (p = db->inode_list; p; p = next) {
6471 next = p->next;
6472 free(p);
6473 }
6474 free(node);
6475}
6476
6477
6478/*
6479 * Main procedure for handling duplicate blocks
6480 */
6481void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
6482{
6483 ext2_filsys fs = ctx->fs;
6484 struct problem_context pctx;
6485
6486 clear_problem_context(&pctx);
6487
6488 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
6489 _("multiply claimed inode map"), &inode_dup_map);
6490 if (pctx.errcode) {
6491 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
6492 ctx->flags |= E2F_FLAG_ABORT;
6493 return;
6494 }
6495
6496 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
6497 dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006498 dict_set_allocator(&ino_dict, inode_dnode_free);
6499 dict_set_allocator(&blk_dict, block_dnode_free);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006500
6501 pass1b(ctx, block_buf);
6502 pass1c(ctx, block_buf);
6503 pass1d(ctx, block_buf);
6504
6505 /*
6506 * Time to free all of the accumulated data structures that we
6507 * don't need anymore.
6508 */
6509 dict_free_nodes(&ino_dict);
6510 dict_free_nodes(&blk_dict);
6511}
6512
6513/*
6514 * Scan the inodes looking for inodes that contain duplicate blocks.
6515 */
6516struct process_block_struct_1b {
6517 e2fsck_t ctx;
6518 ext2_ino_t ino;
6519 int dup_blocks;
6520 struct ext2_inode *inode;
6521 struct problem_context *pctx;
6522};
6523
6524static void pass1b(e2fsck_t ctx, char *block_buf)
6525{
6526 ext2_filsys fs = ctx->fs;
6527 ext2_ino_t ino;
6528 struct ext2_inode inode;
6529 ext2_inode_scan scan;
6530 struct process_block_struct_1b pb;
6531 struct problem_context pctx;
6532
6533 clear_problem_context(&pctx);
6534
6535 if (!(ctx->options & E2F_OPT_PREEN))
6536 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
6537 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
6538 &scan);
6539 if (pctx.errcode) {
6540 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6541 ctx->flags |= E2F_FLAG_ABORT;
6542 return;
6543 }
6544 ctx->stashed_inode = &inode;
6545 pb.ctx = ctx;
6546 pb.pctx = &pctx;
6547 pctx.str = "pass1b";
6548 while (1) {
6549 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
6550 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
6551 continue;
6552 if (pctx.errcode) {
6553 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6554 ctx->flags |= E2F_FLAG_ABORT;
6555 return;
6556 }
6557 if (!ino)
6558 break;
6559 pctx.ino = ctx->stashed_ino = ino;
6560 if ((ino != EXT2_BAD_INO) &&
6561 !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
6562 continue;
6563
6564 pb.ino = ino;
6565 pb.dup_blocks = 0;
6566 pb.inode = &inode;
6567
6568 if (ext2fs_inode_has_valid_blocks(&inode) ||
6569 (ino == EXT2_BAD_INO))
6570 pctx.errcode = ext2fs_block_iterate2(fs, ino,
6571 0, block_buf, process_pass1b_block, &pb);
6572 if (inode.i_file_acl)
6573 process_pass1b_block(fs, &inode.i_file_acl,
6574 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
6575 if (pb.dup_blocks) {
6576 end_problem_latch(ctx, PR_LATCH_DBLOCK);
6577 if (ino >= EXT2_FIRST_INODE(fs->super) ||
6578 ino == EXT2_ROOT_INO)
6579 dup_inode_count++;
6580 }
6581 if (pctx.errcode)
6582 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
6583 }
6584 ext2fs_close_inode_scan(scan);
6585 e2fsck_use_inode_shortcuts(ctx, 0);
6586}
6587
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006588static int process_pass1b_block(ext2_filsys fs FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006589 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006590 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
6591 blk_t ref_blk FSCK_ATTR((unused)),
6592 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006593 void *priv_data)
6594{
6595 struct process_block_struct_1b *p;
6596 e2fsck_t ctx;
6597
6598 if (HOLE_BLKADDR(*block_nr))
6599 return 0;
6600 p = (struct process_block_struct_1b *) priv_data;
6601 ctx = p->ctx;
6602
6603 if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
6604 return 0;
6605
6606 /* OK, this is a duplicate block */
6607 if (p->ino != EXT2_BAD_INO) {
6608 p->pctx->blk = *block_nr;
6609 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
6610 }
6611 p->dup_blocks++;
6612 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
6613
6614 add_dupe(ctx, p->ino, *block_nr, p->inode);
6615
6616 return 0;
6617}
6618
6619/*
6620 * Pass 1c: Scan directories for inodes with duplicate blocks. This
6621 * is used so that we can print pathnames when prompting the user for
6622 * what to do.
6623 */
6624struct search_dir_struct {
6625 int count;
6626 ext2_ino_t first_inode;
6627 ext2_ino_t max_inode;
6628};
6629
6630static int search_dirent_proc(ext2_ino_t dir, int entry,
6631 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006632 int offset FSCK_ATTR((unused)),
6633 int blocksize FSCK_ATTR((unused)),
6634 char *buf FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006635 void *priv_data)
6636{
6637 struct search_dir_struct *sd;
6638 struct dup_inode *p;
6639 dnode_t *n;
6640
6641 sd = (struct search_dir_struct *) priv_data;
6642
6643 if (dirent->inode > sd->max_inode)
6644 /* Should abort this inode, but not everything */
6645 return 0;
6646
6647 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
6648 !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
6649 return 0;
6650
6651 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
6652 if (!n)
6653 return 0;
6654 p = (struct dup_inode *) dnode_get(n);
6655 p->dir = dir;
6656 sd->count--;
6657
6658 return(sd->count ? 0 : DIRENT_ABORT);
6659}
6660
6661
6662static void pass1c(e2fsck_t ctx, char *block_buf)
6663{
6664 ext2_filsys fs = ctx->fs;
6665 struct search_dir_struct sd;
6666 struct problem_context pctx;
6667
6668 clear_problem_context(&pctx);
6669
6670 if (!(ctx->options & E2F_OPT_PREEN))
6671 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
6672
6673 /*
6674 * Search through all directories to translate inodes to names
6675 * (by searching for the containing directory for that inode.)
6676 */
6677 sd.count = dup_inode_count;
6678 sd.first_inode = EXT2_FIRST_INODE(fs->super);
6679 sd.max_inode = fs->super->s_inodes_count;
6680 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
6681 search_dirent_proc, &sd);
6682}
6683
6684static void pass1d(e2fsck_t ctx, char *block_buf)
6685{
6686 ext2_filsys fs = ctx->fs;
6687 struct dup_inode *p, *t;
6688 struct dup_block *q;
6689 ext2_ino_t *shared, ino;
6690 int shared_len;
6691 int i;
6692 int file_ok;
6693 int meta_data = 0;
6694 struct problem_context pctx;
6695 dnode_t *n, *m;
6696 struct block_el *s;
6697 struct inode_el *r;
6698
6699 clear_problem_context(&pctx);
6700
6701 if (!(ctx->options & E2F_OPT_PREEN))
6702 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
6703 e2fsck_read_bitmaps(ctx);
6704
6705 pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
6706 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
6707 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
6708 sizeof(ext2_ino_t) * dict_count(&ino_dict),
6709 "Shared inode list");
6710 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
6711 p = (struct dup_inode *) dnode_get(n);
6712 shared_len = 0;
6713 file_ok = 1;
6714 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
Mike Frysinger874af852006-03-08 07:03:27 +00006715 if (ino == EXT2_BAD_INO || ino == EXT2_RESIZE_INO)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006716 continue;
6717
6718 /*
6719 * Find all of the inodes which share blocks with this
6720 * one. First we find all of the duplicate blocks
6721 * belonging to this inode, and then search each block
6722 * get the list of inodes, and merge them together.
6723 */
6724 for (s = p->block_list; s; s = s->next) {
6725 m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
6726 if (!m)
6727 continue; /* Should never happen... */
6728 q = (struct dup_block *) dnode_get(m);
6729 if (q->num_bad > 1)
6730 file_ok = 0;
6731 if (check_if_fs_block(ctx, s->block)) {
6732 file_ok = 0;
6733 meta_data = 1;
6734 }
6735
6736 /*
6737 * Add all inodes used by this block to the
6738 * shared[] --- which is a unique list, so
6739 * if an inode is already in shared[], don't
6740 * add it again.
6741 */
6742 for (r = q->inode_list; r; r = r->next) {
6743 if (r->inode == ino)
6744 continue;
6745 for (i = 0; i < shared_len; i++)
6746 if (shared[i] == r->inode)
6747 break;
6748 if (i == shared_len) {
6749 shared[shared_len++] = r->inode;
6750 }
6751 }
6752 }
6753
6754 /*
6755 * Report the inode that we are working on
6756 */
6757 pctx.inode = &p->inode;
6758 pctx.ino = ino;
6759 pctx.dir = p->dir;
6760 pctx.blkcount = p->num_dupblocks;
6761 pctx.num = meta_data ? shared_len+1 : shared_len;
6762 fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
6763 pctx.blkcount = 0;
6764 pctx.num = 0;
6765
6766 if (meta_data)
6767 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
6768
6769 for (i = 0; i < shared_len; i++) {
6770 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
6771 if (!m)
6772 continue; /* should never happen */
6773 t = (struct dup_inode *) dnode_get(m);
6774 /*
6775 * Report the inode that we are sharing with
6776 */
6777 pctx.inode = &t->inode;
6778 pctx.ino = shared[i];
6779 pctx.dir = t->dir;
6780 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
6781 }
6782 if (file_ok) {
6783 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
6784 continue;
6785 }
6786 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
6787 pctx.errcode = clone_file(ctx, ino, p, block_buf);
6788 if (pctx.errcode)
6789 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
6790 else
6791 continue;
6792 }
6793 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
6794 delete_file(ctx, ino, p, block_buf);
6795 else
6796 ext2fs_unmark_valid(fs);
6797 }
6798 ext2fs_free_mem(&shared);
6799}
6800
6801/*
6802 * Drop the refcount on the dup_block structure, and clear the entry
6803 * in the block_dup_map if appropriate.
6804 */
6805static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
6806{
6807 p->num_bad--;
6808 if (p->num_bad <= 0 ||
6809 (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
6810 ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
6811}
6812
6813static int delete_file_block(ext2_filsys fs,
6814 blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006815 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
6816 blk_t ref_block FSCK_ATTR((unused)),
6817 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006818 void *priv_data)
6819{
6820 struct process_block_struct_1b *pb;
6821 struct dup_block *p;
6822 dnode_t *n;
6823 e2fsck_t ctx;
6824
6825 pb = (struct process_block_struct_1b *) priv_data;
6826 ctx = pb->ctx;
6827
6828 if (HOLE_BLKADDR(*block_nr))
6829 return 0;
6830
6831 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
6832 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
6833 if (n) {
6834 p = (struct dup_block *) dnode_get(n);
6835 decrement_badcount(ctx, *block_nr, p);
6836 } else
6837 com_err("delete_file_block", 0,
6838 _("internal error; can't find dup_blk for %d\n"),
6839 *block_nr);
6840 } else {
6841 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
6842 ext2fs_block_alloc_stats(fs, *block_nr, -1);
6843 }
6844
6845 return 0;
6846}
6847
6848static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
6849 struct dup_inode *dp, char* block_buf)
6850{
6851 ext2_filsys fs = ctx->fs;
6852 struct process_block_struct_1b pb;
6853 struct ext2_inode inode;
6854 struct problem_context pctx;
6855 unsigned int count;
6856
6857 clear_problem_context(&pctx);
6858 pctx.ino = pb.ino = ino;
6859 pb.dup_blocks = dp->num_dupblocks;
6860 pb.ctx = ctx;
6861 pctx.str = "delete_file";
6862
6863 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
6864 if (ext2fs_inode_has_valid_blocks(&inode))
6865 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
6866 delete_file_block, &pb);
6867 if (pctx.errcode)
6868 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
6869 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
6870 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
6871 if (ctx->inode_bad_map)
6872 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
6873 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
6874
6875 /* Inode may have changed by block_iterate, so reread it */
6876 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
6877 inode.i_links_count = 0;
6878 inode.i_dtime = time(0);
6879 if (inode.i_file_acl &&
6880 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
6881 count = 1;
6882 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
6883 block_buf, -1, &count);
6884 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
6885 pctx.errcode = 0;
6886 count = 1;
6887 }
6888 if (pctx.errcode) {
6889 pctx.blk = inode.i_file_acl;
6890 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
6891 }
6892 /*
6893 * If the count is zero, then arrange to have the
6894 * block deleted. If the block is in the block_dup_map,
6895 * also call delete_file_block since it will take care
6896 * of keeping the accounting straight.
6897 */
6898 if ((count == 0) ||
6899 ext2fs_test_block_bitmap(ctx->block_dup_map,
6900 inode.i_file_acl))
6901 delete_file_block(fs, &inode.i_file_acl,
6902 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
6903 }
6904 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
6905}
6906
6907struct clone_struct {
6908 errcode_t errcode;
6909 ext2_ino_t dir;
6910 char *buf;
6911 e2fsck_t ctx;
6912};
6913
6914static int clone_file_block(ext2_filsys fs,
6915 blk_t *block_nr,
6916 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00006917 blk_t ref_block FSCK_ATTR((unused)),
6918 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006919 void *priv_data)
6920{
6921 struct dup_block *p;
6922 blk_t new_block;
6923 errcode_t retval;
6924 struct clone_struct *cs = (struct clone_struct *) priv_data;
6925 dnode_t *n;
6926 e2fsck_t ctx;
6927
6928 ctx = cs->ctx;
6929
6930 if (HOLE_BLKADDR(*block_nr))
6931 return 0;
6932
6933 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
6934 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
6935 if (n) {
6936 p = (struct dup_block *) dnode_get(n);
6937 retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
6938 &new_block);
6939 if (retval) {
6940 cs->errcode = retval;
6941 return BLOCK_ABORT;
6942 }
6943 if (cs->dir && (blockcnt >= 0)) {
6944 retval = ext2fs_set_dir_block(fs->dblist,
6945 cs->dir, new_block, blockcnt);
6946 if (retval) {
6947 cs->errcode = retval;
6948 return BLOCK_ABORT;
6949 }
6950 }
6951#if 0
6952 printf("Cloning block %u to %u\n", *block_nr,
6953 new_block);
6954#endif
6955 retval = io_channel_read_blk(fs->io, *block_nr, 1,
6956 cs->buf);
6957 if (retval) {
6958 cs->errcode = retval;
6959 return BLOCK_ABORT;
6960 }
6961 retval = io_channel_write_blk(fs->io, new_block, 1,
6962 cs->buf);
6963 if (retval) {
6964 cs->errcode = retval;
6965 return BLOCK_ABORT;
6966 }
6967 decrement_badcount(ctx, *block_nr, p);
6968 *block_nr = new_block;
6969 ext2fs_mark_block_bitmap(ctx->block_found_map,
6970 new_block);
6971 ext2fs_mark_block_bitmap(fs->block_map, new_block);
6972 return BLOCK_CHANGED;
6973 } else
6974 com_err("clone_file_block", 0,
6975 _("internal error; can't find dup_blk for %d\n"),
6976 *block_nr);
6977 }
6978 return 0;
6979}
6980
6981static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
6982 struct dup_inode *dp, char* block_buf)
6983{
6984 ext2_filsys fs = ctx->fs;
6985 errcode_t retval;
6986 struct clone_struct cs;
6987 struct problem_context pctx;
6988 blk_t blk;
6989 dnode_t *n;
6990 struct inode_el *ino_el;
6991 struct dup_block *db;
6992 struct dup_inode *di;
6993
6994 clear_problem_context(&pctx);
6995 cs.errcode = 0;
6996 cs.dir = 0;
6997 cs.ctx = ctx;
6998 retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
6999 if (retval)
7000 return retval;
7001
7002 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
7003 cs.dir = ino;
7004
7005 pctx.ino = ino;
7006 pctx.str = "clone_file";
7007 if (ext2fs_inode_has_valid_blocks(&dp->inode))
7008 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
7009 clone_file_block, &cs);
7010 ext2fs_mark_bb_dirty(fs);
7011 if (pctx.errcode) {
7012 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
7013 retval = pctx.errcode;
7014 goto errout;
7015 }
7016 if (cs.errcode) {
7017 com_err("clone_file", cs.errcode,
7018 _("returned from clone_file_block"));
7019 retval = cs.errcode;
7020 goto errout;
7021 }
7022 /* The inode may have changed on disk, so we have to re-read it */
7023 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
7024 blk = dp->inode.i_file_acl;
7025 if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
7026 BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
7027 BLOCK_CHANGED)) {
7028 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
7029 /*
7030 * If we cloned the EA block, find all other inodes
7031 * which refered to that EA block, and modify
7032 * them to point to the new EA block.
7033 */
7034 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
7035 db = (struct dup_block *) dnode_get(n);
7036 for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
7037 if (ino_el->inode == ino)
7038 continue;
7039 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
7040 di = (struct dup_inode *) dnode_get(n);
7041 if (di->inode.i_file_acl == blk) {
7042 di->inode.i_file_acl = dp->inode.i_file_acl;
7043 e2fsck_write_inode(ctx, ino_el->inode,
7044 &di->inode, "clone file EA");
7045 decrement_badcount(ctx, blk, db);
7046 }
7047 }
7048 }
7049 retval = 0;
7050errout:
7051 ext2fs_free_mem(&cs.buf);
7052 return retval;
7053}
7054
7055/*
7056 * This routine returns 1 if a block overlaps with one of the superblocks,
7057 * group descriptors, inode bitmaps, or block bitmaps.
7058 */
7059static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
7060{
7061 ext2_filsys fs = ctx->fs;
7062 blk_t block;
7063 dgrp_t i;
7064
7065 block = fs->super->s_first_data_block;
7066 for (i = 0; i < fs->group_desc_count; i++) {
7067
7068 /* Check superblocks/block group descriptros */
7069 if (ext2fs_bg_has_super(fs, i)) {
7070 if (test_block >= block &&
7071 (test_block <= block + fs->desc_blocks))
7072 return 1;
7073 }
7074
7075 /* Check the inode table */
7076 if ((fs->group_desc[i].bg_inode_table) &&
7077 (test_block >= fs->group_desc[i].bg_inode_table) &&
7078 (test_block < (fs->group_desc[i].bg_inode_table +
7079 fs->inode_blocks_per_group)))
7080 return 1;
7081
7082 /* Check the bitmap blocks */
7083 if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
7084 (test_block == fs->group_desc[i].bg_inode_bitmap))
7085 return 1;
7086
7087 block += fs->super->s_blocks_per_group;
7088 }
7089 return 0;
7090}
7091/*
7092 * pass2.c --- check directory structure
7093 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007094 * Pass 2 of e2fsck iterates through all active directory inodes, and
7095 * applies to following tests to each directory entry in the directory
7096 * blocks in the inodes:
7097 *
7098 * - The length of the directory entry (rec_len) should be at
7099 * least 8 bytes, and no more than the remaining space
7100 * left in the directory block.
7101 * - The length of the name in the directory entry (name_len)
7102 * should be less than (rec_len - 8).
7103 * - The inode number in the directory entry should be within
7104 * legal bounds.
7105 * - The inode number should refer to a in-use inode.
7106 * - The first entry should be '.', and its inode should be
7107 * the inode of the directory.
7108 * - The second entry should be '..'.
7109 *
7110 * To minimize disk seek time, the directory blocks are processed in
7111 * sorted order of block numbers.
7112 *
7113 * Pass 2 also collects the following information:
7114 * - The inode numbers of the subdirectories for each directory.
7115 *
7116 * Pass 2 relies on the following information from previous passes:
7117 * - The directory information collected in pass 1.
7118 * - The inode_used_map bitmap
7119 * - The inode_bad_map bitmap
7120 * - The inode_dir_map bitmap
7121 *
7122 * Pass 2 frees the following data structures
7123 * - The inode_bad_map bitmap
7124 * - The inode_reg_map bitmap
7125 */
7126
7127/* #define DX_DEBUG */
7128
7129/*
7130 * Keeps track of how many times an inode is referenced.
7131 */
7132static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
7133static int check_dir_block(ext2_filsys fs,
7134 struct ext2_db_entry *dir_blocks_info,
7135 void *priv_data);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007136static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info,
7137 struct problem_context *pctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007138static int update_dir_block(ext2_filsys fs,
7139 blk_t *block_nr,
7140 e2_blkcnt_t blockcnt,
7141 blk_t ref_block,
7142 int ref_offset,
7143 void *priv_data);
7144static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
7145static int htree_depth(struct dx_dir_info *dx_dir,
7146 struct dx_dirblock_info *dx_db);
7147static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
7148
7149struct check_dir_struct {
7150 char *buf;
7151 struct problem_context pctx;
7152 int count, max;
7153 e2fsck_t ctx;
7154};
7155
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007156static void e2fsck_pass2(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007157{
7158 struct ext2_super_block *sb = ctx->fs->super;
7159 struct problem_context pctx;
7160 ext2_filsys fs = ctx->fs;
7161 char *buf;
7162#ifdef RESOURCE_TRACK
7163 struct resource_track rtrack;
7164#endif
7165 struct dir_info *dir;
7166 struct check_dir_struct cd;
7167 struct dx_dir_info *dx_dir;
7168 struct dx_dirblock_info *dx_db, *dx_parent;
7169 int b;
7170 int i, depth;
7171 problem_t code;
7172 int bad_dir;
7173
7174#ifdef RESOURCE_TRACK
7175 init_resource_track(&rtrack);
7176#endif
7177
7178 clear_problem_context(&cd.pctx);
7179
7180#ifdef MTRACE
7181 mtrace_print("Pass 2");
7182#endif
7183
7184 if (!(ctx->options & E2F_OPT_PREEN))
7185 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
7186
7187 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
7188 0, ctx->inode_link_info,
7189 &ctx->inode_count);
7190 if (cd.pctx.errcode) {
7191 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
7192 ctx->flags |= E2F_FLAG_ABORT;
7193 return;
7194 }
7195 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
7196 "directory scan buffer");
7197
7198 /*
7199 * Set up the parent pointer for the root directory, if
7200 * present. (If the root directory is not present, we will
7201 * create it in pass 3.)
7202 */
7203 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
7204 if (dir)
7205 dir->parent = EXT2_ROOT_INO;
7206
7207 cd.buf = buf;
7208 cd.ctx = ctx;
7209 cd.count = 1;
7210 cd.max = ext2fs_dblist_count(fs->dblist);
7211
7212 if (ctx->progress)
7213 (void) (ctx->progress)(ctx, 2, 0, cd.max);
7214
7215 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
7216 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
7217
7218 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
7219 &cd);
7220 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7221 return;
7222 if (cd.pctx.errcode) {
7223 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
7224 ctx->flags |= E2F_FLAG_ABORT;
7225 return;
7226 }
7227
7228#ifdef ENABLE_HTREE
7229 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
7230 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7231 return;
7232 if (dx_dir->numblocks == 0)
7233 continue;
7234 clear_problem_context(&pctx);
7235 bad_dir = 0;
7236 pctx.dir = dx_dir->ino;
7237 dx_db = dx_dir->dx_block;
7238 if (dx_db->flags & DX_FLAG_REFERENCED)
7239 dx_db->flags |= DX_FLAG_DUP_REF;
7240 else
7241 dx_db->flags |= DX_FLAG_REFERENCED;
7242 /*
7243 * Find all of the first and last leaf blocks, and
7244 * update their parent's min and max hash values
7245 */
7246 for (b=0, dx_db = dx_dir->dx_block;
7247 b < dx_dir->numblocks;
7248 b++, dx_db++) {
7249 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
7250 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
7251 continue;
7252 dx_parent = &dx_dir->dx_block[dx_db->parent];
7253 /*
7254 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
7255 */
7256 if (dx_db->flags & DX_FLAG_FIRST)
7257 dx_parent->min_hash = dx_db->min_hash;
7258 /*
7259 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
7260 */
7261 if (dx_db->flags & DX_FLAG_LAST)
7262 dx_parent->max_hash = dx_db->max_hash;
7263 }
7264
7265 for (b=0, dx_db = dx_dir->dx_block;
7266 b < dx_dir->numblocks;
7267 b++, dx_db++) {
7268 pctx.blkcount = b;
7269 pctx.group = dx_db->parent;
7270 code = 0;
7271 if (!(dx_db->flags & DX_FLAG_FIRST) &&
7272 (dx_db->min_hash < dx_db->node_min_hash)) {
7273 pctx.blk = dx_db->min_hash;
7274 pctx.blk2 = dx_db->node_min_hash;
7275 code = PR_2_HTREE_MIN_HASH;
7276 fix_problem(ctx, code, &pctx);
7277 bad_dir++;
7278 }
7279 if (dx_db->type == DX_DIRBLOCK_LEAF) {
7280 depth = htree_depth(dx_dir, dx_db);
7281 if (depth != dx_dir->depth) {
7282 code = PR_2_HTREE_BAD_DEPTH;
7283 fix_problem(ctx, code, &pctx);
7284 bad_dir++;
7285 }
7286 }
7287 /*
7288 * This test doesn't apply for the root block
7289 * at block #0
7290 */
7291 if (b &&
7292 (dx_db->max_hash > dx_db->node_max_hash)) {
7293 pctx.blk = dx_db->max_hash;
7294 pctx.blk2 = dx_db->node_max_hash;
7295 code = PR_2_HTREE_MAX_HASH;
7296 fix_problem(ctx, code, &pctx);
7297 bad_dir++;
7298 }
7299 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
7300 code = PR_2_HTREE_NOTREF;
7301 fix_problem(ctx, code, &pctx);
7302 bad_dir++;
7303 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
7304 code = PR_2_HTREE_DUPREF;
7305 fix_problem(ctx, code, &pctx);
7306 bad_dir++;
7307 }
7308 if (code == 0)
7309 continue;
7310 }
7311 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
7312 clear_htree(ctx, dx_dir->ino);
7313 dx_dir->numblocks = 0;
7314 }
7315 }
7316#endif
7317 ext2fs_free_mem(&buf);
7318 ext2fs_free_dblist(fs->dblist);
7319
Rob Landleye7c43b62006-03-01 16:39:45 +00007320 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
7321 ctx->inode_bad_map = 0;
7322 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
7323 ctx->inode_reg_map = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007324
7325 clear_problem_context(&pctx);
7326 if (ctx->large_files) {
7327 if (!(sb->s_feature_ro_compat &
7328 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
7329 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
7330 sb->s_feature_ro_compat |=
7331 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7332 ext2fs_mark_super_dirty(fs);
7333 }
7334 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
7335 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
7336 ext2fs_update_dynamic_rev(fs);
7337 ext2fs_mark_super_dirty(fs);
7338 }
7339 } else if (!ctx->large_files &&
7340 (sb->s_feature_ro_compat &
7341 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
7342 if (fs->flags & EXT2_FLAG_RW) {
7343 sb->s_feature_ro_compat &=
7344 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7345 ext2fs_mark_super_dirty(fs);
7346 }
7347 }
7348
7349#ifdef RESOURCE_TRACK
7350 if (ctx->options & E2F_OPT_TIME2) {
7351 e2fsck_clear_progbar(ctx);
7352 print_resource_track(_("Pass 2"), &rtrack);
7353 }
7354#endif
7355}
7356
7357#define MAX_DEPTH 32000
7358static int htree_depth(struct dx_dir_info *dx_dir,
7359 struct dx_dirblock_info *dx_db)
7360{
7361 int depth = 0;
7362
7363 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
7364 dx_db = &dx_dir->dx_block[dx_db->parent];
7365 depth++;
7366 }
7367 return depth;
7368}
7369
7370static int dict_de_cmp(const void *a, const void *b)
7371{
7372 const struct ext2_dir_entry *de_a, *de_b;
7373 int a_len, b_len;
7374
7375 de_a = (const struct ext2_dir_entry *) a;
7376 a_len = de_a->name_len & 0xFF;
7377 de_b = (const struct ext2_dir_entry *) b;
7378 b_len = de_b->name_len & 0xFF;
7379
7380 if (a_len != b_len)
7381 return (a_len - b_len);
7382
7383 return strncmp(de_a->name, de_b->name, a_len);
7384}
7385
7386/*
7387 * This is special sort function that makes sure that directory blocks
7388 * with a dirblock of zero are sorted to the beginning of the list.
7389 * This guarantees that the root node of the htree directories are
7390 * processed first, so we know what hash version to use.
7391 */
7392static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
7393{
7394 const struct ext2_db_entry *db_a =
7395 (const struct ext2_db_entry *) a;
7396 const struct ext2_db_entry *db_b =
7397 (const struct ext2_db_entry *) b;
7398
7399 if (db_a->blockcnt && !db_b->blockcnt)
7400 return 1;
7401
7402 if (!db_a->blockcnt && db_b->blockcnt)
7403 return -1;
7404
7405 if (db_a->blk != db_b->blk)
7406 return (int) (db_a->blk - db_b->blk);
7407
7408 if (db_a->ino != db_b->ino)
7409 return (int) (db_a->ino - db_b->ino);
7410
7411 return (int) (db_a->blockcnt - db_b->blockcnt);
7412}
7413
7414
7415/*
7416 * Make sure the first entry in the directory is '.', and that the
7417 * directory entry is sane.
7418 */
7419static int check_dot(e2fsck_t ctx,
7420 struct ext2_dir_entry *dirent,
7421 ext2_ino_t ino, struct problem_context *pctx)
7422{
7423 struct ext2_dir_entry *nextdir;
7424 int status = 0;
7425 int created = 0;
7426 int new_len;
7427 int problem = 0;
7428
7429 if (!dirent->inode)
7430 problem = PR_2_MISSING_DOT;
7431 else if (((dirent->name_len & 0xFF) != 1) ||
7432 (dirent->name[0] != '.'))
7433 problem = PR_2_1ST_NOT_DOT;
7434 else if (dirent->name[1] != '\0')
7435 problem = PR_2_DOT_NULL_TERM;
7436
7437 if (problem) {
7438 if (fix_problem(ctx, problem, pctx)) {
7439 if (dirent->rec_len < 12)
7440 dirent->rec_len = 12;
7441 dirent->inode = ino;
7442 dirent->name_len = 1;
7443 dirent->name[0] = '.';
7444 dirent->name[1] = '\0';
7445 status = 1;
7446 created = 1;
7447 }
7448 }
7449 if (dirent->inode != ino) {
7450 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
7451 dirent->inode = ino;
7452 status = 1;
7453 }
7454 }
7455 if (dirent->rec_len > 12) {
7456 new_len = dirent->rec_len - 12;
7457 if (new_len > 12) {
7458 if (created ||
7459 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
7460 nextdir = (struct ext2_dir_entry *)
7461 ((char *) dirent + 12);
7462 dirent->rec_len = 12;
7463 nextdir->rec_len = new_len;
7464 nextdir->inode = 0;
7465 nextdir->name_len = 0;
7466 status = 1;
7467 }
7468 }
7469 }
7470 return status;
7471}
7472
7473/*
7474 * Make sure the second entry in the directory is '..', and that the
7475 * directory entry is sane. We do not check the inode number of '..'
7476 * here; this gets done in pass 3.
7477 */
7478static int check_dotdot(e2fsck_t ctx,
7479 struct ext2_dir_entry *dirent,
7480 struct dir_info *dir, struct problem_context *pctx)
7481{
7482 int problem = 0;
7483
7484 if (!dirent->inode)
7485 problem = PR_2_MISSING_DOT_DOT;
7486 else if (((dirent->name_len & 0xFF) != 2) ||
7487 (dirent->name[0] != '.') ||
7488 (dirent->name[1] != '.'))
7489 problem = PR_2_2ND_NOT_DOT_DOT;
7490 else if (dirent->name[2] != '\0')
7491 problem = PR_2_DOT_DOT_NULL_TERM;
7492
7493 if (problem) {
7494 if (fix_problem(ctx, problem, pctx)) {
7495 if (dirent->rec_len < 12)
7496 dirent->rec_len = 12;
7497 /*
7498 * Note: we don't have the parent inode just
7499 * yet, so we will fill it in with the root
7500 * inode. This will get fixed in pass 3.
7501 */
7502 dirent->inode = EXT2_ROOT_INO;
7503 dirent->name_len = 2;
7504 dirent->name[0] = '.';
7505 dirent->name[1] = '.';
7506 dirent->name[2] = '\0';
7507 return 1;
7508 }
7509 return 0;
7510 }
7511 dir->dotdot = dirent->inode;
7512 return 0;
7513}
7514
7515/*
7516 * Check to make sure a directory entry doesn't contain any illegal
7517 * characters.
7518 */
7519static int check_name(e2fsck_t ctx,
7520 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007521 struct problem_context *pctx)
7522{
7523 int i;
7524 int fixup = -1;
7525 int ret = 0;
7526
7527 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
7528 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
7529 if (fixup < 0) {
7530 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
7531 }
7532 if (fixup) {
7533 dirent->name[i] = '.';
7534 ret = 1;
7535 }
7536 }
7537 }
7538 return ret;
7539}
7540
7541/*
7542 * Check the directory filetype (if present)
7543 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007544
7545/*
7546 * Given a mode, return the ext2 file type
7547 */
7548static int ext2_file_type(unsigned int mode)
7549{
7550 if (LINUX_S_ISREG(mode))
7551 return EXT2_FT_REG_FILE;
7552
7553 if (LINUX_S_ISDIR(mode))
7554 return EXT2_FT_DIR;
7555
7556 if (LINUX_S_ISCHR(mode))
7557 return EXT2_FT_CHRDEV;
7558
7559 if (LINUX_S_ISBLK(mode))
7560 return EXT2_FT_BLKDEV;
7561
7562 if (LINUX_S_ISLNK(mode))
7563 return EXT2_FT_SYMLINK;
7564
7565 if (LINUX_S_ISFIFO(mode))
7566 return EXT2_FT_FIFO;
7567
7568 if (LINUX_S_ISSOCK(mode))
7569 return EXT2_FT_SOCK;
7570
7571 return 0;
7572}
7573
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007574static _INLINE_ int check_filetype(e2fsck_t ctx,
7575 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007576 struct problem_context *pctx)
7577{
7578 int filetype = dirent->name_len >> 8;
7579 int should_be = EXT2_FT_UNKNOWN;
7580 struct ext2_inode inode;
7581
7582 if (!(ctx->fs->super->s_feature_incompat &
7583 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
7584 if (filetype == 0 ||
7585 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
7586 return 0;
7587 dirent->name_len = dirent->name_len & 0xFF;
7588 return 1;
7589 }
7590
7591 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
7592 should_be = EXT2_FT_DIR;
7593 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
7594 dirent->inode)) {
7595 should_be = EXT2_FT_REG_FILE;
7596 } else if (ctx->inode_bad_map &&
7597 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
7598 dirent->inode))
7599 should_be = 0;
7600 else {
7601 e2fsck_read_inode(ctx, dirent->inode, &inode,
7602 "check_filetype");
7603 should_be = ext2_file_type(inode.i_mode);
7604 }
7605 if (filetype == should_be)
7606 return 0;
7607 pctx->num = should_be;
7608
7609 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
7610 pctx) == 0)
7611 return 0;
7612
7613 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
7614 return 1;
7615}
7616
7617#ifdef ENABLE_HTREE
7618static void parse_int_node(ext2_filsys fs,
7619 struct ext2_db_entry *db,
7620 struct check_dir_struct *cd,
7621 struct dx_dir_info *dx_dir,
7622 char *block_buf)
7623{
7624 struct ext2_dx_root_info *root;
7625 struct ext2_dx_entry *ent;
7626 struct ext2_dx_countlimit *limit;
7627 struct dx_dirblock_info *dx_db;
7628 int i, expect_limit, count;
7629 blk_t blk;
7630 ext2_dirhash_t min_hash = 0xffffffff;
7631 ext2_dirhash_t max_hash = 0;
7632 ext2_dirhash_t hash = 0, prev_hash;
7633
7634 if (db->blockcnt == 0) {
7635 root = (struct ext2_dx_root_info *) (block_buf + 24);
7636
7637#ifdef DX_DEBUG
7638 printf("Root node dump:\n");
7639 printf("\t Reserved zero: %d\n", root->reserved_zero);
7640 printf("\t Hash Version: %d\n", root->hash_version);
7641 printf("\t Info length: %d\n", root->info_length);
7642 printf("\t Indirect levels: %d\n", root->indirect_levels);
7643 printf("\t Flags: %d\n", root->unused_flags);
7644#endif
7645
7646 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
7647 } else {
7648 ent = (struct ext2_dx_entry *) (block_buf+8);
7649 }
7650 limit = (struct ext2_dx_countlimit *) ent;
7651
7652#ifdef DX_DEBUG
7653 printf("Number of entries (count): %d\n",
7654 ext2fs_le16_to_cpu(limit->count));
7655 printf("Number of entries (limit): %d\n",
7656 ext2fs_le16_to_cpu(limit->limit));
7657#endif
7658
7659 count = ext2fs_le16_to_cpu(limit->count);
7660 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
7661 sizeof(struct ext2_dx_entry);
7662 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
7663 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
7664 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
7665 goto clear_and_exit;
7666 }
7667 if (count > expect_limit) {
7668 cd->pctx.num = count;
7669 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
7670 goto clear_and_exit;
7671 count = expect_limit;
7672 }
7673
7674 for (i=0; i < count; i++) {
7675 prev_hash = hash;
7676 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
7677#ifdef DX_DEBUG
7678 printf("Entry #%d: Hash 0x%08x, block %d\n", i,
7679 hash, ext2fs_le32_to_cpu(ent[i].block));
7680#endif
7681 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
7682 /* Check to make sure the block is valid */
7683 if (blk > (blk_t) dx_dir->numblocks) {
7684 cd->pctx.blk = blk;
7685 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
7686 &cd->pctx))
7687 goto clear_and_exit;
7688 }
7689 if (hash < prev_hash &&
7690 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
7691 goto clear_and_exit;
7692 dx_db = &dx_dir->dx_block[blk];
7693 if (dx_db->flags & DX_FLAG_REFERENCED) {
7694 dx_db->flags |= DX_FLAG_DUP_REF;
7695 } else {
7696 dx_db->flags |= DX_FLAG_REFERENCED;
7697 dx_db->parent = db->blockcnt;
7698 }
7699 if (hash < min_hash)
7700 min_hash = hash;
7701 if (hash > max_hash)
7702 max_hash = hash;
7703 dx_db->node_min_hash = hash;
7704 if ((i+1) < count)
7705 dx_db->node_max_hash =
7706 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
7707 else {
7708 dx_db->node_max_hash = 0xfffffffe;
7709 dx_db->flags |= DX_FLAG_LAST;
7710 }
7711 if (i == 0)
7712 dx_db->flags |= DX_FLAG_FIRST;
7713 }
7714#ifdef DX_DEBUG
7715 printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
7716 db->blockcnt, min_hash, max_hash);
7717#endif
7718 dx_db = &dx_dir->dx_block[db->blockcnt];
7719 dx_db->min_hash = min_hash;
7720 dx_db->max_hash = max_hash;
7721 return;
7722
7723clear_and_exit:
7724 clear_htree(cd->ctx, cd->pctx.ino);
7725 dx_dir->numblocks = 0;
7726}
7727#endif /* ENABLE_HTREE */
7728
7729/*
7730 * Given a busted directory, try to salvage it somehow.
7731 *
7732 */
7733static void salvage_directory(ext2_filsys fs,
7734 struct ext2_dir_entry *dirent,
7735 struct ext2_dir_entry *prev,
7736 unsigned int *offset)
7737{
7738 char *cp = (char *) dirent;
7739 int left = fs->blocksize - *offset - dirent->rec_len;
7740 int name_len = dirent->name_len & 0xFF;
7741
7742 /*
7743 * Special case of directory entry of size 8: copy what's left
7744 * of the directory block up to cover up the invalid hole.
7745 */
7746 if ((left >= 12) && (dirent->rec_len == 8)) {
7747 memmove(cp, cp+8, left);
7748 memset(cp + left, 0, 8);
7749 return;
7750 }
7751 /*
7752 * If the directory entry overruns the end of the directory
7753 * block, and the name is small enough to fit, then adjust the
7754 * record length.
7755 */
7756 if ((left < 0) &&
7757 (name_len + 8 <= dirent->rec_len + left) &&
7758 dirent->inode <= fs->super->s_inodes_count &&
7759 strnlen(dirent->name, name_len) == name_len) {
7760 dirent->rec_len += left;
7761 return;
7762 }
7763 /*
7764 * If the directory entry is a multiple of four, so it is
7765 * valid, let the previous directory entry absorb the invalid
7766 * one.
7767 */
7768 if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
7769 prev->rec_len += dirent->rec_len;
7770 *offset += dirent->rec_len;
7771 return;
7772 }
7773 /*
7774 * Default salvage method --- kill all of the directory
7775 * entries for the rest of the block. We will either try to
7776 * absorb it into the previous directory entry, or create a
7777 * new empty directory entry the rest of the directory block.
7778 */
7779 if (prev) {
7780 prev->rec_len += fs->blocksize - *offset;
7781 *offset = fs->blocksize;
7782 } else {
7783 dirent->rec_len = fs->blocksize - *offset;
7784 dirent->name_len = 0;
7785 dirent->inode = 0;
7786 }
7787}
7788
7789static int check_dir_block(ext2_filsys fs,
7790 struct ext2_db_entry *db,
7791 void *priv_data)
7792{
7793 struct dir_info *subdir, *dir;
7794 struct dx_dir_info *dx_dir;
7795#ifdef ENABLE_HTREE
7796 struct dx_dirblock_info *dx_db = 0;
7797#endif /* ENABLE_HTREE */
7798 struct ext2_dir_entry *dirent, *prev;
7799 ext2_dirhash_t hash;
7800 unsigned int offset = 0;
7801 int dir_modified = 0;
7802 int dot_state;
7803 blk_t block_nr = db->blk;
7804 ext2_ino_t ino = db->ino;
7805 __u16 links;
7806 struct check_dir_struct *cd;
7807 char *buf;
7808 e2fsck_t ctx;
7809 int problem;
7810 struct ext2_dx_root_info *root;
7811 struct ext2_dx_countlimit *limit;
7812 static dict_t de_dict;
7813 struct problem_context pctx;
7814 int dups_found = 0;
7815
7816 cd = (struct check_dir_struct *) priv_data;
7817 buf = cd->buf;
7818 ctx = cd->ctx;
7819
7820 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7821 return DIRENT_ABORT;
7822
7823 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
7824 return DIRENT_ABORT;
7825
7826 /*
7827 * Make sure the inode is still in use (could have been
7828 * deleted in the duplicate/bad blocks pass.
7829 */
7830 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
7831 return 0;
7832
7833 cd->pctx.ino = ino;
7834 cd->pctx.blk = block_nr;
7835 cd->pctx.blkcount = db->blockcnt;
7836 cd->pctx.ino2 = 0;
7837 cd->pctx.dirent = 0;
7838 cd->pctx.num = 0;
7839
7840 if (db->blk == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007841 if (allocate_dir_block(ctx, db, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007842 return 0;
7843 block_nr = db->blk;
7844 }
7845
7846 if (db->blockcnt)
7847 dot_state = 2;
7848 else
7849 dot_state = 0;
7850
7851 if (ctx->dirs_to_hash &&
7852 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
7853 dups_found++;
7854
7855#if 0
7856 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
7857 db->blockcnt, ino);
7858#endif
7859
7860 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
7861 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
7862 cd->pctx.errcode = 0; /* We'll handle this ourselves */
7863 if (cd->pctx.errcode) {
7864 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
7865 ctx->flags |= E2F_FLAG_ABORT;
7866 return DIRENT_ABORT;
7867 }
7868 memset(buf, 0, fs->blocksize);
7869 }
7870#ifdef ENABLE_HTREE
7871 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
7872 if (dx_dir && dx_dir->numblocks) {
7873 if (db->blockcnt >= dx_dir->numblocks) {
7874 printf("XXX should never happen!!!\n");
7875 abort();
7876 }
7877 dx_db = &dx_dir->dx_block[db->blockcnt];
7878 dx_db->type = DX_DIRBLOCK_LEAF;
7879 dx_db->phys = block_nr;
7880 dx_db->min_hash = ~0;
7881 dx_db->max_hash = 0;
7882
7883 dirent = (struct ext2_dir_entry *) buf;
7884 limit = (struct ext2_dx_countlimit *) (buf+8);
7885 if (db->blockcnt == 0) {
7886 root = (struct ext2_dx_root_info *) (buf + 24);
7887 dx_db->type = DX_DIRBLOCK_ROOT;
7888 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
7889 if ((root->reserved_zero ||
7890 root->info_length < 8 ||
7891 root->indirect_levels > 1) &&
7892 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
7893 clear_htree(ctx, ino);
7894 dx_dir->numblocks = 0;
7895 dx_db = 0;
7896 }
7897 dx_dir->hashversion = root->hash_version;
7898 dx_dir->depth = root->indirect_levels + 1;
7899 } else if ((dirent->inode == 0) &&
7900 (dirent->rec_len == fs->blocksize) &&
7901 (dirent->name_len == 0) &&
7902 (ext2fs_le16_to_cpu(limit->limit) ==
7903 ((fs->blocksize-8) /
7904 sizeof(struct ext2_dx_entry))))
7905 dx_db->type = DX_DIRBLOCK_NODE;
7906 }
7907#endif /* ENABLE_HTREE */
7908
7909 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
7910 prev = 0;
7911 do {
7912 problem = 0;
7913 dirent = (struct ext2_dir_entry *) (buf + offset);
7914 cd->pctx.dirent = dirent;
7915 cd->pctx.num = offset;
7916 if (((offset + dirent->rec_len) > fs->blocksize) ||
7917 (dirent->rec_len < 12) ||
7918 ((dirent->rec_len % 4) != 0) ||
7919 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
7920 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
7921 salvage_directory(fs, dirent, prev, &offset);
7922 dir_modified++;
7923 continue;
7924 } else
7925 goto abort_free_dict;
7926 }
7927 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
7928 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
7929 dirent->name_len = EXT2_NAME_LEN;
7930 dir_modified++;
7931 }
7932 }
7933
7934 if (dot_state == 0) {
7935 if (check_dot(ctx, dirent, ino, &cd->pctx))
7936 dir_modified++;
7937 } else if (dot_state == 1) {
7938 dir = e2fsck_get_dir_info(ctx, ino);
7939 if (!dir) {
7940 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
7941 goto abort_free_dict;
7942 }
7943 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
7944 dir_modified++;
7945 } else if (dirent->inode == ino) {
7946 problem = PR_2_LINK_DOT;
7947 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
7948 dirent->inode = 0;
7949 dir_modified++;
7950 goto next;
7951 }
7952 }
7953 if (!dirent->inode)
7954 goto next;
7955
7956 /*
7957 * Make sure the inode listed is a legal one.
7958 */
7959 if (((dirent->inode != EXT2_ROOT_INO) &&
7960 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
7961 (dirent->inode > fs->super->s_inodes_count)) {
7962 problem = PR_2_BAD_INO;
7963 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
7964 dirent->inode))) {
7965 /*
7966 * If the inode is unused, offer to clear it.
7967 */
7968 problem = PR_2_UNUSED_INODE;
7969 } else if (ctx->inode_bb_map &&
7970 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
7971 dirent->inode))) {
7972 /*
7973 * If the inode is in a bad block, offer to
7974 * clear it.
7975 */
7976 problem = PR_2_BB_INODE;
7977 } else if ((dot_state > 1) &&
7978 ((dirent->name_len & 0xFF) == 1) &&
7979 (dirent->name[0] == '.')) {
7980 /*
7981 * If there's a '.' entry in anything other
7982 * than the first directory entry, it's a
7983 * duplicate entry that should be removed.
7984 */
7985 problem = PR_2_DUP_DOT;
7986 } else if ((dot_state > 1) &&
7987 ((dirent->name_len & 0xFF) == 2) &&
7988 (dirent->name[0] == '.') &&
7989 (dirent->name[1] == '.')) {
7990 /*
7991 * If there's a '..' entry in anything other
7992 * than the second directory entry, it's a
7993 * duplicate entry that should be removed.
7994 */
7995 problem = PR_2_DUP_DOT_DOT;
7996 } else if ((dot_state > 1) &&
7997 (dirent->inode == EXT2_ROOT_INO)) {
7998 /*
7999 * Don't allow links to the root directory.
8000 * We check this specially to make sure we
8001 * catch this error case even if the root
8002 * directory hasn't been created yet.
8003 */
8004 problem = PR_2_LINK_ROOT;
8005 } else if ((dot_state > 1) &&
8006 (dirent->name_len & 0xFF) == 0) {
8007 /*
8008 * Don't allow zero-length directory names.
8009 */
8010 problem = PR_2_NULL_NAME;
8011 }
8012
8013 if (problem) {
8014 if (fix_problem(ctx, problem, &cd->pctx)) {
8015 dirent->inode = 0;
8016 dir_modified++;
8017 goto next;
8018 } else {
8019 ext2fs_unmark_valid(fs);
8020 if (problem == PR_2_BAD_INO)
8021 goto next;
8022 }
8023 }
8024
8025 /*
8026 * If the inode was marked as having bad fields in
8027 * pass1, process it and offer to fix/clear it.
8028 * (We wait until now so that we can display the
8029 * pathname to the user.)
8030 */
8031 if (ctx->inode_bad_map &&
8032 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
8033 dirent->inode)) {
8034 if (e2fsck_process_bad_inode(ctx, ino,
8035 dirent->inode,
8036 buf + fs->blocksize)) {
8037 dirent->inode = 0;
8038 dir_modified++;
8039 goto next;
8040 }
8041 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8042 return DIRENT_ABORT;
8043 }
8044
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008045 if (check_name(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008046 dir_modified++;
8047
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008048 if (check_filetype(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008049 dir_modified++;
8050
8051#ifdef ENABLE_HTREE
8052 if (dx_db) {
8053 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
8054 (dirent->name_len & 0xFF),
8055 fs->super->s_hash_seed, &hash, 0);
8056 if (hash < dx_db->min_hash)
8057 dx_db->min_hash = hash;
8058 if (hash > dx_db->max_hash)
8059 dx_db->max_hash = hash;
8060 }
8061#endif
8062
8063 /*
8064 * If this is a directory, then mark its parent in its
8065 * dir_info structure. If the parent field is already
8066 * filled in, then this directory has more than one
8067 * hard link. We assume the first link is correct,
8068 * and ask the user if he/she wants to clear this one.
8069 */
8070 if ((dot_state > 1) &&
8071 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8072 dirent->inode))) {
8073 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
8074 if (!subdir) {
8075 cd->pctx.ino = dirent->inode;
8076 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
8077 goto abort_free_dict;
8078 }
8079 if (subdir->parent) {
8080 cd->pctx.ino2 = subdir->parent;
8081 if (fix_problem(ctx, PR_2_LINK_DIR,
8082 &cd->pctx)) {
8083 dirent->inode = 0;
8084 dir_modified++;
8085 goto next;
8086 }
8087 cd->pctx.ino2 = 0;
8088 } else
8089 subdir->parent = ino;
8090 }
8091
8092 if (dups_found) {
8093 ;
8094 } else if (dict_lookup(&de_dict, dirent)) {
8095 clear_problem_context(&pctx);
8096 pctx.ino = ino;
8097 pctx.dirent = dirent;
8098 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
8099 if (!ctx->dirs_to_hash)
8100 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
8101 if (ctx->dirs_to_hash)
8102 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8103 dups_found++;
8104 } else
8105 dict_alloc_insert(&de_dict, dirent, dirent);
8106
8107 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
8108 &links);
8109 if (links > 1)
8110 ctx->fs_links_count++;
8111 ctx->fs_total_count++;
8112 next:
8113 prev = dirent;
8114 offset += dirent->rec_len;
8115 dot_state++;
8116 } while (offset < fs->blocksize);
8117#if 0
8118 printf("\n");
8119#endif
8120#ifdef ENABLE_HTREE
8121 if (dx_db) {
8122#ifdef DX_DEBUG
8123 printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
8124 db->blockcnt, dx_db->type,
8125 dx_db->min_hash, dx_db->max_hash);
8126#endif
8127 cd->pctx.dir = cd->pctx.ino;
8128 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
8129 (dx_db->type == DX_DIRBLOCK_NODE))
8130 parse_int_node(fs, db, cd, dx_dir, buf);
8131 }
8132#endif /* ENABLE_HTREE */
8133 if (offset != fs->blocksize) {
8134 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
8135 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
8136 dirent->rec_len = cd->pctx.num;
8137 dir_modified++;
8138 }
8139 }
8140 if (dir_modified) {
8141 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
8142 if (cd->pctx.errcode) {
8143 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
8144 &cd->pctx))
8145 goto abort_free_dict;
8146 }
8147 ext2fs_mark_changed(fs);
8148 }
8149 dict_free_nodes(&de_dict);
8150 return 0;
8151abort_free_dict:
8152 dict_free_nodes(&de_dict);
8153 ctx->flags |= E2F_FLAG_ABORT;
8154 return DIRENT_ABORT;
8155}
8156
8157/*
8158 * This function is called to deallocate a block, and is an interator
8159 * functioned called by deallocate inode via ext2fs_iterate_block().
8160 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008161static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00008162 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
8163 blk_t ref_block FSCK_ATTR((unused)),
8164 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008165 void *priv_data)
8166{
8167 e2fsck_t ctx = (e2fsck_t) priv_data;
8168
8169 if (HOLE_BLKADDR(*block_nr))
8170 return 0;
8171 if ((*block_nr < fs->super->s_first_data_block) ||
8172 (*block_nr >= fs->super->s_blocks_count))
8173 return 0;
8174 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
8175 ext2fs_block_alloc_stats(fs, *block_nr, -1);
8176 return 0;
8177}
8178
8179/*
8180 * This fuction deallocates an inode
8181 */
8182static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
8183{
8184 ext2_filsys fs = ctx->fs;
8185 struct ext2_inode inode;
8186 struct problem_context pctx;
8187 __u32 count;
8188
8189 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
8190 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
8191 inode.i_links_count = 0;
8192 inode.i_dtime = time(0);
8193 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
8194 clear_problem_context(&pctx);
8195 pctx.ino = ino;
8196
8197 /*
8198 * Fix up the bitmaps...
8199 */
8200 e2fsck_read_bitmaps(ctx);
8201 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
8202 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
8203 if (ctx->inode_bad_map)
8204 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8205 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
8206
8207 if (inode.i_file_acl &&
8208 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
8209 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
8210 block_buf, -1, &count);
8211 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
8212 pctx.errcode = 0;
8213 count = 1;
8214 }
8215 if (pctx.errcode) {
8216 pctx.blk = inode.i_file_acl;
8217 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
8218 ctx->flags |= E2F_FLAG_ABORT;
8219 return;
8220 }
8221 if (count == 0) {
8222 ext2fs_unmark_block_bitmap(ctx->block_found_map,
8223 inode.i_file_acl);
8224 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
8225 }
8226 inode.i_file_acl = 0;
8227 }
8228
8229 if (!ext2fs_inode_has_valid_blocks(&inode))
8230 return;
8231
8232 if (LINUX_S_ISREG(inode.i_mode) &&
8233 (inode.i_size_high || inode.i_size & 0x80000000UL))
8234 ctx->large_files--;
8235
8236 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
8237 deallocate_inode_block, ctx);
8238 if (pctx.errcode) {
8239 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
8240 ctx->flags |= E2F_FLAG_ABORT;
8241 return;
8242 }
8243}
8244
8245/*
8246 * This fuction clears the htree flag on an inode
8247 */
8248static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
8249{
8250 struct ext2_inode inode;
8251
8252 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
8253 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
8254 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
8255 if (ctx->dirs_to_hash)
8256 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8257}
8258
8259
8260static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
8261 ext2_ino_t ino, char *buf)
8262{
8263 ext2_filsys fs = ctx->fs;
8264 struct ext2_inode inode;
8265 int inode_modified = 0;
8266 int not_fixed = 0;
8267 unsigned char *frag, *fsize;
8268 struct problem_context pctx;
8269 int problem = 0;
8270
8271 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
8272
8273 clear_problem_context(&pctx);
8274 pctx.ino = ino;
8275 pctx.dir = dir;
8276 pctx.inode = &inode;
8277
8278 if (inode.i_file_acl &&
8279 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
8280 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
8281 inode.i_file_acl = 0;
8282#ifdef EXT2FS_ENABLE_SWAPFS
8283 /*
8284 * This is a special kludge to deal with long symlinks
8285 * on big endian systems. i_blocks had already been
8286 * decremented earlier in pass 1, but since i_file_acl
8287 * hadn't yet been cleared, ext2fs_read_inode()
8288 * assumed that the file was short symlink and would
8289 * not have byte swapped i_block[0]. Hence, we have
8290 * to byte-swap it here.
8291 */
8292 if (LINUX_S_ISLNK(inode.i_mode) &&
8293 (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
8294 (inode.i_blocks == fs->blocksize >> 9))
8295 inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
8296#endif
8297 inode_modified++;
8298 } else
8299 not_fixed++;
8300
8301 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
8302 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
8303 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
8304 !(LINUX_S_ISSOCK(inode.i_mode)))
8305 problem = PR_2_BAD_MODE;
8306 else if (LINUX_S_ISCHR(inode.i_mode)
8307 && !e2fsck_pass1_check_device_inode(fs, &inode))
8308 problem = PR_2_BAD_CHAR_DEV;
8309 else if (LINUX_S_ISBLK(inode.i_mode)
8310 && !e2fsck_pass1_check_device_inode(fs, &inode))
8311 problem = PR_2_BAD_BLOCK_DEV;
8312 else if (LINUX_S_ISFIFO(inode.i_mode)
8313 && !e2fsck_pass1_check_device_inode(fs, &inode))
8314 problem = PR_2_BAD_FIFO;
8315 else if (LINUX_S_ISSOCK(inode.i_mode)
8316 && !e2fsck_pass1_check_device_inode(fs, &inode))
8317 problem = PR_2_BAD_SOCKET;
8318 else if (LINUX_S_ISLNK(inode.i_mode)
8319 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
8320 problem = PR_2_INVALID_SYMLINK;
8321 }
8322
8323 if (problem) {
8324 if (fix_problem(ctx, problem, &pctx)) {
8325 deallocate_inode(ctx, ino, 0);
8326 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8327 return 0;
8328 return 1;
8329 } else
8330 not_fixed++;
8331 problem = 0;
8332 }
8333
8334 if (inode.i_faddr) {
8335 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
8336 inode.i_faddr = 0;
8337 inode_modified++;
8338 } else
8339 not_fixed++;
8340 }
8341
8342 switch (fs->super->s_creator_os) {
8343 case EXT2_OS_LINUX:
8344 frag = &inode.osd2.linux2.l_i_frag;
8345 fsize = &inode.osd2.linux2.l_i_fsize;
8346 break;
8347 case EXT2_OS_HURD:
8348 frag = &inode.osd2.hurd2.h_i_frag;
8349 fsize = &inode.osd2.hurd2.h_i_fsize;
8350 break;
8351 case EXT2_OS_MASIX:
8352 frag = &inode.osd2.masix2.m_i_frag;
8353 fsize = &inode.osd2.masix2.m_i_fsize;
8354 break;
8355 default:
8356 frag = fsize = 0;
8357 }
8358 if (frag && *frag) {
8359 pctx.num = *frag;
8360 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
8361 *frag = 0;
8362 inode_modified++;
8363 } else
8364 not_fixed++;
8365 pctx.num = 0;
8366 }
8367 if (fsize && *fsize) {
8368 pctx.num = *fsize;
8369 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
8370 *fsize = 0;
8371 inode_modified++;
8372 } else
8373 not_fixed++;
8374 pctx.num = 0;
8375 }
8376
8377 if (inode.i_file_acl &&
8378 ((inode.i_file_acl < fs->super->s_first_data_block) ||
8379 (inode.i_file_acl >= fs->super->s_blocks_count))) {
8380 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
8381 inode.i_file_acl = 0;
8382 inode_modified++;
8383 } else
8384 not_fixed++;
8385 }
8386 if (inode.i_dir_acl &&
8387 LINUX_S_ISDIR(inode.i_mode)) {
8388 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
8389 inode.i_dir_acl = 0;
8390 inode_modified++;
8391 } else
8392 not_fixed++;
8393 }
8394
8395 if (inode_modified)
8396 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
8397 if (!not_fixed)
8398 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8399 return 0;
8400}
8401
8402
8403/*
8404 * allocate_dir_block --- this function allocates a new directory
8405 * block for a particular inode; this is done if a directory has
8406 * a "hole" in it, or if a directory has a illegal block number
8407 * that was zeroed out and now needs to be replaced.
8408 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008409static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008410 struct problem_context *pctx)
8411{
8412 ext2_filsys fs = ctx->fs;
8413 blk_t blk;
8414 char *block;
8415 struct ext2_inode inode;
8416
8417 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
8418 return 1;
8419
8420 /*
8421 * Read the inode and block bitmaps in; we'll be messing with
8422 * them.
8423 */
8424 e2fsck_read_bitmaps(ctx);
8425
8426 /*
8427 * First, find a free block
8428 */
8429 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8430 if (pctx->errcode) {
8431 pctx->str = "ext2fs_new_block";
8432 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8433 return 1;
8434 }
8435 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8436 ext2fs_mark_block_bitmap(fs->block_map, blk);
8437 ext2fs_mark_bb_dirty(fs);
8438
8439 /*
8440 * Now let's create the actual data block for the inode
8441 */
8442 if (db->blockcnt)
8443 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
8444 else
8445 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
8446 EXT2_ROOT_INO, &block);
8447
8448 if (pctx->errcode) {
8449 pctx->str = "ext2fs_new_dir_block";
8450 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8451 return 1;
8452 }
8453
8454 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
8455 ext2fs_free_mem(&block);
8456 if (pctx->errcode) {
8457 pctx->str = "ext2fs_write_dir_block";
8458 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8459 return 1;
8460 }
8461
8462 /*
8463 * Update the inode block count
8464 */
8465 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
8466 inode.i_blocks += fs->blocksize / 512;
8467 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
8468 inode.i_size = (db->blockcnt+1) * fs->blocksize;
8469 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
8470
8471 /*
8472 * Finally, update the block pointers for the inode
8473 */
8474 db->blk = blk;
8475 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
8476 0, update_dir_block, db);
8477 if (pctx->errcode) {
8478 pctx->str = "ext2fs_block_iterate";
8479 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8480 return 1;
8481 }
8482
8483 return 0;
8484}
8485
8486/*
8487 * This is a helper function for allocate_dir_block().
8488 */
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00008489static int update_dir_block(ext2_filsys fs FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008490 blk_t *block_nr,
8491 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00008492 blk_t ref_block FSCK_ATTR((unused)),
8493 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008494 void *priv_data)
8495{
8496 struct ext2_db_entry *db;
8497
8498 db = (struct ext2_db_entry *) priv_data;
8499 if (db->blockcnt == (int) blockcnt) {
8500 *block_nr = db->blk;
8501 return BLOCK_CHANGED;
8502 }
8503 return 0;
8504}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008505
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008506/*
8507 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
8508 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008509 * Pass #3 assures that all directories are connected to the
8510 * filesystem tree, using the following algorithm:
8511 *
8512 * First, the root directory is checked to make sure it exists; if
8513 * not, e2fsck will offer to create a new one. It is then marked as
8514 * "done".
8515 *
8516 * Then, pass3 interates over all directory inodes; for each directory
8517 * it attempts to trace up the filesystem tree, using dirinfo.parent
8518 * until it reaches a directory which has been marked "done". If it
8519 * can not do so, then the directory must be disconnected, and e2fsck
8520 * will offer to reconnect it to /lost+found. While it is chasing
8521 * parent pointers up the filesystem tree, if pass3 sees a directory
8522 * twice, then it has detected a filesystem loop, and it will again
8523 * offer to reconnect the directory to /lost+found in to break the
8524 * filesystem loop.
8525 *
8526 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
8527 * reconnect inodes to /lost+found; this subroutine is also used by
8528 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
8529 * is responsible for creating /lost+found if it does not exist.
8530 *
8531 * Pass 3 frees the following data structures:
8532 * - The dirinfo directory information cache.
8533 */
8534
8535static void check_root(e2fsck_t ctx);
8536static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8537 struct problem_context *pctx);
8538static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
8539
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008540static ext2fs_inode_bitmap inode_loop_detect;
8541static ext2fs_inode_bitmap inode_done_map;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008542
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008543static void e2fsck_pass3(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008544{
8545 ext2_filsys fs = ctx->fs;
8546 int i;
8547#ifdef RESOURCE_TRACK
8548 struct resource_track rtrack;
8549#endif
8550 struct problem_context pctx;
8551 struct dir_info *dir;
8552 unsigned long maxdirs, count;
8553
8554#ifdef RESOURCE_TRACK
8555 init_resource_track(&rtrack);
8556#endif
8557
8558 clear_problem_context(&pctx);
8559
8560#ifdef MTRACE
8561 mtrace_print("Pass 3");
8562#endif
8563
8564 if (!(ctx->options & E2F_OPT_PREEN))
8565 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
8566
8567 /*
8568 * Allocate some bitmaps to do loop detection.
8569 */
8570 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
8571 &inode_done_map);
8572 if (pctx.errcode) {
8573 pctx.num = 2;
8574 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
8575 ctx->flags |= E2F_FLAG_ABORT;
8576 goto abort_exit;
8577 }
8578#ifdef RESOURCE_TRACK
8579 if (ctx->options & E2F_OPT_TIME) {
8580 e2fsck_clear_progbar(ctx);
8581 print_resource_track(_("Peak memory"), &ctx->global_rtrack);
8582 }
8583#endif
8584
8585 check_root(ctx);
8586 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8587 goto abort_exit;
8588
8589 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
8590
8591 maxdirs = e2fsck_get_num_dirinfo(ctx);
8592 count = 1;
8593
8594 if (ctx->progress)
8595 if ((ctx->progress)(ctx, 3, 0, maxdirs))
8596 goto abort_exit;
8597
8598 for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
8599 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8600 goto abort_exit;
8601 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
8602 goto abort_exit;
8603 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
8604 if (check_directory(ctx, dir, &pctx))
8605 goto abort_exit;
8606 }
8607
8608 /*
8609 * Force the creation of /lost+found if not present
8610 */
8611 if ((ctx->flags & E2F_OPT_READONLY) == 0)
8612 e2fsck_get_lost_and_found(ctx, 1);
8613
8614 /*
8615 * If there are any directories that need to be indexed or
8616 * optimized, do it here.
8617 */
8618 e2fsck_rehash_directories(ctx);
8619
8620abort_exit:
8621 e2fsck_free_dir_info(ctx);
Rob Landleye7c43b62006-03-01 16:39:45 +00008622 ext2fs_free_inode_bitmap(inode_loop_detect);
8623 inode_loop_detect = 0;
8624 ext2fs_free_inode_bitmap(inode_done_map);
8625 inode_done_map = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008626
8627#ifdef RESOURCE_TRACK
8628 if (ctx->options & E2F_OPT_TIME2) {
8629 e2fsck_clear_progbar(ctx);
8630 print_resource_track(_("Pass 3"), &rtrack);
8631 }
8632#endif
8633}
8634
8635/*
8636 * This makes sure the root inode is present; if not, we ask if the
8637 * user wants us to create it. Not creating it is a fatal error.
8638 */
8639static void check_root(e2fsck_t ctx)
8640{
8641 ext2_filsys fs = ctx->fs;
8642 blk_t blk;
8643 struct ext2_inode inode;
8644 char * block;
8645 struct problem_context pctx;
8646
8647 clear_problem_context(&pctx);
8648
8649 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
8650 /*
8651 * If the root inode is not a directory, die here. The
8652 * user must have answered 'no' in pass1 when we
8653 * offered to clear it.
8654 */
8655 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8656 EXT2_ROOT_INO))) {
8657 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
8658 ctx->flags |= E2F_FLAG_ABORT;
8659 }
8660 return;
8661 }
8662
8663 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
8664 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
8665 ctx->flags |= E2F_FLAG_ABORT;
8666 return;
8667 }
8668
8669 e2fsck_read_bitmaps(ctx);
8670
8671 /*
8672 * First, find a free block
8673 */
8674 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8675 if (pctx.errcode) {
8676 pctx.str = "ext2fs_new_block";
8677 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8678 ctx->flags |= E2F_FLAG_ABORT;
8679 return;
8680 }
8681 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8682 ext2fs_mark_block_bitmap(fs->block_map, blk);
8683 ext2fs_mark_bb_dirty(fs);
8684
8685 /*
8686 * Now let's create the actual data block for the inode
8687 */
8688 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
8689 &block);
8690 if (pctx.errcode) {
8691 pctx.str = "ext2fs_new_dir_block";
8692 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8693 ctx->flags |= E2F_FLAG_ABORT;
8694 return;
8695 }
8696
8697 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
8698 if (pctx.errcode) {
8699 pctx.str = "ext2fs_write_dir_block";
8700 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8701 ctx->flags |= E2F_FLAG_ABORT;
8702 return;
8703 }
8704 ext2fs_free_mem(&block);
8705
8706 /*
8707 * Set up the inode structure
8708 */
8709 memset(&inode, 0, sizeof(inode));
8710 inode.i_mode = 040755;
8711 inode.i_size = fs->blocksize;
8712 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
8713 inode.i_links_count = 2;
8714 inode.i_blocks = fs->blocksize / 512;
8715 inode.i_block[0] = blk;
8716
8717 /*
8718 * Write out the inode.
8719 */
8720 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
8721 if (pctx.errcode) {
8722 pctx.str = "ext2fs_write_inode";
8723 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8724 ctx->flags |= E2F_FLAG_ABORT;
8725 return;
8726 }
8727
8728 /*
8729 * Miscellaneous bookkeeping...
8730 */
8731 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
8732 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
8733 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
8734
8735 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
8736 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
8737 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
8738 ext2fs_mark_ib_dirty(fs);
8739}
8740
8741/*
8742 * This subroutine is responsible for making sure that a particular
8743 * directory is connected to the root; if it isn't we trace it up as
8744 * far as we can go, and then offer to connect the resulting parent to
8745 * the lost+found. We have to do loop detection; if we ever discover
8746 * a loop, we treat that as a disconnected directory and offer to
8747 * reparent it to lost+found.
8748 *
8749 * However, loop detection is expensive, because for very large
8750 * filesystems, the inode_loop_detect bitmap is huge, and clearing it
8751 * is non-trivial. Loops in filesystems are also a rare error case,
8752 * and we shouldn't optimize for error cases. So we try two passes of
8753 * the algorithm. The first time, we ignore loop detection and merely
8754 * increment a counter; if the counter exceeds some extreme threshold,
8755 * then we try again with the loop detection bitmap enabled.
8756 */
8757static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8758 struct problem_context *pctx)
8759{
8760 ext2_filsys fs = ctx->fs;
8761 struct dir_info *p = dir;
8762 int loop_pass = 0, parent_count = 0;
8763
8764 if (!p)
8765 return 0;
8766
8767 while (1) {
8768 /*
8769 * Mark this inode as being "done"; by the time we
8770 * return from this function, the inode we either be
8771 * verified as being connected to the directory tree,
8772 * or we will have offered to reconnect this to
8773 * lost+found.
8774 *
8775 * If it was marked done already, then we've reached a
8776 * parent we've already checked.
8777 */
8778 if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
8779 break;
8780
8781 /*
8782 * If this directory doesn't have a parent, or we've
8783 * seen the parent once already, then offer to
8784 * reparent it to lost+found
8785 */
8786 if (!p->parent ||
8787 (loop_pass &&
8788 (ext2fs_test_inode_bitmap(inode_loop_detect,
8789 p->parent)))) {
8790 pctx->ino = p->ino;
8791 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
8792 if (e2fsck_reconnect_file(ctx, pctx->ino))
8793 ext2fs_unmark_valid(fs);
8794 else {
8795 p = e2fsck_get_dir_info(ctx, pctx->ino);
8796 p->parent = ctx->lost_and_found;
8797 fix_dotdot(ctx, p, ctx->lost_and_found);
8798 }
8799 }
8800 break;
8801 }
8802 p = e2fsck_get_dir_info(ctx, p->parent);
8803 if (!p) {
8804 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
8805 return 0;
8806 }
8807 if (loop_pass) {
8808 ext2fs_mark_inode_bitmap(inode_loop_detect,
8809 p->ino);
8810 } else if (parent_count++ > 2048) {
8811 /*
8812 * If we've run into a path depth that's
8813 * greater than 2048, try again with the inode
8814 * loop bitmap turned on and start from the
8815 * top.
8816 */
8817 loop_pass = 1;
8818 if (inode_loop_detect)
8819 ext2fs_clear_inode_bitmap(inode_loop_detect);
8820 else {
8821 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
8822 if (pctx->errcode) {
8823 pctx->num = 1;
8824 fix_problem(ctx,
8825 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
8826 ctx->flags |= E2F_FLAG_ABORT;
8827 return -1;
8828 }
8829 }
8830 p = dir;
8831 }
8832 }
8833
8834 /*
8835 * Make sure that .. and the parent directory are the same;
8836 * offer to fix it if not.
8837 */
8838 if (dir->parent != dir->dotdot) {
8839 pctx->ino = dir->ino;
8840 pctx->ino2 = dir->dotdot;
8841 pctx->dir = dir->parent;
8842 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
8843 fix_dotdot(ctx, dir, dir->parent);
8844 }
8845 return 0;
8846}
8847
8848/*
8849 * This routine gets the lost_and_found inode, making it a directory
8850 * if necessary
8851 */
8852ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
8853{
8854 ext2_filsys fs = ctx->fs;
8855 ext2_ino_t ino;
8856 blk_t blk;
8857 errcode_t retval;
8858 struct ext2_inode inode;
8859 char * block;
8860 static const char name[] = "lost+found";
8861 struct problem_context pctx;
8862 struct dir_info *dirinfo;
8863
8864 if (ctx->lost_and_found)
8865 return ctx->lost_and_found;
8866
8867 clear_problem_context(&pctx);
8868
8869 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
8870 sizeof(name)-1, 0, &ino);
8871 if (retval && !fix)
8872 return 0;
8873 if (!retval) {
8874 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
8875 ctx->lost_and_found = ino;
8876 return ino;
8877 }
8878
8879 /* Lost+found isn't a directory! */
8880 if (!fix)
8881 return 0;
8882 pctx.ino = ino;
8883 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
8884 return 0;
8885
8886 /* OK, unlink the old /lost+found file. */
8887 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
8888 if (pctx.errcode) {
8889 pctx.str = "ext2fs_unlink";
8890 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
8891 return 0;
8892 }
8893 dirinfo = e2fsck_get_dir_info(ctx, ino);
8894 if (dirinfo)
8895 dirinfo->parent = 0;
8896 e2fsck_adjust_inode_count(ctx, ino, -1);
8897 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
8898 pctx.errcode = retval;
8899 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
8900 }
8901 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
8902 return 0;
8903
8904 /*
8905 * Read the inode and block bitmaps in; we'll be messing with
8906 * them.
8907 */
8908 e2fsck_read_bitmaps(ctx);
8909
8910 /*
8911 * First, find a free block
8912 */
8913 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8914 if (retval) {
8915 pctx.errcode = retval;
8916 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
8917 return 0;
8918 }
8919 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8920 ext2fs_block_alloc_stats(fs, blk, +1);
8921
8922 /*
8923 * Next find a free inode.
8924 */
8925 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
8926 ctx->inode_used_map, &ino);
8927 if (retval) {
8928 pctx.errcode = retval;
8929 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
8930 return 0;
8931 }
8932 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
8933 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
8934 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
8935
8936 /*
8937 * Now let's create the actual data block for the inode
8938 */
8939 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
8940 if (retval) {
8941 pctx.errcode = retval;
8942 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
8943 return 0;
8944 }
8945
8946 retval = ext2fs_write_dir_block(fs, blk, block);
8947 ext2fs_free_mem(&block);
8948 if (retval) {
8949 pctx.errcode = retval;
8950 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
8951 return 0;
8952 }
8953
8954 /*
8955 * Set up the inode structure
8956 */
8957 memset(&inode, 0, sizeof(inode));
8958 inode.i_mode = 040700;
8959 inode.i_size = fs->blocksize;
8960 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
8961 inode.i_links_count = 2;
8962 inode.i_blocks = fs->blocksize / 512;
8963 inode.i_block[0] = blk;
8964
8965 /*
8966 * Next, write out the inode.
8967 */
8968 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
8969 if (pctx.errcode) {
8970 pctx.str = "ext2fs_write_inode";
8971 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
8972 return 0;
8973 }
8974 /*
8975 * Finally, create the directory link
8976 */
8977 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
8978 if (pctx.errcode) {
8979 pctx.str = "ext2fs_link";
8980 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
8981 return 0;
8982 }
8983
8984 /*
8985 * Miscellaneous bookkeeping that needs to be kept straight.
8986 */
8987 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
8988 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
8989 ext2fs_icount_store(ctx->inode_count, ino, 2);
8990 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
8991 ctx->lost_and_found = ino;
8992#if 0
8993 printf("/lost+found created; inode #%lu\n", ino);
8994#endif
8995 return ino;
8996}
8997
8998/*
8999 * This routine will connect a file to lost+found
9000 */
9001int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
9002{
9003 ext2_filsys fs = ctx->fs;
9004 errcode_t retval;
9005 char name[80];
9006 struct problem_context pctx;
9007 struct ext2_inode inode;
9008 int file_type = 0;
9009
9010 clear_problem_context(&pctx);
9011 pctx.ino = ino;
9012
9013 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
9014 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
9015 ctx->bad_lost_and_found++;
9016 }
9017 if (ctx->bad_lost_and_found) {
9018 fix_problem(ctx, PR_3_NO_LPF, &pctx);
9019 return 1;
9020 }
9021
9022 sprintf(name, "#%u", ino);
9023 if (ext2fs_read_inode(fs, ino, &inode) == 0)
9024 file_type = ext2_file_type(inode.i_mode);
9025 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
9026 if (retval == EXT2_ET_DIR_NO_SPACE) {
9027 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
9028 return 1;
9029 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
9030 1, 0);
9031 if (retval) {
9032 pctx.errcode = retval;
9033 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
9034 return 1;
9035 }
9036 retval = ext2fs_link(fs, ctx->lost_and_found, name,
9037 ino, file_type);
9038 }
9039 if (retval) {
9040 pctx.errcode = retval;
9041 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
9042 return 1;
9043 }
9044 e2fsck_adjust_inode_count(ctx, ino, 1);
9045
9046 return 0;
9047}
9048
9049/*
9050 * Utility routine to adjust the inode counts on an inode.
9051 */
9052errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
9053{
9054 ext2_filsys fs = ctx->fs;
9055 errcode_t retval;
9056 struct ext2_inode inode;
9057
9058 if (!ino)
9059 return 0;
9060
9061 retval = ext2fs_read_inode(fs, ino, &inode);
9062 if (retval)
9063 return retval;
9064
9065#if 0
9066 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
9067 inode.i_links_count);
9068#endif
9069
9070 if (adj == 1) {
9071 ext2fs_icount_increment(ctx->inode_count, ino, 0);
9072 if (inode.i_links_count == (__u16) ~0)
9073 return 0;
9074 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
9075 inode.i_links_count++;
9076 } else if (adj == -1) {
9077 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
9078 if (inode.i_links_count == 0)
9079 return 0;
9080 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
9081 inode.i_links_count--;
9082 }
9083
9084 retval = ext2fs_write_inode(fs, ino, &inode);
9085 if (retval)
9086 return retval;
9087
9088 return 0;
9089}
9090
9091/*
9092 * Fix parent --- this routine fixes up the parent of a directory.
9093 */
9094struct fix_dotdot_struct {
9095 ext2_filsys fs;
9096 ext2_ino_t parent;
9097 int done;
9098 e2fsck_t ctx;
9099};
9100
9101static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00009102 int offset FSCK_ATTR((unused)),
9103 int blocksize FSCK_ATTR((unused)),
9104 char *buf FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009105 void *priv_data)
9106{
9107 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
9108 errcode_t retval;
9109 struct problem_context pctx;
9110
9111 if ((dirent->name_len & 0xFF) != 2)
9112 return 0;
9113 if (strncmp(dirent->name, "..", 2))
9114 return 0;
9115
9116 clear_problem_context(&pctx);
9117
9118 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
9119 if (retval) {
9120 pctx.errcode = retval;
9121 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9122 }
9123 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
9124 if (retval) {
9125 pctx.errcode = retval;
9126 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9127 }
9128 dirent->inode = fp->parent;
9129
9130 fp->done++;
9131 return DIRENT_ABORT | DIRENT_CHANGED;
9132}
9133
9134static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
9135{
9136 ext2_filsys fs = ctx->fs;
9137 errcode_t retval;
9138 struct fix_dotdot_struct fp;
9139 struct problem_context pctx;
9140
9141 fp.fs = fs;
9142 fp.parent = parent;
9143 fp.done = 0;
9144 fp.ctx = ctx;
9145
9146#if 0
9147 printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent);
9148#endif
9149
9150 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
9151 0, fix_dotdot_proc, &fp);
9152 if (retval || !fp.done) {
9153 clear_problem_context(&pctx);
9154 pctx.ino = dir->ino;
9155 pctx.errcode = retval;
9156 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
9157 PR_3_FIX_PARENT_NOFIND, &pctx);
9158 ext2fs_unmark_valid(fs);
9159 }
9160 dir->dotdot = parent;
9161
9162 return;
9163}
9164
9165/*
9166 * These routines are responsible for expanding a /lost+found if it is
9167 * too small.
9168 */
9169
9170struct expand_dir_struct {
9171 int num;
9172 int guaranteed_size;
9173 int newblocks;
9174 int last_block;
9175 errcode_t err;
9176 e2fsck_t ctx;
9177};
9178
9179static int expand_dir_proc(ext2_filsys fs,
9180 blk_t *blocknr,
9181 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +00009182 blk_t ref_block FSCK_ATTR((unused)),
9183 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009184 void *priv_data)
9185{
9186 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
9187 blk_t new_blk;
9188 static blk_t last_blk = 0;
9189 char *block;
9190 errcode_t retval;
9191 e2fsck_t ctx;
9192
9193 ctx = es->ctx;
9194
9195 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
9196 return BLOCK_ABORT;
9197
9198 if (blockcnt > 0)
9199 es->last_block = blockcnt;
9200 if (*blocknr) {
9201 last_blk = *blocknr;
9202 return 0;
9203 }
9204 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
9205 &new_blk);
9206 if (retval) {
9207 es->err = retval;
9208 return BLOCK_ABORT;
9209 }
9210 if (blockcnt > 0) {
9211 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
9212 if (retval) {
9213 es->err = retval;
9214 return BLOCK_ABORT;
9215 }
9216 es->num--;
9217 retval = ext2fs_write_dir_block(fs, new_blk, block);
9218 } else {
9219 retval = ext2fs_get_mem(fs->blocksize, &block);
9220 if (retval) {
9221 es->err = retval;
9222 return BLOCK_ABORT;
9223 }
9224 memset(block, 0, fs->blocksize);
9225 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
9226 }
9227 if (retval) {
9228 es->err = retval;
9229 return BLOCK_ABORT;
9230 }
9231 ext2fs_free_mem(&block);
9232 *blocknr = new_blk;
9233 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
9234 ext2fs_block_alloc_stats(fs, new_blk, +1);
9235 es->newblocks++;
9236
9237 if (es->num == 0)
9238 return (BLOCK_CHANGED | BLOCK_ABORT);
9239 else
9240 return BLOCK_CHANGED;
9241}
9242
9243errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
9244 int num, int guaranteed_size)
9245{
9246 ext2_filsys fs = ctx->fs;
9247 errcode_t retval;
9248 struct expand_dir_struct es;
9249 struct ext2_inode inode;
9250
9251 if (!(fs->flags & EXT2_FLAG_RW))
9252 return EXT2_ET_RO_FILSYS;
9253
9254 /*
9255 * Read the inode and block bitmaps in; we'll be messing with
9256 * them.
9257 */
9258 e2fsck_read_bitmaps(ctx);
9259
9260 retval = ext2fs_check_directory(fs, dir);
9261 if (retval)
9262 return retval;
9263
9264 es.num = num;
9265 es.guaranteed_size = guaranteed_size;
9266 es.last_block = 0;
9267 es.err = 0;
9268 es.newblocks = 0;
9269 es.ctx = ctx;
9270
9271 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
9272 0, expand_dir_proc, &es);
9273
9274 if (es.err)
9275 return es.err;
9276
9277 /*
9278 * Update the size and block count fields in the inode.
9279 */
9280 retval = ext2fs_read_inode(fs, dir, &inode);
9281 if (retval)
9282 return retval;
9283
9284 inode.i_size = (es.last_block + 1) * fs->blocksize;
9285 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
9286
9287 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
9288
9289 return 0;
9290}
9291
9292/*
9293 * pass4.c -- pass #4 of e2fsck: Check reference counts
9294 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009295 * Pass 4 frees the following data structures:
9296 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
9297 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
9298 */
9299
9300/*
9301 * This routine is called when an inode is not connected to the
9302 * directory tree.
9303 *
9304 * This subroutine returns 1 then the caller shouldn't bother with the
9305 * rest of the pass 4 tests.
9306 */
9307static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
9308{
9309 ext2_filsys fs = ctx->fs;
9310 struct ext2_inode inode;
9311 struct problem_context pctx;
9312
9313 e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
9314 clear_problem_context(&pctx);
9315 pctx.ino = i;
9316 pctx.inode = &inode;
9317
9318 /*
9319 * Offer to delete any zero-length files that does not have
9320 * blocks. If there is an EA block, it might have useful
9321 * information, so we won't prompt to delete it, but let it be
9322 * reconnected to lost+found.
9323 */
9324 if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
9325 LINUX_S_ISDIR(inode.i_mode))) {
9326 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
9327 ext2fs_icount_store(ctx->inode_link_info, i, 0);
9328 inode.i_links_count = 0;
9329 inode.i_dtime = time(0);
9330 e2fsck_write_inode(ctx, i, &inode,
9331 "disconnect_inode");
9332 /*
9333 * Fix up the bitmaps...
9334 */
9335 e2fsck_read_bitmaps(ctx);
9336 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
9337 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
9338 ext2fs_inode_alloc_stats2(fs, i, -1,
9339 LINUX_S_ISDIR(inode.i_mode));
9340 return 0;
9341 }
9342 }
9343
9344 /*
9345 * Prompt to reconnect.
9346 */
9347 if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
9348 if (e2fsck_reconnect_file(ctx, i))
9349 ext2fs_unmark_valid(fs);
9350 } else {
9351 /*
9352 * If we don't attach the inode, then skip the
9353 * i_links_test since there's no point in trying to
9354 * force i_links_count to zero.
9355 */
9356 ext2fs_unmark_valid(fs);
9357 return 1;
9358 }
9359 return 0;
9360}
9361
9362
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009363static void e2fsck_pass4(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009364{
9365 ext2_filsys fs = ctx->fs;
9366 ext2_ino_t i;
9367 struct ext2_inode inode;
9368#ifdef RESOURCE_TRACK
9369 struct resource_track rtrack;
9370#endif
9371 struct problem_context pctx;
9372 __u16 link_count, link_counted;
9373 char *buf = 0;
9374 int group, maxgroup;
9375
9376#ifdef RESOURCE_TRACK
9377 init_resource_track(&rtrack);
9378#endif
9379
9380#ifdef MTRACE
9381 mtrace_print("Pass 4");
9382#endif
9383
9384 clear_problem_context(&pctx);
9385
9386 if (!(ctx->options & E2F_OPT_PREEN))
9387 fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
9388
9389 group = 0;
9390 maxgroup = fs->group_desc_count;
9391 if (ctx->progress)
9392 if ((ctx->progress)(ctx, 4, 0, maxgroup))
9393 return;
9394
9395 for (i=1; i <= fs->super->s_inodes_count; i++) {
9396 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9397 return;
9398 if ((i % fs->super->s_inodes_per_group) == 0) {
9399 group++;
9400 if (ctx->progress)
9401 if ((ctx->progress)(ctx, 4, group, maxgroup))
9402 return;
9403 }
9404 if (i == EXT2_BAD_INO ||
9405 (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
9406 continue;
9407 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
9408 (ctx->inode_imagic_map &&
9409 ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) ||
9410 (ctx->inode_bb_map &&
9411 ext2fs_test_inode_bitmap(ctx->inode_bb_map, i)))
9412 continue;
9413 ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
9414 ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
9415 if (link_counted == 0) {
9416 if (!buf)
9417 buf = e2fsck_allocate_memory(ctx,
9418 fs->blocksize, "bad_inode buffer");
9419 if (e2fsck_process_bad_inode(ctx, 0, i, buf))
9420 continue;
9421 if (disconnect_inode(ctx, i))
9422 continue;
9423 ext2fs_icount_fetch(ctx->inode_link_info, i,
9424 &link_count);
9425 ext2fs_icount_fetch(ctx->inode_count, i,
9426 &link_counted);
9427 }
9428 if (link_counted != link_count) {
9429 e2fsck_read_inode(ctx, i, &inode, "pass4");
9430 pctx.ino = i;
9431 pctx.inode = &inode;
9432 if (link_count != inode.i_links_count) {
9433 pctx.num = link_count;
9434 fix_problem(ctx,
9435 PR_4_INCONSISTENT_COUNT, &pctx);
9436 }
9437 pctx.num = link_counted;
9438 if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
9439 inode.i_links_count = link_counted;
9440 e2fsck_write_inode(ctx, i, &inode, "pass4");
9441 }
9442 }
9443 }
9444 ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
9445 ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
9446 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
9447 ctx->inode_bb_map = 0;
9448 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
9449 ctx->inode_imagic_map = 0;
Rob Landleye7c43b62006-03-01 16:39:45 +00009450 ext2fs_free_mem(&buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009451#ifdef RESOURCE_TRACK
9452 if (ctx->options & E2F_OPT_TIME2) {
9453 e2fsck_clear_progbar(ctx);
9454 print_resource_track(_("Pass 4"), &rtrack);
9455 }
9456#endif
9457}
9458
9459/*
9460 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009461 */
9462
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009463#define NO_BLK ((blk_t) -1)
9464
9465static void print_bitmap_problem(e2fsck_t ctx, int problem,
9466 struct problem_context *pctx)
9467{
9468 switch (problem) {
9469 case PR_5_BLOCK_UNUSED:
9470 if (pctx->blk == pctx->blk2)
9471 pctx->blk2 = 0;
9472 else
9473 problem = PR_5_BLOCK_RANGE_UNUSED;
9474 break;
9475 case PR_5_BLOCK_USED:
9476 if (pctx->blk == pctx->blk2)
9477 pctx->blk2 = 0;
9478 else
9479 problem = PR_5_BLOCK_RANGE_USED;
9480 break;
9481 case PR_5_INODE_UNUSED:
9482 if (pctx->ino == pctx->ino2)
9483 pctx->ino2 = 0;
9484 else
9485 problem = PR_5_INODE_RANGE_UNUSED;
9486 break;
9487 case PR_5_INODE_USED:
9488 if (pctx->ino == pctx->ino2)
9489 pctx->ino2 = 0;
9490 else
9491 problem = PR_5_INODE_RANGE_USED;
9492 break;
9493 }
9494 fix_problem(ctx, problem, pctx);
9495 pctx->blk = pctx->blk2 = NO_BLK;
9496 pctx->ino = pctx->ino2 = 0;
9497}
9498
9499static void check_block_bitmaps(e2fsck_t ctx)
9500{
9501 ext2_filsys fs = ctx->fs;
9502 blk_t i;
9503 int *free_array;
9504 int group = 0;
9505 unsigned int blocks = 0;
9506 unsigned int free_blocks = 0;
9507 int group_free = 0;
9508 int actual, bitmap;
9509 struct problem_context pctx;
9510 int problem, save_problem, fixit, had_problem;
9511 errcode_t retval;
9512
9513 clear_problem_context(&pctx);
9514 free_array = (int *) e2fsck_allocate_memory(ctx,
9515 fs->group_desc_count * sizeof(int), "free block count array");
9516
9517 if ((fs->super->s_first_data_block <
9518 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
9519 (fs->super->s_blocks_count-1 >
9520 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
9521 pctx.num = 1;
9522 pctx.blk = fs->super->s_first_data_block;
9523 pctx.blk2 = fs->super->s_blocks_count -1;
9524 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
9525 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
9526 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9527
9528 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9529 return;
9530 }
9531
9532 if ((fs->super->s_first_data_block <
9533 ext2fs_get_block_bitmap_start(fs->block_map)) ||
9534 (fs->super->s_blocks_count-1 >
9535 ext2fs_get_block_bitmap_end(fs->block_map))) {
9536 pctx.num = 2;
9537 pctx.blk = fs->super->s_first_data_block;
9538 pctx.blk2 = fs->super->s_blocks_count -1;
9539 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
9540 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
9541 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9542
9543 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9544 return;
9545 }
9546
9547redo_counts:
9548 had_problem = 0;
9549 save_problem = 0;
9550 pctx.blk = pctx.blk2 = NO_BLK;
9551 for (i = fs->super->s_first_data_block;
9552 i < fs->super->s_blocks_count;
9553 i++) {
9554 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
9555 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
9556
9557 if (actual == bitmap)
9558 goto do_counts;
9559
9560 if (!actual && bitmap) {
9561 /*
9562 * Block not used, but marked in use in the bitmap.
9563 */
9564 problem = PR_5_BLOCK_UNUSED;
9565 } else {
9566 /*
9567 * Block used, but not marked in use in the bitmap.
9568 */
9569 problem = PR_5_BLOCK_USED;
9570 }
9571 if (pctx.blk == NO_BLK) {
9572 pctx.blk = pctx.blk2 = i;
9573 save_problem = problem;
9574 } else {
9575 if ((problem == save_problem) &&
9576 (pctx.blk2 == i-1))
9577 pctx.blk2++;
9578 else {
9579 print_bitmap_problem(ctx, save_problem, &pctx);
9580 pctx.blk = pctx.blk2 = i;
9581 save_problem = problem;
9582 }
9583 }
9584 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
9585 had_problem++;
9586
9587 do_counts:
9588 if (!bitmap) {
9589 group_free++;
9590 free_blocks++;
9591 }
9592 blocks ++;
9593 if ((blocks == fs->super->s_blocks_per_group) ||
9594 (i == fs->super->s_blocks_count-1)) {
9595 free_array[group] = group_free;
9596 group ++;
9597 blocks = 0;
9598 group_free = 0;
9599 if (ctx->progress)
9600 if ((ctx->progress)(ctx, 5, group,
9601 fs->group_desc_count*2))
9602 return;
9603 }
9604 }
9605 if (pctx.blk != NO_BLK)
9606 print_bitmap_problem(ctx, save_problem, &pctx);
9607 if (had_problem)
9608 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
9609 else
9610 fixit = -1;
9611 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
9612
9613 if (fixit == 1) {
9614 ext2fs_free_block_bitmap(fs->block_map);
9615 retval = ext2fs_copy_bitmap(ctx->block_found_map,
9616 &fs->block_map);
9617 if (retval) {
9618 clear_problem_context(&pctx);
9619 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
9620 ctx->flags |= E2F_FLAG_ABORT;
9621 return;
9622 }
9623 ext2fs_set_bitmap_padding(fs->block_map);
9624 ext2fs_mark_bb_dirty(fs);
9625
9626 /* Redo the counts */
9627 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
9628 memset(free_array, 0, fs->group_desc_count * sizeof(int));
9629 goto redo_counts;
9630 } else if (fixit == 0)
9631 ext2fs_unmark_valid(fs);
9632
9633 for (i = 0; i < fs->group_desc_count; i++) {
9634 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
9635 pctx.group = i;
9636 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
9637 pctx.blk2 = free_array[i];
9638
9639 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
9640 &pctx)) {
9641 fs->group_desc[i].bg_free_blocks_count =
9642 free_array[i];
9643 ext2fs_mark_super_dirty(fs);
9644 } else
9645 ext2fs_unmark_valid(fs);
9646 }
9647 }
9648 if (free_blocks != fs->super->s_free_blocks_count) {
9649 pctx.group = 0;
9650 pctx.blk = fs->super->s_free_blocks_count;
9651 pctx.blk2 = free_blocks;
9652
9653 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
9654 fs->super->s_free_blocks_count = free_blocks;
9655 ext2fs_mark_super_dirty(fs);
9656 } else
9657 ext2fs_unmark_valid(fs);
9658 }
9659 ext2fs_free_mem(&free_array);
9660}
9661
9662static void check_inode_bitmaps(e2fsck_t ctx)
9663{
9664 ext2_filsys fs = ctx->fs;
9665 ext2_ino_t i;
9666 unsigned int free_inodes = 0;
9667 int group_free = 0;
9668 int dirs_count = 0;
9669 int group = 0;
9670 unsigned int inodes = 0;
9671 int *free_array;
9672 int *dir_array;
9673 int actual, bitmap;
9674 errcode_t retval;
9675 struct problem_context pctx;
9676 int problem, save_problem, fixit, had_problem;
9677
9678 clear_problem_context(&pctx);
9679 free_array = (int *) e2fsck_allocate_memory(ctx,
9680 fs->group_desc_count * sizeof(int), "free inode count array");
9681
9682 dir_array = (int *) e2fsck_allocate_memory(ctx,
9683 fs->group_desc_count * sizeof(int), "directory count array");
9684
9685 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
9686 (fs->super->s_inodes_count >
9687 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
9688 pctx.num = 3;
9689 pctx.blk = 1;
9690 pctx.blk2 = fs->super->s_inodes_count;
9691 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
9692 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
9693 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9694
9695 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9696 return;
9697 }
9698 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
9699 (fs->super->s_inodes_count >
9700 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
9701 pctx.num = 4;
9702 pctx.blk = 1;
9703 pctx.blk2 = fs->super->s_inodes_count;
9704 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
9705 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
9706 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9707
9708 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9709 return;
9710 }
9711
9712redo_counts:
9713 had_problem = 0;
9714 save_problem = 0;
9715 pctx.ino = pctx.ino2 = 0;
9716 for (i = 1; i <= fs->super->s_inodes_count; i++) {
9717 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
9718 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
9719
9720 if (actual == bitmap)
9721 goto do_counts;
9722
9723 if (!actual && bitmap) {
9724 /*
9725 * Inode wasn't used, but marked in bitmap
9726 */
9727 problem = PR_5_INODE_UNUSED;
9728 } else /* if (actual && !bitmap) */ {
9729 /*
9730 * Inode used, but not in bitmap
9731 */
9732 problem = PR_5_INODE_USED;
9733 }
9734 if (pctx.ino == 0) {
9735 pctx.ino = pctx.ino2 = i;
9736 save_problem = problem;
9737 } else {
9738 if ((problem == save_problem) &&
9739 (pctx.ino2 == i-1))
9740 pctx.ino2++;
9741 else {
9742 print_bitmap_problem(ctx, save_problem, &pctx);
9743 pctx.ino = pctx.ino2 = i;
9744 save_problem = problem;
9745 }
9746 }
9747 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
9748 had_problem++;
9749
9750do_counts:
9751 if (!bitmap) {
9752 group_free++;
9753 free_inodes++;
9754 } else {
9755 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
9756 dirs_count++;
9757 }
9758 inodes++;
9759 if ((inodes == fs->super->s_inodes_per_group) ||
9760 (i == fs->super->s_inodes_count)) {
9761 free_array[group] = group_free;
9762 dir_array[group] = dirs_count;
9763 group ++;
9764 inodes = 0;
9765 group_free = 0;
9766 dirs_count = 0;
9767 if (ctx->progress)
9768 if ((ctx->progress)(ctx, 5,
9769 group + fs->group_desc_count,
9770 fs->group_desc_count*2))
9771 return;
9772 }
9773 }
9774 if (pctx.ino)
9775 print_bitmap_problem(ctx, save_problem, &pctx);
9776
9777 if (had_problem)
9778 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
9779 else
9780 fixit = -1;
9781 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
9782
9783 if (fixit == 1) {
9784 ext2fs_free_inode_bitmap(fs->inode_map);
9785 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
9786 &fs->inode_map);
9787 if (retval) {
9788 clear_problem_context(&pctx);
9789 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
9790 ctx->flags |= E2F_FLAG_ABORT;
9791 return;
9792 }
9793 ext2fs_set_bitmap_padding(fs->inode_map);
9794 ext2fs_mark_ib_dirty(fs);
9795
9796 /* redo counts */
9797 inodes = 0; free_inodes = 0; group_free = 0;
9798 dirs_count = 0; group = 0;
9799 memset(free_array, 0, fs->group_desc_count * sizeof(int));
9800 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
9801 goto redo_counts;
9802 } else if (fixit == 0)
9803 ext2fs_unmark_valid(fs);
9804
9805 for (i = 0; i < fs->group_desc_count; i++) {
9806 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
9807 pctx.group = i;
9808 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
9809 pctx.ino2 = free_array[i];
9810 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
9811 &pctx)) {
9812 fs->group_desc[i].bg_free_inodes_count =
9813 free_array[i];
9814 ext2fs_mark_super_dirty(fs);
9815 } else
9816 ext2fs_unmark_valid(fs);
9817 }
9818 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
9819 pctx.group = i;
9820 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
9821 pctx.ino2 = dir_array[i];
9822
9823 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
9824 &pctx)) {
9825 fs->group_desc[i].bg_used_dirs_count =
9826 dir_array[i];
9827 ext2fs_mark_super_dirty(fs);
9828 } else
9829 ext2fs_unmark_valid(fs);
9830 }
9831 }
9832 if (free_inodes != fs->super->s_free_inodes_count) {
9833 pctx.group = -1;
9834 pctx.ino = fs->super->s_free_inodes_count;
9835 pctx.ino2 = free_inodes;
9836
9837 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
9838 fs->super->s_free_inodes_count = free_inodes;
9839 ext2fs_mark_super_dirty(fs);
9840 } else
9841 ext2fs_unmark_valid(fs);
9842 }
9843 ext2fs_free_mem(&free_array);
9844 ext2fs_free_mem(&dir_array);
9845}
9846
9847static void check_inode_end(e2fsck_t ctx)
9848{
9849 ext2_filsys fs = ctx->fs;
9850 ext2_ino_t end, save_inodes_count, i;
9851 struct problem_context pctx;
9852
9853 clear_problem_context(&pctx);
9854
9855 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
9856 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
9857 &save_inodes_count);
9858 if (pctx.errcode) {
9859 pctx.num = 1;
9860 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9861 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9862 return;
9863 }
9864 if (save_inodes_count == end)
9865 return;
9866
9867 for (i = save_inodes_count + 1; i <= end; i++) {
9868 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
9869 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
9870 for (i = save_inodes_count + 1; i <= end; i++)
9871 ext2fs_mark_inode_bitmap(fs->inode_map,
9872 i);
9873 ext2fs_mark_ib_dirty(fs);
9874 } else
9875 ext2fs_unmark_valid(fs);
9876 break;
9877 }
9878 }
9879
9880 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
9881 save_inodes_count, 0);
9882 if (pctx.errcode) {
9883 pctx.num = 2;
9884 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9885 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9886 return;
9887 }
9888}
9889
9890static void check_block_end(e2fsck_t ctx)
9891{
9892 ext2_filsys fs = ctx->fs;
9893 blk_t end, save_blocks_count, i;
9894 struct problem_context pctx;
9895
9896 clear_problem_context(&pctx);
9897
9898 end = fs->block_map->start +
9899 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
9900 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
9901 &save_blocks_count);
9902 if (pctx.errcode) {
9903 pctx.num = 3;
9904 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9905 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9906 return;
9907 }
9908 if (save_blocks_count == end)
9909 return;
9910
9911 for (i = save_blocks_count + 1; i <= end; i++) {
9912 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
9913 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
9914 for (i = save_blocks_count + 1; i <= end; i++)
9915 ext2fs_mark_block_bitmap(fs->block_map,
9916 i);
9917 ext2fs_mark_bb_dirty(fs);
9918 } else
9919 ext2fs_unmark_valid(fs);
9920 break;
9921 }
9922 }
9923
9924 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
9925 save_blocks_count, 0);
9926 if (pctx.errcode) {
9927 pctx.num = 4;
9928 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9929 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9930 return;
9931 }
9932}
9933
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009934static void e2fsck_pass5(e2fsck_t ctx)
9935{
9936#ifdef RESOURCE_TRACK
9937 struct resource_track rtrack;
9938#endif
9939 struct problem_context pctx;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009940
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009941#ifdef MTRACE
9942 mtrace_print("Pass 5");
9943#endif
9944
9945#ifdef RESOURCE_TRACK
9946 init_resource_track(&rtrack);
9947#endif
9948
9949 clear_problem_context(&pctx);
9950
9951 if (!(ctx->options & E2F_OPT_PREEN))
9952 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
9953
9954 if (ctx->progress)
9955 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
9956 return;
9957
9958 e2fsck_read_bitmaps(ctx);
9959
9960 check_block_bitmaps(ctx);
9961 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9962 return;
9963 check_inode_bitmaps(ctx);
9964 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9965 return;
9966 check_inode_end(ctx);
9967 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9968 return;
9969 check_block_end(ctx);
9970 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9971 return;
9972
9973 ext2fs_free_inode_bitmap(ctx->inode_used_map);
9974 ctx->inode_used_map = 0;
9975 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
9976 ctx->inode_dir_map = 0;
9977 ext2fs_free_block_bitmap(ctx->block_found_map);
9978 ctx->block_found_map = 0;
9979
9980#ifdef RESOURCE_TRACK
9981 if (ctx->options & E2F_OPT_TIME2) {
9982 e2fsck_clear_progbar(ctx);
9983 print_resource_track(_("Pass 5"), &rtrack);
9984 }
9985#endif
9986}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009987
9988/*
9989 * problem.c --- report filesystem problems to the user
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009990 */
9991
9992#define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */
9993#define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */
9994#define PR_NO_DEFAULT 0x000004 /* Default to no */
9995#define PR_MSG_ONLY 0x000008 /* Print message only */
9996
9997/* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */
9998
9999#define PR_FATAL 0x001000 /* Fatal error */
10000#define PR_AFTER_CODE 0x002000 /* After asking the first question, */
10001 /* ask another */
10002#define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */
10003#define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */
10004#define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */
10005#define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */
10006#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
10007
10008
10009#define PROMPT_NONE 0
10010#define PROMPT_FIX 1
10011#define PROMPT_CLEAR 2
10012#define PROMPT_RELOCATE 3
10013#define PROMPT_ALLOCATE 4
10014#define PROMPT_EXPAND 5
10015#define PROMPT_CONNECT 6
10016#define PROMPT_CREATE 7
10017#define PROMPT_SALVAGE 8
10018#define PROMPT_TRUNCATE 9
10019#define PROMPT_CLEAR_INODE 10
10020#define PROMPT_ABORT 11
10021#define PROMPT_SPLIT 12
10022#define PROMPT_CONTINUE 13
10023#define PROMPT_CLONE 14
10024#define PROMPT_DELETE 15
10025#define PROMPT_SUPPRESS 16
10026#define PROMPT_UNLINK 17
10027#define PROMPT_CLEAR_HTREE 18
10028#define PROMPT_RECREATE 19
10029#define PROMPT_NULL 20
10030
10031struct e2fsck_problem {
10032 problem_t e2p_code;
10033 const char * e2p_description;
10034 char prompt;
10035 int flags;
10036 problem_t second_code;
10037};
10038
10039struct latch_descr {
10040 int latch_code;
10041 problem_t question;
10042 problem_t end_message;
10043 int flags;
10044};
10045
10046/*
10047 * These are the prompts which are used to ask the user if they want
10048 * to fix a problem.
10049 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010050static const char * const prompt[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010051 N_("(no prompt)"), /* 0 */
10052 N_("Fix"), /* 1 */
10053 N_("Clear"), /* 2 */
10054 N_("Relocate"), /* 3 */
10055 N_("Allocate"), /* 4 */
10056 N_("Expand"), /* 5 */
10057 N_("Connect to /lost+found"), /* 6 */
10058 N_("Create"), /* 7 */
10059 N_("Salvage"), /* 8 */
10060 N_("Truncate"), /* 9 */
10061 N_("Clear inode"), /* 10 */
10062 N_("Abort"), /* 11 */
10063 N_("Split"), /* 12 */
10064 N_("Continue"), /* 13 */
Mike Frysinger874af852006-03-08 07:03:27 +000010065 N_("Clone multiply-claimed blocks"), /* 14 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010066 N_("Delete file"), /* 15 */
10067 N_("Suppress messages"),/* 16 */
10068 N_("Unlink"), /* 17 */
10069 N_("Clear HTree index"),/* 18 */
10070 N_("Recreate"), /* 19 */
10071 "", /* 20 */
10072};
10073
10074/*
10075 * These messages are printed when we are preen mode and we will be
10076 * automatically fixing the problem.
10077 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010078static const char * const preen_msg[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010079 N_("(NONE)"), /* 0 */
10080 N_("FIXED"), /* 1 */
10081 N_("CLEARED"), /* 2 */
10082 N_("RELOCATED"), /* 3 */
10083 N_("ALLOCATED"), /* 4 */
10084 N_("EXPANDED"), /* 5 */
10085 N_("RECONNECTED"), /* 6 */
10086 N_("CREATED"), /* 7 */
10087 N_("SALVAGED"), /* 8 */
10088 N_("TRUNCATED"), /* 9 */
10089 N_("INODE CLEARED"), /* 10 */
10090 N_("ABORTED"), /* 11 */
10091 N_("SPLIT"), /* 12 */
10092 N_("CONTINUING"), /* 13 */
Mike Frysinger874af852006-03-08 07:03:27 +000010093 N_("MULTIPLY-CLAIMED BLOCKS CLONED"), /* 14 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010094 N_("FILE DELETED"), /* 15 */
10095 N_("SUPPRESSED"), /* 16 */
10096 N_("UNLINKED"), /* 17 */
10097 N_("HTREE INDEX CLEARED"),/* 18 */
10098 N_("WILL RECREATE"), /* 19 */
10099 "", /* 20 */
10100};
10101
10102static const struct e2fsck_problem problem_table[] = {
10103
10104 /* Pre-Pass 1 errors */
10105
10106 /* Block bitmap not in group */
10107 { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
10108 PROMPT_RELOCATE, PR_LATCH_RELOC },
10109
10110 /* Inode bitmap not in group */
10111 { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
10112 PROMPT_RELOCATE, PR_LATCH_RELOC },
10113
10114 /* Inode table not in group */
10115 { PR_0_ITABLE_NOT_GROUP,
10116 N_("@i table for @g %g is not in @g. (@b %b)\n"
10117 "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
10118 PROMPT_RELOCATE, PR_LATCH_RELOC },
10119
10120 /* Superblock corrupt */
10121 { PR_0_SB_CORRUPT,
10122 N_("\nThe @S could not be read or does not describe a correct ext2\n"
10123 "@f. If the @v is valid and it really contains an ext2\n"
10124 "@f (and not swap or ufs or something else), then the @S\n"
10125 "is corrupt, and you might try running e2fsck with an alternate @S:\n"
10126 " e2fsck -b %S <@v>\n\n"),
10127 PROMPT_NONE, PR_FATAL },
10128
10129 /* Filesystem size is wrong */
10130 { PR_0_FS_SIZE_WRONG,
10131 N_("The @f size (according to the @S) is %b @bs\n"
10132 "The physical size of the @v is %c @bs\n"
10133 "Either the @S or the partition table is likely to be corrupt!\n"),
10134 PROMPT_ABORT, 0 },
10135
10136 /* Fragments not supported */
10137 { PR_0_NO_FRAGMENTS,
10138 N_("@S @b_size = %b, fragsize = %c.\n"
10139 "This version of e2fsck does not support fragment sizes different\n"
10140 "from the @b size.\n"),
10141 PROMPT_NONE, PR_FATAL },
10142
10143 /* Bad blocks_per_group */
10144 { PR_0_BLOCKS_PER_GROUP,
10145 N_("@S @bs_per_group = %b, should have been %c\n"),
10146 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10147
10148 /* Bad first_data_block */
10149 { PR_0_FIRST_DATA_BLOCK,
10150 N_("@S first_data_@b = %b, should have been %c\n"),
10151 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10152
10153 /* Adding UUID to filesystem */
10154 { PR_0_ADD_UUID,
10155 N_("@f did not have a UUID; generating one.\n\n"),
10156 PROMPT_NONE, 0 },
10157
10158 /* Relocate hint */
10159 { PR_0_RELOCATE_HINT,
Mike Frysinger874af852006-03-08 07:03:27 +000010160 N_("Note: if several inode or block bitmap blocks or part\n"
10161 "of the inode table require relocation, you may wish to try\n"
10162 "running e2fsck with the '-b %S' option first. The problem\n"
10163 "may lie only with the primary block group descriptors, and\n"
10164 "the backup block group descriptors may be OK.\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010165 PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
10166
10167 /* Miscellaneous superblock corruption */
10168 { PR_0_MISC_CORRUPT_SUPER,
10169 N_("Corruption found in @S. (%s = %N).\n"),
10170 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10171
10172 /* Error determing physical device size of filesystem */
10173 { PR_0_GETSIZE_ERROR,
10174 N_("Error determining size of the physical @v: %m\n"),
10175 PROMPT_NONE, PR_FATAL },
10176
10177 /* Inode count in superblock is incorrect */
10178 { PR_0_INODE_COUNT_WRONG,
Mike Frysinger874af852006-03-08 07:03:27 +000010179 N_("@i count in @S is %i, @s %j.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010180 PROMPT_FIX, 0 },
10181
10182 { PR_0_HURD_CLEAR_FILETYPE,
10183 N_("The Hurd does not support the filetype feature.\n"),
10184 PROMPT_CLEAR, 0 },
10185
10186 /* Journal inode is invalid */
10187 { PR_0_JOURNAL_BAD_INODE,
Mike Frysinger874af852006-03-08 07:03:27 +000010188 N_("@S has an @n ext3 @j (@i %i).\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010189 PROMPT_CLEAR, PR_PREEN_OK },
10190
10191 /* The external journal has (unsupported) multiple filesystems */
10192 { PR_0_JOURNAL_UNSUPP_MULTIFS,
10193 N_("External @j has multiple @f users (unsupported).\n"),
10194 PROMPT_NONE, PR_FATAL },
10195
10196 /* Can't find external journal */
10197 { PR_0_CANT_FIND_JOURNAL,
10198 N_("Can't find external @j\n"),
10199 PROMPT_NONE, PR_FATAL },
10200
10201 /* External journal has bad superblock */
10202 { PR_0_EXT_JOURNAL_BAD_SUPER,
10203 N_("External @j has bad @S\n"),
10204 PROMPT_NONE, PR_FATAL },
10205
10206 /* Superblock has a bad journal UUID */
10207 { PR_0_JOURNAL_BAD_UUID,
10208 N_("External @j does not support this @f\n"),
10209 PROMPT_NONE, PR_FATAL },
10210
10211 /* Journal has an unknown superblock type */
10212 { PR_0_JOURNAL_UNSUPP_SUPER,
10213 N_("Ext3 @j @S is unknown type %N (unsupported).\n"
10214 "It is likely that your copy of e2fsck is old and/or doesn't "
10215 "support this @j format.\n"
10216 "It is also possible the @j @S is corrupt.\n"),
10217 PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
10218
10219 /* Journal superblock is corrupt */
10220 { PR_0_JOURNAL_BAD_SUPER,
10221 N_("Ext3 @j @S is corrupt.\n"),
10222 PROMPT_FIX, PR_PREEN_OK },
10223
10224 /* Superblock flag should be cleared */
10225 { PR_0_JOURNAL_HAS_JOURNAL,
10226 N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
10227 PROMPT_CLEAR, PR_PREEN_OK },
10228
10229 /* Superblock flag is incorrect */
10230 { PR_0_JOURNAL_RECOVER_SET,
10231 N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
10232 PROMPT_CLEAR, PR_PREEN_OK },
10233
10234 /* Journal has data, but recovery flag is clear */
10235 { PR_0_JOURNAL_RECOVERY_CLEAR,
Mike Frysinger874af852006-03-08 07:03:27 +000010236 N_("ext3 recovery flag is clear, but @j has data.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010237 PROMPT_NONE, 0 },
10238
10239 /* Ask if we should clear the journal */
10240 { PR_0_JOURNAL_RESET_JOURNAL,
10241 N_("Clear @j"),
10242 PROMPT_NULL, PR_PREEN_NOMSG },
10243
10244 /* Ask if we should run the journal anyway */
10245 { PR_0_JOURNAL_RUN,
10246 N_("Run @j anyway"),
10247 PROMPT_NULL, 0 },
10248
10249 /* Run the journal by default */
10250 { PR_0_JOURNAL_RUN_DEFAULT,
10251 N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
10252 PROMPT_NONE, 0 },
10253
10254 /* Clearing orphan inode */
10255 { PR_0_ORPHAN_CLEAR_INODE,
10256 N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
10257 PROMPT_NONE, 0 },
10258
10259 /* Illegal block found in orphaned inode */
10260 { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
10261 N_("@I @b #%B (%b) found in @o @i %i.\n"),
10262 PROMPT_NONE, 0 },
10263
10264 /* Already cleared block found in orphaned inode */
10265 { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
10266 N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
10267 PROMPT_NONE, 0 },
10268
10269 /* Illegal orphan inode in superblock */
10270 { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
10271 N_("@I @o @i %i in @S.\n"),
10272 PROMPT_NONE, 0 },
10273
10274 /* Illegal inode in orphaned inode list */
10275 { PR_0_ORPHAN_ILLEGAL_INODE,
10276 N_("@I @i %i in @o @i list.\n"),
10277 PROMPT_NONE, 0 },
10278
10279 /* Filesystem revision is 0, but feature flags are set */
10280 { PR_0_FS_REV_LEVEL,
Mike Frysinger874af852006-03-08 07:03:27 +000010281 N_("@f has feature flag(s) set, but is a revision 0 @f. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010282 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10283
10284 /* Journal superblock has an unknown read-only feature flag set */
10285 { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
10286 N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
10287 PROMPT_ABORT, 0 },
10288
10289 /* Journal superblock has an unknown incompatible feature flag set */
10290 { PR_0_JOURNAL_UNSUPP_INCOMPAT,
10291 N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
10292 PROMPT_ABORT, 0 },
10293
10294 /* Journal has unsupported version number */
10295 { PR_0_JOURNAL_UNSUPP_VERSION,
10296 N_("@j version not supported by this e2fsck.\n"),
10297 PROMPT_ABORT, 0 },
10298
10299 /* Moving journal to hidden file */
10300 { PR_0_MOVE_JOURNAL,
Mike Frysinger874af852006-03-08 07:03:27 +000010301 N_("Moving @j from /%s to hidden @i.\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010302 PROMPT_NONE, 0 },
10303
10304 /* Error moving journal to hidden file */
10305 { PR_0_ERR_MOVE_JOURNAL,
10306 N_("Error moving @j: %m\n\n"),
10307 PROMPT_NONE, 0 },
10308
10309 /* Clearing V2 journal superblock */
10310 { PR_0_CLEAR_V2_JOURNAL,
Mike Frysinger874af852006-03-08 07:03:27 +000010311 N_("Found @n V2 @j @S fields (from V1 @j).\n"
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010312 "Clearing fields beyond the V1 @j @S...\n\n"),
10313 PROMPT_NONE, 0 },
10314
10315 /* Backup journal inode blocks */
10316 { PR_0_BACKUP_JNL,
10317 N_("Backing up @j @i @b information.\n\n"),
10318 PROMPT_NONE, 0 },
10319
10320 /* Reserved blocks w/o resize_inode */
10321 { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
10322 N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
10323 "is %N; @s zero. "),
10324 PROMPT_FIX, 0 },
10325
10326 /* Resize_inode not enabled, but resize inode is non-zero */
10327 { PR_0_CLEAR_RESIZE_INODE,
Mike Frysinger874af852006-03-08 07:03:27 +000010328 N_("Resize_@i not enabled, but the resize @i is non-zero. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010329 PROMPT_CLEAR, 0 },
10330
10331 /* Resize inode invalid */
10332 { PR_0_RESIZE_INODE_INVALID,
10333 N_("Resize @i not valid. "),
10334 PROMPT_RECREATE, 0 },
10335
10336 /* Pass 1 errors */
10337
10338 /* Pass 1: Checking inodes, blocks, and sizes */
10339 { PR_1_PASS_HEADER,
10340 N_("Pass 1: Checking @is, @bs, and sizes\n"),
10341 PROMPT_NONE, 0 },
10342
10343 /* Root directory is not an inode */
10344 { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
10345 PROMPT_CLEAR, 0 },
10346
10347 /* Root directory has dtime set */
10348 { PR_1_ROOT_DTIME,
10349 N_("@r has dtime set (probably due to old mke2fs). "),
10350 PROMPT_FIX, PR_PREEN_OK },
10351
10352 /* Reserved inode has bad mode */
10353 { PR_1_RESERVED_BAD_MODE,
Mike Frysinger874af852006-03-08 07:03:27 +000010354 N_("Reserved @i %i (%Q) has @n mode. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010355 PROMPT_CLEAR, PR_PREEN_OK },
10356
10357 /* Deleted inode has zero dtime */
10358 { PR_1_ZERO_DTIME,
10359 N_("@D @i %i has zero dtime. "),
10360 PROMPT_FIX, PR_PREEN_OK },
10361
10362 /* Inode in use, but dtime set */
10363 { PR_1_SET_DTIME,
10364 N_("@i %i is in use, but has dtime set. "),
10365 PROMPT_FIX, PR_PREEN_OK },
10366
10367 /* Zero-length directory */
10368 { PR_1_ZERO_LENGTH_DIR,
10369 N_("@i %i is a @z @d. "),
10370 PROMPT_CLEAR, PR_PREEN_OK },
10371
10372 /* Block bitmap conflicts with some other fs block */
10373 { PR_1_BB_CONFLICT,
10374 N_("@g %g's @b @B at %b @C.\n"),
10375 PROMPT_RELOCATE, 0 },
10376
10377 /* Inode bitmap conflicts with some other fs block */
10378 { PR_1_IB_CONFLICT,
10379 N_("@g %g's @i @B at %b @C.\n"),
10380 PROMPT_RELOCATE, 0 },
10381
10382 /* Inode table conflicts with some other fs block */
10383 { PR_1_ITABLE_CONFLICT,
10384 N_("@g %g's @i table at %b @C.\n"),
10385 PROMPT_RELOCATE, 0 },
10386
10387 /* Block bitmap is on a bad block */
10388 { PR_1_BB_BAD_BLOCK,
10389 N_("@g %g's @b @B (%b) is bad. "),
10390 PROMPT_RELOCATE, 0 },
10391
10392 /* Inode bitmap is on a bad block */
10393 { PR_1_IB_BAD_BLOCK,
10394 N_("@g %g's @i @B (%b) is bad. "),
10395 PROMPT_RELOCATE, 0 },
10396
10397 /* Inode has incorrect i_size */
10398 { PR_1_BAD_I_SIZE,
10399 N_("@i %i, i_size is %Is, @s %N. "),
10400 PROMPT_FIX, PR_PREEN_OK },
10401
10402 /* Inode has incorrect i_blocks */
10403 { PR_1_BAD_I_BLOCKS,
10404 N_("@i %i, i_@bs is %Ib, @s %N. "),
10405 PROMPT_FIX, PR_PREEN_OK },
10406
10407 /* Illegal blocknumber in inode */
10408 { PR_1_ILLEGAL_BLOCK_NUM,
10409 N_("@I @b #%B (%b) in @i %i. "),
10410 PROMPT_CLEAR, PR_LATCH_BLOCK },
10411
10412 /* Block number overlaps fs metadata */
10413 { PR_1_BLOCK_OVERLAPS_METADATA,
10414 N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
10415 PROMPT_CLEAR, PR_LATCH_BLOCK },
10416
10417 /* Inode has illegal blocks (latch question) */
10418 { PR_1_INODE_BLOCK_LATCH,
10419 N_("@i %i has illegal @b(s). "),
10420 PROMPT_CLEAR, 0 },
10421
10422 /* Too many bad blocks in inode */
10423 { PR_1_TOO_MANY_BAD_BLOCKS,
10424 N_("Too many illegal @bs in @i %i.\n"),
10425 PROMPT_CLEAR_INODE, PR_NO_OK },
10426
10427 /* Illegal block number in bad block inode */
10428 { PR_1_BB_ILLEGAL_BLOCK_NUM,
10429 N_("@I @b #%B (%b) in bad @b @i. "),
10430 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10431
10432 /* Bad block inode has illegal blocks (latch question) */
10433 { PR_1_INODE_BBLOCK_LATCH,
10434 N_("Bad @b @i has illegal @b(s). "),
10435 PROMPT_CLEAR, 0 },
10436
10437 /* Duplicate or bad blocks in use! */
10438 { PR_1_DUP_BLOCKS_PREENSTOP,
10439 N_("Duplicate or bad @b in use!\n"),
10440 PROMPT_NONE, 0 },
10441
10442 /* Bad block used as bad block indirect block */
10443 { PR_1_BBINODE_BAD_METABLOCK,
10444 N_("Bad @b %b used as bad @b @i indirect @b. "),
10445 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10446
10447 /* Inconsistency can't be fixed prompt */
10448 { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
10449 N_("\nThe bad @b @i has probably been corrupted. You probably\n"
10450 "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
10451 "in the @f.\n"),
10452 PROMPT_CONTINUE, PR_PREEN_NOMSG },
10453
10454 /* Bad primary block */
10455 { PR_1_BAD_PRIMARY_BLOCK,
10456 N_("\nIf the @b is really bad, the @f can not be fixed.\n"),
10457 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
10458
10459 /* Bad primary block prompt */
10460 { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
Mike Frysinger874af852006-03-08 07:03:27 +000010461 N_("You can remove this @b from the bad @b list and hope\n"
10462 "that the @b is really OK. But there are no guarantees.\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010463 PROMPT_CLEAR, PR_PREEN_NOMSG },
10464
10465 /* Bad primary superblock */
10466 { PR_1_BAD_PRIMARY_SUPERBLOCK,
10467 N_("The primary @S (%b) is on the bad @b list.\n"),
10468 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10469
10470 /* Bad primary block group descriptors */
10471 { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
10472 N_("Block %b in the primary @g descriptors "
10473 "is on the bad @b list\n"),
10474 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10475
10476 /* Bad superblock in group */
10477 { PR_1_BAD_SUPERBLOCK,
10478 N_("Warning: Group %g's @S (%b) is bad.\n"),
10479 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10480
10481 /* Bad block group descriptors in group */
10482 { PR_1_BAD_GROUP_DESCRIPTORS,
10483 N_("Warning: Group %g's copy of the @g descriptors has a bad "
10484 "@b (%b).\n"),
10485 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10486
10487 /* Block claimed for no reason */
10488 { PR_1_PROGERR_CLAIMED_BLOCK,
10489 N_("Programming error? @b #%b claimed for no reason in "
10490 "process_bad_@b.\n"),
10491 PROMPT_NONE, PR_PREEN_OK },
10492
10493 /* Error allocating blocks for relocating metadata */
10494 { PR_1_RELOC_BLOCK_ALLOCATE,
10495 N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
10496 PROMPT_NONE, PR_PREEN_OK },
10497
10498 /* Error allocating block buffer during relocation process */
10499 { PR_1_RELOC_MEMORY_ALLOCATE,
10500 N_("@A @b buffer for relocating %s\n"),
10501 PROMPT_NONE, PR_PREEN_OK },
10502
10503 /* Relocating metadata group information from X to Y */
10504 { PR_1_RELOC_FROM_TO,
10505 N_("Relocating @g %g's %s from %b to %c...\n"),
10506 PROMPT_NONE, PR_PREEN_OK },
10507
10508 /* Relocating metatdata group information to X */
10509 { PR_1_RELOC_TO,
10510 N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
10511 PROMPT_NONE, PR_PREEN_OK },
10512
10513 /* Block read error during relocation process */
10514 { PR_1_RELOC_READ_ERR,
10515 N_("Warning: could not read @b %b of %s: %m\n"),
10516 PROMPT_NONE, PR_PREEN_OK },
10517
10518 /* Block write error during relocation process */
10519 { PR_1_RELOC_WRITE_ERR,
10520 N_("Warning: could not write @b %b for %s: %m\n"),
10521 PROMPT_NONE, PR_PREEN_OK },
10522
10523 /* Error allocating inode bitmap */
10524 { PR_1_ALLOCATE_IBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +000010525 N_("@A @i @B (%N): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010526 PROMPT_NONE, PR_FATAL },
10527
10528 /* Error allocating block bitmap */
10529 { PR_1_ALLOCATE_BBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +000010530 N_("@A @b @B (%N): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010531 PROMPT_NONE, PR_FATAL },
10532
10533 /* Error allocating icount structure */
10534 { PR_1_ALLOCATE_ICOUNT,
10535 N_("@A icount link information: %m\n"),
10536 PROMPT_NONE, PR_FATAL },
10537
10538 /* Error allocating dbcount */
10539 { PR_1_ALLOCATE_DBCOUNT,
10540 N_("@A @d @b array: %m\n"),
10541 PROMPT_NONE, PR_FATAL },
10542
10543 /* Error while scanning inodes */
10544 { PR_1_ISCAN_ERROR,
10545 N_("Error while scanning @is (%i): %m\n"),
10546 PROMPT_NONE, PR_FATAL },
10547
10548 /* Error while iterating over blocks */
10549 { PR_1_BLOCK_ITERATE,
10550 N_("Error while iterating over @bs in @i %i: %m\n"),
10551 PROMPT_NONE, PR_FATAL },
10552
10553 /* Error while storing inode count information */
10554 { PR_1_ICOUNT_STORE,
10555 N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
10556 PROMPT_NONE, PR_FATAL },
10557
10558 /* Error while storing directory block information */
10559 { PR_1_ADD_DBLOCK,
10560 N_("Error storing @d @b information "
10561 "(@i=%i, @b=%b, num=%N): %m\n"),
10562 PROMPT_NONE, PR_FATAL },
10563
10564 /* Error while reading inode (for clearing) */
10565 { PR_1_READ_INODE,
10566 N_("Error reading @i %i: %m\n"),
10567 PROMPT_NONE, PR_FATAL },
10568
10569 /* Suppress messages prompt */
10570 { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
10571
10572 /* Imagic flag set on an inode when filesystem doesn't support it */
10573 { PR_1_SET_IMAGIC,
10574 N_("@i %i has imagic flag set. "),
10575 PROMPT_CLEAR, 0 },
10576
10577 /* Immutable flag set on a device or socket inode */
10578 { PR_1_SET_IMMUTABLE,
10579 N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
10580 "or append-only flag set. "),
10581 PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
10582
10583 /* Compression flag set on an inode when filesystem doesn't support it */
10584 { PR_1_COMPR_SET,
10585 N_("@i %i has @cion flag set on @f without @cion support. "),
10586 PROMPT_CLEAR, 0 },
10587
10588 /* Non-zero size for device, fifo or socket inode */
10589 { PR_1_SET_NONZSIZE,
Mike Frysinger874af852006-03-08 07:03:27 +000010590 N_("Special (@v/socket/fifo) @i %i has non-zero size. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010591 PROMPT_FIX, PR_PREEN_OK },
10592
10593 /* Filesystem revision is 0, but feature flags are set */
10594 { PR_1_FS_REV_LEVEL,
Mike Frysinger874af852006-03-08 07:03:27 +000010595 N_("@f has feature flag(s) set, but is a revision 0 @f. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010596 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10597
10598 /* Journal inode is not in use, but contains data */
10599 { PR_1_JOURNAL_INODE_NOT_CLEAR,
Mike Frysinger874af852006-03-08 07:03:27 +000010600 N_("@j @i is not in use, but contains data. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010601 PROMPT_CLEAR, PR_PREEN_OK },
10602
10603 /* Journal has bad mode */
10604 { PR_1_JOURNAL_BAD_MODE,
10605 N_("@j is not regular file. "),
10606 PROMPT_FIX, PR_PREEN_OK },
10607
10608 /* Deal with inodes that were part of orphan linked list */
10609 { PR_1_LOW_DTIME,
Mike Frysinger874af852006-03-08 07:03:27 +000010610 N_("@i %i was part of the @o @i list. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010611 PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
10612
10613 /* Deal with inodes that were part of corrupted orphan linked
10614 list (latch question) */
10615 { PR_1_ORPHAN_LIST_REFUGEES,
10616 N_("@is that were part of a corrupted orphan linked list found. "),
10617 PROMPT_FIX, 0 },
10618
10619 /* Error allocating refcount structure */
10620 { PR_1_ALLOCATE_REFCOUNT,
Mike Frysinger874af852006-03-08 07:03:27 +000010621 N_("@A refcount structure (%N): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010622 PROMPT_NONE, PR_FATAL },
10623
10624 /* Error reading extended attribute block */
10625 { PR_1_READ_EA_BLOCK,
10626 N_("Error reading @a @b %b for @i %i. "),
10627 PROMPT_CLEAR, 0 },
10628
10629 /* Invalid extended attribute block */
10630 { PR_1_BAD_EA_BLOCK,
10631 N_("@i %i has a bad @a @b %b. "),
10632 PROMPT_CLEAR, 0 },
10633
10634 /* Error reading Extended Attribute block while fixing refcount */
10635 { PR_1_EXTATTR_READ_ABORT,
10636 N_("Error reading @a @b %b (%m). "),
10637 PROMPT_ABORT, 0 },
10638
10639 /* Extended attribute reference count incorrect */
10640 { PR_1_EXTATTR_REFCOUNT,
Mike Frysinger874af852006-03-08 07:03:27 +000010641 N_("@a @b %b has reference count %B, @s %N. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010642 PROMPT_FIX, 0 },
10643
10644 /* Error writing Extended Attribute block while fixing refcount */
10645 { PR_1_EXTATTR_WRITE,
10646 N_("Error writing @a @b %b (%m). "),
10647 PROMPT_ABORT, 0 },
10648
10649 /* Multiple EA blocks not supported */
10650 { PR_1_EA_MULTI_BLOCK,
Mike Frysinger874af852006-03-08 07:03:27 +000010651 N_("@a @b %b has h_@bs > 1. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010652 PROMPT_CLEAR, 0},
10653
10654 /* Error allocating EA region allocation structure */
10655 { PR_1_EA_ALLOC_REGION,
Mike Frysinger874af852006-03-08 07:03:27 +000010656 N_("@A @a @b %b. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010657 PROMPT_ABORT, 0},
10658
10659 /* Error EA allocation collision */
10660 { PR_1_EA_ALLOC_COLLISION,
10661 N_("@a @b %b is corrupt (allocation collision). "),
10662 PROMPT_CLEAR, 0},
10663
10664 /* Bad extended attribute name */
10665 { PR_1_EA_BAD_NAME,
Mike Frysinger874af852006-03-08 07:03:27 +000010666 N_("@a @b %b is corrupt (@n name). "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010667 PROMPT_CLEAR, 0},
10668
10669 /* Bad extended attribute value */
10670 { PR_1_EA_BAD_VALUE,
Mike Frysinger874af852006-03-08 07:03:27 +000010671 N_("@a @b %b is corrupt (@n value). "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010672 PROMPT_CLEAR, 0},
10673
10674 /* Inode too big (latch question) */
10675 { PR_1_INODE_TOOBIG,
10676 N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
10677
10678 /* Directory too big */
10679 { PR_1_TOOBIG_DIR,
10680 N_("@b #%B (%b) causes @d to be too big. "),
10681 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10682
10683 /* Regular file too big */
10684 { PR_1_TOOBIG_REG,
10685 N_("@b #%B (%b) causes file to be too big. "),
10686 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10687
10688 /* Symlink too big */
10689 { PR_1_TOOBIG_SYMLINK,
10690 N_("@b #%B (%b) causes symlink to be too big. "),
10691 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10692
10693 /* INDEX_FL flag set on a non-HTREE filesystem */
10694 { PR_1_HTREE_SET,
10695 N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
10696 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10697
10698 /* INDEX_FL flag set on a non-directory */
10699 { PR_1_HTREE_NODIR,
10700 N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
10701 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10702
10703 /* Invalid root node in HTREE directory */
10704 { PR_1_HTREE_BADROOT,
Mike Frysinger874af852006-03-08 07:03:27 +000010705 N_("@h %i has an @n root node.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010706 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10707
10708 /* Unsupported hash version in HTREE directory */
10709 { PR_1_HTREE_HASHV,
10710 N_("@h %i has an unsupported hash version (%N)\n"),
10711 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10712
10713 /* Incompatible flag in HTREE root node */
10714 { PR_1_HTREE_INCOMPAT,
10715 N_("@h %i uses an incompatible htree root node flag.\n"),
10716 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10717
10718 /* HTREE too deep */
10719 { PR_1_HTREE_DEPTH,
10720 N_("@h %i has a tree depth (%N) which is too big\n"),
10721 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10722
10723 /* Bad block has indirect block that conflicts with filesystem block */
10724 { PR_1_BB_FS_BLOCK,
10725 N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
10726 "@f metadata. "),
10727 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10728
10729 /* Resize inode failed */
10730 { PR_1_RESIZE_INODE_CREATE,
10731 N_("Resize @i (re)creation failed: %m."),
10732 PROMPT_ABORT, 0 },
10733
10734 /* invalid inode->i_extra_isize */
10735 { PR_1_EXTRA_ISIZE,
Mike Frysinger874af852006-03-08 07:03:27 +000010736 N_("@i %i has a extra size (%IS) which is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010737 PROMPT_FIX, PR_PREEN_OK },
10738
10739 /* invalid ea entry->e_name_len */
10740 { PR_1_ATTR_NAME_LEN,
Mike Frysinger874af852006-03-08 07:03:27 +000010741 N_("@a in @i %i has a namelen (%N) which is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010742 PROMPT_CLEAR, PR_PREEN_OK },
10743
10744 /* invalid ea entry->e_value_size */
10745 { PR_1_ATTR_VALUE_SIZE,
Mike Frysinger874af852006-03-08 07:03:27 +000010746 N_("@a in @i %i has a value size (%N) which is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010747 PROMPT_CLEAR, PR_PREEN_OK },
10748
10749 /* invalid ea entry->e_value_offs */
10750 { PR_1_ATTR_VALUE_OFFSET,
Mike Frysinger874af852006-03-08 07:03:27 +000010751 N_("@a in @i %i has a value offset (%N) which is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010752 PROMPT_CLEAR, PR_PREEN_OK },
10753
10754 /* invalid ea entry->e_value_block */
10755 { PR_1_ATTR_VALUE_BLOCK,
Mike Frysinger874af852006-03-08 07:03:27 +000010756 N_("@a in @i %i has a value @b (%N) which is @n (must be 0)\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010757 PROMPT_CLEAR, PR_PREEN_OK },
10758
10759 /* invalid ea entry->e_hash */
10760 { PR_1_ATTR_HASH,
Mike Frysinger874af852006-03-08 07:03:27 +000010761 N_("@a in @i %i has a hash (%N) which is @n (must be 0)\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010762 PROMPT_CLEAR, PR_PREEN_OK },
10763
10764 /* Pass 1b errors */
10765
10766 /* Pass 1B: Rescan for duplicate/bad blocks */
10767 { PR_1B_PASS_HEADER,
Mike Frysinger874af852006-03-08 07:03:27 +000010768 N_("\nRunning additional passes to resolve @bs claimed by more than one @i...\n"
10769 "Pass 1B: Rescanning for @m @bs\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010770 PROMPT_NONE, 0 },
10771
10772 /* Duplicate/bad block(s) header */
10773 { PR_1B_DUP_BLOCK_HEADER,
Mike Frysinger874af852006-03-08 07:03:27 +000010774 N_("@m @b(s) in @i %i:"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010775 PROMPT_NONE, 0 },
10776
10777 /* Duplicate/bad block(s) in inode */
10778 { PR_1B_DUP_BLOCK,
10779 " %b",
10780 PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
10781
10782 /* Duplicate/bad block(s) end */
10783 { PR_1B_DUP_BLOCK_END,
10784 "\n",
10785 PROMPT_NONE, PR_PREEN_NOHDR },
10786
10787 /* Error while scanning inodes */
10788 { PR_1B_ISCAN_ERROR,
10789 N_("Error while scanning inodes (%i): %m\n"),
10790 PROMPT_NONE, PR_FATAL },
10791
10792 /* Error allocating inode bitmap */
10793 { PR_1B_ALLOCATE_IBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +000010794 N_("@A @i @B (@i_dup_map): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010795 PROMPT_NONE, PR_FATAL },
10796
10797 /* Error while iterating over blocks */
10798 { PR_1B_BLOCK_ITERATE,
10799 N_("Error while iterating over @bs in @i %i (%s): %m\n"),
10800 PROMPT_NONE, 0 },
10801
10802 /* Error adjusting EA refcount */
10803 { PR_1B_ADJ_EA_REFCOUNT,
Mike Frysinger874af852006-03-08 07:03:27 +000010804 N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010805 PROMPT_NONE, 0 },
10806
10807
Mike Frysinger874af852006-03-08 07:03:27 +000010808 /* Pass 1C: Scan directories for inodes with multiply-claimed blocks. */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010809 { PR_1C_PASS_HEADER,
Mike Frysinger874af852006-03-08 07:03:27 +000010810 N_("Pass 1C: Scanning directories for @is with @m @bs.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010811 PROMPT_NONE, 0 },
10812
10813
Mike Frysinger874af852006-03-08 07:03:27 +000010814 /* Pass 1D: Reconciling multiply-claimed blocks */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010815 { PR_1D_PASS_HEADER,
Mike Frysinger874af852006-03-08 07:03:27 +000010816 N_("Pass 1D: Reconciling @m @bs\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010817 PROMPT_NONE, 0 },
10818
10819 /* File has duplicate blocks */
10820 { PR_1D_DUP_FILE,
10821 N_("File %Q (@i #%i, mod time %IM) \n"
Mike Frysinger874af852006-03-08 07:03:27 +000010822 " has %B @m @b(s), shared with %N file(s):\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010823 PROMPT_NONE, 0 },
10824
10825 /* List of files sharing duplicate blocks */
10826 { PR_1D_DUP_FILE_LIST,
10827 N_("\t%Q (@i #%i, mod time %IM)\n"),
10828 PROMPT_NONE, 0 },
10829
10830 /* File sharing blocks with filesystem metadata */
10831 { PR_1D_SHARE_METADATA,
10832 N_("\t<@f metadata>\n"),
10833 PROMPT_NONE, 0 },
10834
10835 /* Report of how many duplicate/bad inodes */
10836 { PR_1D_NUM_DUP_INODES,
Mike Frysinger874af852006-03-08 07:03:27 +000010837 N_("(There are %N @is containing @m @bs.)\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010838 PROMPT_NONE, 0 },
10839
10840 /* Duplicated blocks already reassigned or cloned. */
10841 { PR_1D_DUP_BLOCKS_DEALT,
Mike Frysinger874af852006-03-08 07:03:27 +000010842 N_("@m @bs already reassigned or cloned.\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010843 PROMPT_NONE, 0 },
10844
10845 /* Clone duplicate/bad blocks? */
10846 { PR_1D_CLONE_QUESTION,
10847 "", PROMPT_CLONE, PR_NO_OK },
10848
10849 /* Delete file? */
10850 { PR_1D_DELETE_QUESTION,
10851 "", PROMPT_DELETE, 0 },
10852
10853 /* Couldn't clone file (error) */
10854 { PR_1D_CLONE_ERROR,
10855 N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
10856
10857 /* Pass 2 errors */
10858
10859 /* Pass 2: Checking directory structure */
10860 { PR_2_PASS_HEADER,
10861 N_("Pass 2: Checking @d structure\n"),
10862 PROMPT_NONE, 0 },
10863
10864 /* Bad inode number for '.' */
10865 { PR_2_BAD_INODE_DOT,
Mike Frysinger874af852006-03-08 07:03:27 +000010866 N_("@n @i number for '.' in @d @i %i.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010867 PROMPT_FIX, 0 },
10868
10869 /* Directory entry has bad inode number */
10870 { PR_2_BAD_INO,
Mike Frysinger874af852006-03-08 07:03:27 +000010871 N_("@E has @n @i #: %Di.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010872 PROMPT_CLEAR, 0 },
10873
10874 /* Directory entry has deleted or unused inode */
10875 { PR_2_UNUSED_INODE,
10876 N_("@E has @D/unused @i %Di. "),
10877 PROMPT_CLEAR, PR_PREEN_OK },
10878
10879 /* Directry entry is link to '.' */
10880 { PR_2_LINK_DOT,
10881 N_("@E @L to '.' "),
10882 PROMPT_CLEAR, 0 },
10883
10884 /* Directory entry points to inode now located in a bad block */
10885 { PR_2_BB_INODE,
10886 N_("@E points to @i (%Di) located in a bad @b.\n"),
10887 PROMPT_CLEAR, 0 },
10888
10889 /* Directory entry contains a link to a directory */
10890 { PR_2_LINK_DIR,
10891 N_("@E @L to @d %P (%Di).\n"),
10892 PROMPT_CLEAR, 0 },
10893
10894 /* Directory entry contains a link to the root directry */
10895 { PR_2_LINK_ROOT,
10896 N_("@E @L to the @r.\n"),
10897 PROMPT_CLEAR, 0 },
10898
10899 /* Directory entry has illegal characters in its name */
10900 { PR_2_BAD_NAME,
10901 N_("@E has illegal characters in its name.\n"),
10902 PROMPT_FIX, 0 },
10903
10904 /* Missing '.' in directory inode */
10905 { PR_2_MISSING_DOT,
10906 N_("Missing '.' in @d @i %i.\n"),
10907 PROMPT_FIX, 0 },
10908
10909 /* Missing '..' in directory inode */
10910 { PR_2_MISSING_DOT_DOT,
10911 N_("Missing '..' in @d @i %i.\n"),
10912 PROMPT_FIX, 0 },
10913
10914 /* First entry in directory inode doesn't contain '.' */
10915 { PR_2_1ST_NOT_DOT,
Mike Frysinger874af852006-03-08 07:03:27 +000010916 N_("First @e '%Dn' (@i=%Di) in @d @i %i (%p) @s '.'\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010917 PROMPT_FIX, 0 },
10918
10919 /* Second entry in directory inode doesn't contain '..' */
10920 { PR_2_2ND_NOT_DOT_DOT,
Mike Frysinger874af852006-03-08 07:03:27 +000010921 N_("Second @e '%Dn' (@i=%Di) in @d @i %i @s '..'\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010922 PROMPT_FIX, 0 },
10923
10924 /* i_faddr should be zero */
10925 { PR_2_FADDR_ZERO,
10926 N_("i_faddr @F %IF, @s zero.\n"),
10927 PROMPT_CLEAR, 0 },
10928
10929 /* i_file_acl should be zero */
10930 { PR_2_FILE_ACL_ZERO,
10931 N_("i_file_acl @F %If, @s zero.\n"),
10932 PROMPT_CLEAR, 0 },
10933
10934 /* i_dir_acl should be zero */
10935 { PR_2_DIR_ACL_ZERO,
10936 N_("i_dir_acl @F %Id, @s zero.\n"),
10937 PROMPT_CLEAR, 0 },
10938
10939 /* i_frag should be zero */
10940 { PR_2_FRAG_ZERO,
10941 N_("i_frag @F %N, @s zero.\n"),
10942 PROMPT_CLEAR, 0 },
10943
10944 /* i_fsize should be zero */
10945 { PR_2_FSIZE_ZERO,
10946 N_("i_fsize @F %N, @s zero.\n"),
10947 PROMPT_CLEAR, 0 },
10948
10949 /* inode has bad mode */
10950 { PR_2_BAD_MODE,
Mike Frysinger874af852006-03-08 07:03:27 +000010951 N_("@i %i (%Q) has @n mode (%Im).\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010952 PROMPT_CLEAR, 0 },
10953
10954 /* directory corrupted */
10955 { PR_2_DIR_CORRUPTED,
10956 N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
10957 PROMPT_SALVAGE, 0 },
10958
10959 /* filename too long */
10960 { PR_2_FILENAME_LONG,
10961 N_("@d @i %i, @b %B, offset %N: filename too long\n"),
10962 PROMPT_TRUNCATE, 0 },
10963
10964 /* Directory inode has a missing block (hole) */
10965 { PR_2_DIRECTORY_HOLE,
10966 N_("@d @i %i has an unallocated @b #%B. "),
10967 PROMPT_ALLOCATE, 0 },
10968
10969 /* '.' is not NULL terminated */
10970 { PR_2_DOT_NULL_TERM,
10971 N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
10972 PROMPT_FIX, 0 },
10973
10974 /* '..' is not NULL terminated */
10975 { PR_2_DOT_DOT_NULL_TERM,
10976 N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
10977 PROMPT_FIX, 0 },
10978
10979 /* Illegal character device inode */
10980 { PR_2_BAD_CHAR_DEV,
10981 N_("@i %i (%Q) is an @I character @v.\n"),
10982 PROMPT_CLEAR, 0 },
10983
10984 /* Illegal block device inode */
10985 { PR_2_BAD_BLOCK_DEV,
10986 N_("@i %i (%Q) is an @I @b @v.\n"),
10987 PROMPT_CLEAR, 0 },
10988
10989 /* Duplicate '.' entry */
10990 { PR_2_DUP_DOT,
10991 N_("@E is duplicate '.' @e.\n"),
10992 PROMPT_FIX, 0 },
10993
10994 /* Duplicate '..' entry */
10995 { PR_2_DUP_DOT_DOT,
10996 N_("@E is duplicate '..' @e.\n"),
10997 PROMPT_FIX, 0 },
10998
10999 /* Internal error: couldn't find dir_info */
11000 { PR_2_NO_DIRINFO,
11001 N_("Internal error: couldn't find dir_info for %i.\n"),
11002 PROMPT_NONE, PR_FATAL },
11003
11004 /* Final rec_len is wrong */
11005 { PR_2_FINAL_RECLEN,
Mike Frysinger874af852006-03-08 07:03:27 +000011006 N_("@E has rec_len of %Dr, @s %N.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011007 PROMPT_FIX, 0 },
11008
11009 /* Error allocating icount structure */
11010 { PR_2_ALLOCATE_ICOUNT,
11011 N_("@A icount structure: %m\n"),
11012 PROMPT_NONE, PR_FATAL },
11013
11014 /* Error iterating over directory blocks */
11015 { PR_2_DBLIST_ITERATE,
11016 N_("Error iterating over @d @bs: %m\n"),
11017 PROMPT_NONE, PR_FATAL },
11018
11019 /* Error reading directory block */
11020 { PR_2_READ_DIRBLOCK,
11021 N_("Error reading @d @b %b (@i %i): %m\n"),
11022 PROMPT_CONTINUE, 0 },
11023
11024 /* Error writing directory block */
11025 { PR_2_WRITE_DIRBLOCK,
11026 N_("Error writing @d @b %b (@i %i): %m\n"),
11027 PROMPT_CONTINUE, 0 },
11028
11029 /* Error allocating new directory block */
11030 { PR_2_ALLOC_DIRBOCK,
11031 N_("@A new @d @b for @i %i (%s): %m\n"),
11032 PROMPT_NONE, 0 },
11033
11034 /* Error deallocating inode */
11035 { PR_2_DEALLOC_INODE,
11036 N_("Error deallocating @i %i: %m\n"),
11037 PROMPT_NONE, PR_FATAL },
11038
11039 /* Directory entry for '.' is big. Split? */
11040 { PR_2_SPLIT_DOT,
11041 N_("@d @e for '.' is big. "),
11042 PROMPT_SPLIT, PR_NO_OK },
11043
11044 /* Illegal FIFO inode */
11045 { PR_2_BAD_FIFO,
11046 N_("@i %i (%Q) is an @I FIFO.\n"),
11047 PROMPT_CLEAR, 0 },
11048
11049 /* Illegal socket inode */
11050 { PR_2_BAD_SOCKET,
11051 N_("@i %i (%Q) is an @I socket.\n"),
11052 PROMPT_CLEAR, 0 },
11053
11054 /* Directory filetype not set */
11055 { PR_2_SET_FILETYPE,
11056 N_("Setting filetype for @E to %N.\n"),
11057 PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
11058
11059 /* Directory filetype incorrect */
11060 { PR_2_BAD_FILETYPE,
Mike Frysinger874af852006-03-08 07:03:27 +000011061 N_("@E has an incorrect filetype (was %Dt, @s %N).\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011062 PROMPT_FIX, 0 },
11063
11064 /* Directory filetype set on filesystem */
11065 { PR_2_CLEAR_FILETYPE,
11066 N_("@E has filetype set.\n"),
11067 PROMPT_CLEAR, PR_PREEN_OK },
11068
11069 /* Directory filename is null */
11070 { PR_2_NULL_NAME,
Mike Frysinger874af852006-03-08 07:03:27 +000011071 N_("@E has a @z name.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011072 PROMPT_CLEAR, 0 },
11073
11074 /* Invalid symlink */
11075 { PR_2_INVALID_SYMLINK,
Mike Frysinger874af852006-03-08 07:03:27 +000011076 N_("Symlink %Q (@i #%i) is @n.\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011077 PROMPT_CLEAR, 0 },
11078
11079 /* i_file_acl (extended attribute block) is bad */
11080 { PR_2_FILE_ACL_BAD,
Mike Frysinger874af852006-03-08 07:03:27 +000011081 N_("@a @b @F @n (%If).\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011082 PROMPT_CLEAR, 0 },
11083
11084 /* Filesystem contains large files, but has no such flag in sb */
11085 { PR_2_FEATURE_LARGE_FILES,
11086 N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
11087 PROMPT_FIX, 0 },
11088
11089 /* Node in HTREE directory not referenced */
11090 { PR_2_HTREE_NOTREF,
11091 N_("@p @h %d: node (%B) not referenced\n"),
11092 PROMPT_NONE, 0 },
11093
11094 /* Node in HTREE directory referenced twice */
11095 { PR_2_HTREE_DUPREF,
11096 N_("@p @h %d: node (%B) referenced twice\n"),
11097 PROMPT_NONE, 0 },
11098
11099 /* Node in HTREE directory has bad min hash */
11100 { PR_2_HTREE_MIN_HASH,
11101 N_("@p @h %d: node (%B) has bad min hash\n"),
11102 PROMPT_NONE, 0 },
11103
11104 /* Node in HTREE directory has bad max hash */
11105 { PR_2_HTREE_MAX_HASH,
11106 N_("@p @h %d: node (%B) has bad max hash\n"),
11107 PROMPT_NONE, 0 },
11108
11109 /* Clear invalid HTREE directory */
11110 { PR_2_HTREE_CLEAR,
Mike Frysinger874af852006-03-08 07:03:27 +000011111 N_("@n @h %d (%q). "), PROMPT_CLEAR, 0 },
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011112
11113 /* Bad block in htree interior node */
11114 { PR_2_HTREE_BADBLK,
11115 N_("@p @h %d (%q): bad @b number %b.\n"),
11116 PROMPT_CLEAR_HTREE, 0 },
11117
11118 /* Error adjusting EA refcount */
11119 { PR_2_ADJ_EA_REFCOUNT,
Mike Frysinger874af852006-03-08 07:03:27 +000011120 N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011121 PROMPT_NONE, PR_FATAL },
11122
11123 /* Invalid HTREE root node */
11124 { PR_2_HTREE_BAD_ROOT,
Mike Frysinger874af852006-03-08 07:03:27 +000011125 N_("@p @h %d: root node is @n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011126 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11127
11128 /* Invalid HTREE limit */
11129 { PR_2_HTREE_BAD_LIMIT,
Mike Frysinger874af852006-03-08 07:03:27 +000011130 N_("@p @h %d: node (%B) has @n limit (%N)\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011131 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11132
11133 /* Invalid HTREE count */
11134 { PR_2_HTREE_BAD_COUNT,
Mike Frysinger874af852006-03-08 07:03:27 +000011135 N_("@p @h %d: node (%B) has @n count (%N)\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011136 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11137
11138 /* HTREE interior node has out-of-order hashes in table */
11139 { PR_2_HTREE_HASH_ORDER,
11140 N_("@p @h %d: node (%B) has an unordered hash table\n"),
11141 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11142
Mike Frysinger874af852006-03-08 07:03:27 +000011143 /* Node in HTREE directory has invalid depth */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011144 { PR_2_HTREE_BAD_DEPTH,
Mike Frysinger874af852006-03-08 07:03:27 +000011145 N_("@p @h %d: node (%B) has @n depth\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011146 PROMPT_NONE, 0 },
11147
11148 /* Duplicate directory entry found */
11149 { PR_2_DUPLICATE_DIRENT,
11150 N_("Duplicate @E found. "),
11151 PROMPT_CLEAR, 0 },
11152
11153 /* Non-unique filename found */
11154 { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
11155 N_("@E has a non-unique filename.\nRename to %s"),
11156 PROMPT_NULL, 0 },
11157
11158 /* Duplicate directory entry found */
11159 { PR_2_REPORT_DUP_DIRENT,
11160 N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
11161 PROMPT_NONE, 0 },
11162
11163 /* Pass 3 errors */
11164
11165 /* Pass 3: Checking directory connectivity */
11166 { PR_3_PASS_HEADER,
11167 N_("Pass 3: Checking @d connectivity\n"),
11168 PROMPT_NONE, 0 },
11169
11170 /* Root inode not allocated */
11171 { PR_3_NO_ROOT_INODE,
11172 N_("@r not allocated. "),
11173 PROMPT_ALLOCATE, 0 },
11174
11175 /* No room in lost+found */
11176 { PR_3_EXPAND_LF_DIR,
11177 N_("No room in @l @d. "),
11178 PROMPT_EXPAND, 0 },
11179
11180 /* Unconnected directory inode */
11181 { PR_3_UNCONNECTED_DIR,
11182 N_("Unconnected @d @i %i (%p)\n"),
11183 PROMPT_CONNECT, 0 },
11184
11185 /* /lost+found not found */
11186 { PR_3_NO_LF_DIR,
11187 N_("/@l not found. "),
11188 PROMPT_CREATE, PR_PREEN_OK },
11189
11190 /* .. entry is incorrect */
11191 { PR_3_BAD_DOT_DOT,
11192 N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
11193 PROMPT_FIX, 0 },
11194
11195 /* Bad or non-existent /lost+found. Cannot reconnect */
11196 { PR_3_NO_LPF,
11197 N_("Bad or non-existent /@l. Cannot reconnect.\n"),
11198 PROMPT_NONE, 0 },
11199
11200 /* Could not expand /lost+found */
11201 { PR_3_CANT_EXPAND_LPF,
11202 N_("Could not expand /@l: %m\n"),
11203 PROMPT_NONE, 0 },
11204
11205 /* Could not reconnect inode */
11206 { PR_3_CANT_RECONNECT,
11207 N_("Could not reconnect %i: %m\n"),
11208 PROMPT_NONE, 0 },
11209
11210 /* Error while trying to find /lost+found */
11211 { PR_3_ERR_FIND_LPF,
11212 N_("Error while trying to find /@l: %m\n"),
11213 PROMPT_NONE, 0 },
11214
11215 /* Error in ext2fs_new_block while creating /lost+found */
11216 { PR_3_ERR_LPF_NEW_BLOCK,
11217 N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
11218 PROMPT_NONE, 0 },
11219
11220 /* Error in ext2fs_new_inode while creating /lost+found */
11221 { PR_3_ERR_LPF_NEW_INODE,
11222 N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
11223 PROMPT_NONE, 0 },
11224
11225 /* Error in ext2fs_new_dir_block while creating /lost+found */
11226 { PR_3_ERR_LPF_NEW_DIR_BLOCK,
11227 N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
11228 PROMPT_NONE, 0 },
11229
11230 /* Error while writing directory block for /lost+found */
11231 { PR_3_ERR_LPF_WRITE_BLOCK,
11232 N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
11233 PROMPT_NONE, 0 },
11234
11235 /* Error while adjusting inode count */
11236 { PR_3_ADJUST_INODE,
11237 N_("Error while adjusting @i count on @i %i\n"),
11238 PROMPT_NONE, 0 },
11239
11240 /* Couldn't fix parent directory -- error */
11241 { PR_3_FIX_PARENT_ERR,
11242 N_("Couldn't fix parent of @i %i: %m\n\n"),
11243 PROMPT_NONE, 0 },
11244
11245 /* Couldn't fix parent directory -- couldn't find it */
11246 { PR_3_FIX_PARENT_NOFIND,
Mike Frysinger874af852006-03-08 07:03:27 +000011247 N_("Couldn't fix parent of @i %i: Couldn't find parent @d @e\n\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011248 PROMPT_NONE, 0 },
11249
11250 /* Error allocating inode bitmap */
11251 { PR_3_ALLOCATE_IBITMAP_ERROR,
11252 N_("@A @i @B (%N): %m\n"),
11253 PROMPT_NONE, PR_FATAL },
11254
11255 /* Error creating root directory */
11256 { PR_3_CREATE_ROOT_ERROR,
11257 N_("Error creating root @d (%s): %m\n"),
11258 PROMPT_NONE, PR_FATAL },
11259
11260 /* Error creating lost and found directory */
11261 { PR_3_CREATE_LPF_ERROR,
11262 N_("Error creating /@l @d (%s): %m\n"),
11263 PROMPT_NONE, PR_FATAL },
11264
11265 /* Root inode is not directory; aborting */
11266 { PR_3_ROOT_NOT_DIR_ABORT,
11267 N_("@r is not a @d; aborting.\n"),
11268 PROMPT_NONE, PR_FATAL },
11269
11270 /* Cannot proceed without a root inode. */
11271 { PR_3_NO_ROOT_INODE_ABORT,
11272 N_("Cannot proceed without a @r.\n"),
11273 PROMPT_NONE, PR_FATAL },
11274
11275 /* Internal error: couldn't find dir_info */
11276 { PR_3_NO_DIRINFO,
11277 N_("Internal error: couldn't find dir_info for %i.\n"),
11278 PROMPT_NONE, PR_FATAL },
11279
11280 /* Lost+found not a directory */
11281 { PR_3_LPF_NOTDIR,
11282 N_("/@l is not a @d (ino=%i)\n"),
11283 PROMPT_UNLINK, 0 },
11284
11285 /* Pass 3A Directory Optimization */
11286
11287 /* Pass 3A: Optimizing directories */
11288 { PR_3A_PASS_HEADER,
11289 N_("Pass 3A: Optimizing directories\n"),
11290 PROMPT_NONE, PR_PREEN_NOMSG },
11291
11292 /* Error iterating over directories */
11293 { PR_3A_OPTIMIZE_ITER,
11294 N_("Failed to create dirs_to_hash iterator: %m"),
11295 PROMPT_NONE, 0 },
11296
11297 /* Error rehash directory */
11298 { PR_3A_OPTIMIZE_DIR_ERR,
11299 N_("Failed to optimize directory %q (%d): %m"),
11300 PROMPT_NONE, 0 },
11301
11302 /* Rehashing dir header */
11303 { PR_3A_OPTIMIZE_DIR_HEADER,
11304 N_("Optimizing directories: "),
11305 PROMPT_NONE, PR_MSG_ONLY },
11306
11307 /* Rehashing directory %d */
11308 { PR_3A_OPTIMIZE_DIR,
11309 " %d",
11310 PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
11311
11312 /* Rehashing dir end */
11313 { PR_3A_OPTIMIZE_DIR_END,
11314 "\n",
11315 PROMPT_NONE, PR_PREEN_NOHDR },
11316
11317 /* Pass 4 errors */
11318
11319 /* Pass 4: Checking reference counts */
11320 { PR_4_PASS_HEADER,
11321 N_("Pass 4: Checking reference counts\n"),
11322 PROMPT_NONE, 0 },
11323
11324 /* Unattached zero-length inode */
11325 { PR_4_ZERO_LEN_INODE,
Mike Frysinger874af852006-03-08 07:03:27 +000011326 N_("@u @z @i %i. "),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011327 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
11328
11329 /* Unattached inode */
11330 { PR_4_UNATTACHED_INODE,
Mike Frysinger874af852006-03-08 07:03:27 +000011331 N_("@u @i %i\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011332 PROMPT_CONNECT, 0 },
11333
11334 /* Inode ref count wrong */
11335 { PR_4_BAD_REF_COUNT,
11336 N_("@i %i ref count is %Il, @s %N. "),
11337 PROMPT_FIX, PR_PREEN_OK },
11338
11339 { PR_4_INCONSISTENT_COUNT,
11340 N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
11341 "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
11342 "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
Mike Frysinger874af852006-03-08 07:03:27 +000011343 "They @s the same!\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011344 PROMPT_NONE, 0 },
11345
11346 /* Pass 5 errors */
11347
11348 /* Pass 5: Checking group summary information */
11349 { PR_5_PASS_HEADER,
11350 N_("Pass 5: Checking @g summary information\n"),
11351 PROMPT_NONE, 0 },
11352
11353 /* Padding at end of inode bitmap is not set. */
11354 { PR_5_INODE_BMAP_PADDING,
11355 N_("Padding at end of @i @B is not set. "),
11356 PROMPT_FIX, PR_PREEN_OK },
11357
11358 /* Padding at end of block bitmap is not set. */
11359 { PR_5_BLOCK_BMAP_PADDING,
11360 N_("Padding at end of @b @B is not set. "),
11361 PROMPT_FIX, PR_PREEN_OK },
11362
11363 /* Block bitmap differences header */
11364 { PR_5_BLOCK_BITMAP_HEADER,
11365 N_("@b @B differences: "),
11366 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
11367
11368 /* Block not used, but marked in bitmap */
11369 { PR_5_BLOCK_UNUSED,
11370 " -%b",
11371 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11372
11373 /* Block used, but not marked used in bitmap */
11374 { PR_5_BLOCK_USED,
11375 " +%b",
11376 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11377
11378 /* Block bitmap differences end */
11379 { PR_5_BLOCK_BITMAP_END,
11380 "\n",
11381 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11382
11383 /* Inode bitmap differences header */
11384 { PR_5_INODE_BITMAP_HEADER,
11385 N_("@i @B differences: "),
11386 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
11387
11388 /* Inode not used, but marked in bitmap */
11389 { PR_5_INODE_UNUSED,
11390 " -%i",
11391 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11392
11393 /* Inode used, but not marked used in bitmap */
11394 { PR_5_INODE_USED,
11395 " +%i",
11396 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11397
11398 /* Inode bitmap differences end */
11399 { PR_5_INODE_BITMAP_END,
11400 "\n",
11401 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11402
11403 /* Free inodes count for group wrong */
11404 { PR_5_FREE_INODE_COUNT_GROUP,
11405 N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
11406 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11407
11408 /* Directories count for group wrong */
11409 { PR_5_FREE_DIR_COUNT_GROUP,
11410 N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
11411 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11412
11413 /* Free inodes count wrong */
11414 { PR_5_FREE_INODE_COUNT,
11415 N_("Free @is count wrong (%i, counted=%j).\n"),
11416 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11417
11418 /* Free blocks count for group wrong */
11419 { PR_5_FREE_BLOCK_COUNT_GROUP,
11420 N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
11421 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11422
11423 /* Free blocks count wrong */
11424 { PR_5_FREE_BLOCK_COUNT,
11425 N_("Free @bs count wrong (%b, counted=%c).\n"),
11426 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11427
11428 /* Programming error: bitmap endpoints don't match */
11429 { PR_5_BMAP_ENDPOINTS,
11430 N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
11431 "match calculated @B endpoints (%i, %j)\n"),
11432 PROMPT_NONE, PR_FATAL },
11433
11434 /* Internal error: fudging end of bitmap */
11435 { PR_5_FUDGE_BITMAP_ERROR,
11436 N_("Internal error: fudging end of bitmap (%N)\n"),
11437 PROMPT_NONE, PR_FATAL },
11438
11439 /* Error copying in replacement inode bitmap */
11440 { PR_5_COPY_IBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +000011441 N_("Error copying in replacement @i @B: %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011442 PROMPT_NONE, PR_FATAL },
11443
11444 /* Error copying in replacement block bitmap */
11445 { PR_5_COPY_BBITMAP_ERROR,
Mike Frysinger874af852006-03-08 07:03:27 +000011446 N_("Error copying in replacement @b @B: %m\n"),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011447 PROMPT_NONE, PR_FATAL },
11448
11449 /* Block range not used, but marked in bitmap */
11450 { PR_5_BLOCK_RANGE_UNUSED,
11451 " -(%b--%c)",
11452 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11453
11454 /* Block range used, but not marked used in bitmap */
11455 { PR_5_BLOCK_RANGE_USED,
11456 " +(%b--%c)",
11457 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11458
11459 /* Inode range not used, but marked in bitmap */
11460 { PR_5_INODE_RANGE_UNUSED,
11461 " -(%i--%j)",
11462 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11463
11464 /* Inode range used, but not marked used in bitmap */
11465 { PR_5_INODE_RANGE_USED,
11466 " +(%i--%j)",
11467 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11468
11469 { 0 }
11470};
11471
11472/*
11473 * This is the latch flags register. It allows several problems to be
11474 * "latched" together. This means that the user has to answer but one
11475 * question for the set of problems, and all of the associated
11476 * problems will be either fixed or not fixed.
11477 */
11478static struct latch_descr pr_latch_info[] = {
11479 { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
11480 { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
11481 { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
11482 { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
11483 { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
11484 { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
11485 { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
11486 { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
11487 { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
11488 { -1, 0, 0 },
11489};
11490
11491static const struct e2fsck_problem *find_problem(problem_t code)
11492{
11493 int i;
11494
11495 for (i=0; problem_table[i].e2p_code; i++) {
11496 if (problem_table[i].e2p_code == code)
11497 return &problem_table[i];
11498 }
11499 return 0;
11500}
11501
11502static struct latch_descr *find_latch(int code)
11503{
11504 int i;
11505
11506 for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
11507 if (pr_latch_info[i].latch_code == code)
11508 return &pr_latch_info[i];
11509 }
11510 return 0;
11511}
11512
11513int end_problem_latch(e2fsck_t ctx, int mask)
11514{
11515 struct latch_descr *ldesc;
11516 struct problem_context pctx;
11517 int answer = -1;
11518
11519 ldesc = find_latch(mask);
11520 if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
11521 clear_problem_context(&pctx);
11522 answer = fix_problem(ctx, ldesc->end_message, &pctx);
11523 }
11524 ldesc->flags &= ~(PRL_VARIABLE);
11525 return answer;
11526}
11527
11528int set_latch_flags(int mask, int setflags, int clearflags)
11529{
11530 struct latch_descr *ldesc;
11531
11532 ldesc = find_latch(mask);
11533 if (!ldesc)
11534 return -1;
11535 ldesc->flags |= setflags;
11536 ldesc->flags &= ~clearflags;
11537 return 0;
11538}
11539
11540void clear_problem_context(struct problem_context *ctx)
11541{
11542 memset(ctx, 0, sizeof(struct problem_context));
11543 ctx->blkcount = -1;
11544 ctx->group = -1;
11545}
11546
11547int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
11548{
11549 ext2_filsys fs = ctx->fs;
11550 const struct e2fsck_problem *ptr;
11551 struct latch_descr *ldesc = 0;
11552 const char *message;
11553 int def_yn, answer, ans;
11554 int print_answer = 0;
11555 int suppress = 0;
11556
11557 ptr = find_problem(code);
11558 if (!ptr) {
11559 printf(_("Unhandled error code (0x%x)!\n"), code);
11560 return 0;
11561 }
11562 def_yn = 1;
11563 if ((ptr->flags & PR_NO_DEFAULT) ||
11564 ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
11565 (ctx->options & E2F_OPT_NO))
11566 def_yn= 0;
11567
11568 /*
11569 * Do special latch processing. This is where we ask the
11570 * latch question, if it exists
11571 */
11572 if (ptr->flags & PR_LATCH_MASK) {
11573 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
11574 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
11575 ans = fix_problem(ctx, ldesc->question, pctx);
11576 if (ans == 1)
11577 ldesc->flags |= PRL_YES;
11578 if (ans == 0)
11579 ldesc->flags |= PRL_NO;
11580 ldesc->flags |= PRL_LATCHED;
11581 }
11582 if (ldesc->flags & PRL_SUPPRESS)
11583 suppress++;
11584 }
11585 if ((ptr->flags & PR_PREEN_NOMSG) &&
11586 (ctx->options & E2F_OPT_PREEN))
11587 suppress++;
11588 if ((ptr->flags & PR_NO_NOMSG) &&
11589 (ctx->options & E2F_OPT_NO))
11590 suppress++;
11591 if (!suppress) {
11592 message = ptr->e2p_description;
11593 if ((ctx->options & E2F_OPT_PREEN) &&
11594 !(ptr->flags & PR_PREEN_NOHDR)) {
11595 printf("%s: ", ctx->device_name ?
11596 ctx->device_name : ctx->filesystem_name);
11597 }
11598 if (*message)
11599 print_e2fsck_message(ctx, _(message), pctx, 1);
11600 }
11601 if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
11602 preenhalt(ctx);
11603
11604 if (ptr->flags & PR_FATAL)
11605 fatal_error(ctx, 0);
11606
11607 if (ptr->prompt == PROMPT_NONE) {
11608 if (ptr->flags & PR_NOCOLLATE)
11609 answer = -1;
11610 else
11611 answer = def_yn;
11612 } else {
11613 if (ctx->options & E2F_OPT_PREEN) {
11614 answer = def_yn;
11615 if (!(ptr->flags & PR_PREEN_NOMSG))
11616 print_answer = 1;
11617 } else if ((ptr->flags & PR_LATCH_MASK) &&
11618 (ldesc->flags & (PRL_YES | PRL_NO))) {
11619 if (!suppress)
11620 print_answer = 1;
11621 if (ldesc->flags & PRL_YES)
11622 answer = 1;
11623 else
11624 answer = 0;
11625 } else
11626 answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
11627 if (!answer && !(ptr->flags & PR_NO_OK))
11628 ext2fs_unmark_valid(fs);
11629
11630 if (print_answer)
11631 printf("%s.\n", answer ?
11632 _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
11633
11634 }
11635
11636 if ((ptr->prompt == PROMPT_ABORT) && answer)
11637 fatal_error(ctx, 0);
11638
11639 if (ptr->flags & PR_AFTER_CODE)
11640 answer = fix_problem(ctx, ptr->second_code, pctx);
11641
11642 return answer;
11643}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011644
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011645/*
11646 * linux/fs/recovery.c
11647 *
11648 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011649 */
11650
11651/*
11652 * Maintain information about the progress of the recovery job, so that
11653 * the different passes can carry information between them.
11654 */
11655struct recovery_info
11656{
11657 tid_t start_transaction;
11658 tid_t end_transaction;
11659
11660 int nr_replays;
11661 int nr_revokes;
11662 int nr_revoke_hits;
11663};
11664
11665enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
11666static int do_one_pass(journal_t *journal,
11667 struct recovery_info *info, enum passtype pass);
11668static int scan_revoke_records(journal_t *, struct buffer_head *,
11669 tid_t, struct recovery_info *);
11670
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011671/*
11672 * Read a block from the journal
11673 */
11674
11675static int jread(struct buffer_head **bhp, journal_t *journal,
11676 unsigned int offset)
11677{
11678 int err;
11679 unsigned long blocknr;
11680 struct buffer_head *bh;
11681
11682 *bhp = NULL;
11683
11684 J_ASSERT (offset < journal->j_maxlen);
11685
11686 err = journal_bmap(journal, offset, &blocknr);
11687
11688 if (err) {
11689 printk (KERN_ERR "JBD: bad block at offset %u\n",
11690 offset);
11691 return err;
11692 }
11693
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011694 bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011695 if (!bh)
11696 return -ENOMEM;
11697
11698 if (!buffer_uptodate(bh)) {
11699 /* If this is a brand new buffer, start readahead.
11700 Otherwise, we assume we are already reading it. */
11701 if (!buffer_req(bh))
11702 do_readahead(journal, offset);
11703 wait_on_buffer(bh);
11704 }
11705
11706 if (!buffer_uptodate(bh)) {
11707 printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
11708 offset);
11709 brelse(bh);
11710 return -EIO;
11711 }
11712
11713 *bhp = bh;
11714 return 0;
11715}
11716
11717
11718/*
11719 * Count the number of in-use tags in a journal descriptor block.
11720 */
11721
11722static int count_tags(struct buffer_head *bh, int size)
11723{
11724 char * tagp;
11725 journal_block_tag_t * tag;
11726 int nr = 0;
11727
11728 tagp = &bh->b_data[sizeof(journal_header_t)];
11729
11730 while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
11731 tag = (journal_block_tag_t *) tagp;
11732
11733 nr++;
11734 tagp += sizeof(journal_block_tag_t);
11735 if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
11736 tagp += 16;
11737
11738 if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
11739 break;
11740 }
11741
11742 return nr;
11743}
11744
11745
11746/* Make sure we wrap around the log correctly! */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000011747#define wrap(journal, var) \
11748do { \
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011749 if (var >= (journal)->j_last) \
11750 var -= ((journal)->j_last - (journal)->j_first); \
11751} while (0)
11752
11753/**
11754 * int journal_recover(journal_t *journal) - recovers a on-disk journal
11755 * @journal: the journal to recover
11756 *
11757 * The primary function for recovering the log contents when mounting a
11758 * journaled device.
11759 *
11760 * Recovery is done in three passes. In the first pass, we look for the
11761 * end of the log. In the second, we assemble the list of revoke
11762 * blocks. In the third and final pass, we replay any un-revoked blocks
11763 * in the log.
11764 */
11765int journal_recover(journal_t *journal)
11766{
11767 int err;
11768 journal_superblock_t * sb;
11769
11770 struct recovery_info info;
11771
11772 memset(&info, 0, sizeof(info));
11773 sb = journal->j_superblock;
11774
11775 /*
11776 * The journal superblock's s_start field (the current log head)
11777 * is always zero if, and only if, the journal was cleanly
11778 * unmounted.
11779 */
11780
11781 if (!sb->s_start) {
11782 jbd_debug(1, "No recovery required, last transaction %d\n",
11783 ntohl(sb->s_sequence));
11784 journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
11785 return 0;
11786 }
11787
11788 err = do_one_pass(journal, &info, PASS_SCAN);
11789 if (!err)
11790 err = do_one_pass(journal, &info, PASS_REVOKE);
11791 if (!err)
11792 err = do_one_pass(journal, &info, PASS_REPLAY);
11793
11794 jbd_debug(0, "JBD: recovery, exit status %d, "
11795 "recovered transactions %u to %u\n",
11796 err, info.start_transaction, info.end_transaction);
11797 jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
11798 info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
11799
11800 /* Restart the log at the next transaction ID, thus invalidating
11801 * any existing commit records in the log. */
11802 journal->j_transaction_sequence = ++info.end_transaction;
11803
11804 journal_clear_revoke(journal);
11805 sync_blockdev(journal->j_fs_dev);
11806 return err;
11807}
11808
11809static int do_one_pass(journal_t *journal,
11810 struct recovery_info *info, enum passtype pass)
11811{
11812 unsigned int first_commit_ID, next_commit_ID;
11813 unsigned long next_log_block;
11814 int err, success = 0;
11815 journal_superblock_t * sb;
11816 journal_header_t * tmp;
11817 struct buffer_head * bh;
11818 unsigned int sequence;
11819 int blocktype;
11820
11821 /* Precompute the maximum metadata descriptors in a descriptor block */
11822 int MAX_BLOCKS_PER_DESC;
11823 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
11824 / sizeof(journal_block_tag_t));
11825
11826 /*
11827 * First thing is to establish what we expect to find in the log
11828 * (in terms of transaction IDs), and where (in terms of log
11829 * block offsets): query the superblock.
11830 */
11831
11832 sb = journal->j_superblock;
11833 next_commit_ID = ntohl(sb->s_sequence);
11834 next_log_block = ntohl(sb->s_start);
11835
11836 first_commit_ID = next_commit_ID;
11837 if (pass == PASS_SCAN)
11838 info->start_transaction = first_commit_ID;
11839
11840 jbd_debug(1, "Starting recovery pass %d\n", pass);
11841
11842 /*
11843 * Now we walk through the log, transaction by transaction,
11844 * making sure that each transaction has a commit block in the
11845 * expected place. Each complete transaction gets replayed back
11846 * into the main filesystem.
11847 */
11848
11849 while (1) {
11850 int flags;
11851 char * tagp;
11852 journal_block_tag_t * tag;
11853 struct buffer_head * obh;
11854 struct buffer_head * nbh;
11855
11856 /* If we already know where to stop the log traversal,
11857 * check right now that we haven't gone past the end of
11858 * the log. */
11859
11860 if (pass != PASS_SCAN)
11861 if (tid_geq(next_commit_ID, info->end_transaction))
11862 break;
11863
11864 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
11865 next_commit_ID, next_log_block, journal->j_last);
11866
11867 /* Skip over each chunk of the transaction looking
11868 * either the next descriptor block or the final commit
11869 * record. */
11870
11871 jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
11872 err = jread(&bh, journal, next_log_block);
11873 if (err)
11874 goto failed;
11875
11876 next_log_block++;
11877 wrap(journal, next_log_block);
11878
11879 /* What kind of buffer is it?
11880 *
11881 * If it is a descriptor block, check that it has the
11882 * expected sequence number. Otherwise, we're all done
11883 * here. */
11884
11885 tmp = (journal_header_t *)bh->b_data;
11886
11887 if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
11888 brelse(bh);
11889 break;
11890 }
11891
11892 blocktype = ntohl(tmp->h_blocktype);
11893 sequence = ntohl(tmp->h_sequence);
11894 jbd_debug(3, "Found magic %d, sequence %d\n",
11895 blocktype, sequence);
11896
11897 if (sequence != next_commit_ID) {
11898 brelse(bh);
11899 break;
11900 }
11901
11902 /* OK, we have a valid descriptor block which matches
11903 * all of the sequence number checks. What are we going
11904 * to do with it? That depends on the pass... */
11905
11906 switch(blocktype) {
11907 case JFS_DESCRIPTOR_BLOCK:
11908 /* If it is a valid descriptor block, replay it
11909 * in pass REPLAY; otherwise, just skip over the
11910 * blocks it describes. */
11911 if (pass != PASS_REPLAY) {
11912 next_log_block +=
11913 count_tags(bh, journal->j_blocksize);
11914 wrap(journal, next_log_block);
11915 brelse(bh);
11916 continue;
11917 }
11918
11919 /* A descriptor block: we can now write all of
11920 * the data blocks. Yay, useful work is finally
11921 * getting done here! */
11922
11923 tagp = &bh->b_data[sizeof(journal_header_t)];
11924 while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
11925 <= journal->j_blocksize) {
11926 unsigned long io_block;
11927
11928 tag = (journal_block_tag_t *) tagp;
11929 flags = ntohl(tag->t_flags);
11930
11931 io_block = next_log_block++;
11932 wrap(journal, next_log_block);
11933 err = jread(&obh, journal, io_block);
11934 if (err) {
11935 /* Recover what we can, but
11936 * report failure at the end. */
11937 success = err;
11938 printk (KERN_ERR
11939 "JBD: IO error %d recovering "
11940 "block %ld in log\n",
11941 err, io_block);
11942 } else {
11943 unsigned long blocknr;
11944
11945 J_ASSERT(obh != NULL);
11946 blocknr = ntohl(tag->t_blocknr);
11947
11948 /* If the block has been
11949 * revoked, then we're all done
11950 * here. */
11951 if (journal_test_revoke
11952 (journal, blocknr,
11953 next_commit_ID)) {
11954 brelse(obh);
11955 ++info->nr_revoke_hits;
11956 goto skip_write;
11957 }
11958
11959 /* Find a buffer for the new
11960 * data being restored */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011961 nbh = getblk(journal->j_fs_dev,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011962 blocknr,
11963 journal->j_blocksize);
11964 if (nbh == NULL) {
11965 printk(KERN_ERR
11966 "JBD: Out of memory "
11967 "during recovery.\n");
11968 err = -ENOMEM;
11969 brelse(bh);
11970 brelse(obh);
11971 goto failed;
11972 }
11973
11974 lock_buffer(nbh);
11975 memcpy(nbh->b_data, obh->b_data,
11976 journal->j_blocksize);
11977 if (flags & JFS_FLAG_ESCAPE) {
11978 *((unsigned int *)bh->b_data) =
11979 htonl(JFS_MAGIC_NUMBER);
11980 }
11981
11982 BUFFER_TRACE(nbh, "marking dirty");
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011983 mark_buffer_uptodate(nbh, 1);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011984 mark_buffer_dirty(nbh);
11985 BUFFER_TRACE(nbh, "marking uptodate");
11986 ++info->nr_replays;
11987 /* ll_rw_block(WRITE, 1, &nbh); */
11988 unlock_buffer(nbh);
11989 brelse(obh);
11990 brelse(nbh);
11991 }
11992
11993 skip_write:
11994 tagp += sizeof(journal_block_tag_t);
11995 if (!(flags & JFS_FLAG_SAME_UUID))
11996 tagp += 16;
11997
11998 if (flags & JFS_FLAG_LAST_TAG)
11999 break;
12000 }
12001
12002 brelse(bh);
12003 continue;
12004
12005 case JFS_COMMIT_BLOCK:
12006 /* Found an expected commit block: not much to
12007 * do other than move on to the next sequence
12008 * number. */
12009 brelse(bh);
12010 next_commit_ID++;
12011 continue;
12012
12013 case JFS_REVOKE_BLOCK:
12014 /* If we aren't in the REVOKE pass, then we can
12015 * just skip over this block. */
12016 if (pass != PASS_REVOKE) {
12017 brelse(bh);
12018 continue;
12019 }
12020
12021 err = scan_revoke_records(journal, bh,
12022 next_commit_ID, info);
12023 brelse(bh);
12024 if (err)
12025 goto failed;
12026 continue;
12027
12028 default:
12029 jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
12030 blocktype);
12031 goto done;
12032 }
12033 }
12034
12035 done:
12036 /*
12037 * We broke out of the log scan loop: either we came to the
12038 * known end of the log or we found an unexpected block in the
12039 * log. If the latter happened, then we know that the "current"
12040 * transaction marks the end of the valid log.
12041 */
12042
12043 if (pass == PASS_SCAN)
12044 info->end_transaction = next_commit_ID;
12045 else {
12046 /* It's really bad news if different passes end up at
12047 * different places (but possible due to IO errors). */
12048 if (info->end_transaction != next_commit_ID) {
12049 printk (KERN_ERR "JBD: recovery pass %d ended at "
12050 "transaction %u, expected %u\n",
12051 pass, next_commit_ID, info->end_transaction);
12052 if (!success)
12053 success = -EIO;
12054 }
12055 }
12056
12057 return success;
12058
12059 failed:
12060 return err;
12061}
12062
12063
12064/* Scan a revoke record, marking all blocks mentioned as revoked. */
12065
12066static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
12067 tid_t sequence, struct recovery_info *info)
12068{
12069 journal_revoke_header_t *header;
12070 int offset, max;
12071
12072 header = (journal_revoke_header_t *) bh->b_data;
12073 offset = sizeof(journal_revoke_header_t);
12074 max = ntohl(header->r_count);
12075
12076 while (offset < max) {
12077 unsigned long blocknr;
12078 int err;
12079
12080 blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
12081 offset += 4;
12082 err = journal_set_revoke(journal, blocknr, sequence);
12083 if (err)
12084 return err;
12085 ++info->nr_revokes;
12086 }
12087 return 0;
12088}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012089
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012090
12091/*
12092 * rehash.c --- rebuild hash tree directories
12093 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012094 * This algorithm is designed for simplicity of implementation and to
12095 * pack the directory as much as possible. It however requires twice
12096 * as much memory as the size of the directory. The maximum size
12097 * directory supported using a 4k blocksize is roughly a gigabyte, and
12098 * so there may very well be problems with machines that don't have
12099 * virtual memory, and obscenely large directories.
12100 *
12101 * An alternate algorithm which is much more disk intensive could be
12102 * written, and probably will need to be written in the future. The
12103 * design goals of such an algorithm are: (a) use (roughly) constant
12104 * amounts of memory, no matter how large the directory, (b) the
12105 * directory must be safe at all times, even if e2fsck is interrupted
12106 * in the middle, (c) we must use minimal amounts of extra disk
12107 * blocks. This pretty much requires an incremental approach, where
12108 * we are reading from one part of the directory, and inserting into
12109 * the front half. So the algorithm will have to keep track of a
12110 * moving block boundary between the new tree and the old tree, and
12111 * files will need to be moved from the old directory and inserted
12112 * into the new tree. If the new directory requires space which isn't
12113 * yet available, blocks from the beginning part of the old directory
12114 * may need to be moved to the end of the directory to make room for
12115 * the new tree:
12116 *
12117 * --------------------------------------------------------
12118 * | new tree | | old tree |
12119 * --------------------------------------------------------
12120 * ^ ptr ^ptr
12121 * tail new head old
12122 *
12123 * This is going to be a pain in the tuckus to implement, and will
12124 * require a lot more disk accesses. So I'm going to skip it for now;
12125 * it's only really going to be an issue for really, really big
12126 * filesystems (when we reach the level of tens of millions of files
12127 * in a single directory). It will probably be easier to simply
12128 * require that e2fsck use VM first.
12129 */
12130
12131struct fill_dir_struct {
12132 char *buf;
12133 struct ext2_inode *inode;
12134 int err;
12135 e2fsck_t ctx;
12136 struct hash_entry *harray;
12137 int max_array, num_array;
12138 int dir_size;
12139 int compress;
12140 ino_t parent;
12141};
12142
12143struct hash_entry {
12144 ext2_dirhash_t hash;
12145 ext2_dirhash_t minor_hash;
12146 struct ext2_dir_entry *dir;
12147};
12148
12149struct out_dir {
12150 int num;
12151 int max;
12152 char *buf;
12153 ext2_dirhash_t *hashes;
12154};
12155
12156static int fill_dir_block(ext2_filsys fs,
12157 blk_t *block_nr,
12158 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000012159 blk_t ref_block FSCK_ATTR((unused)),
12160 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012161 void *priv_data)
12162{
12163 struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
12164 struct hash_entry *new_array, *ent;
12165 struct ext2_dir_entry *dirent;
12166 char *dir;
12167 unsigned int offset, dir_offset;
12168
12169 if (blockcnt < 0)
12170 return 0;
12171
12172 offset = blockcnt * fs->blocksize;
12173 if (offset + fs->blocksize > fd->inode->i_size) {
12174 fd->err = EXT2_ET_DIR_CORRUPTED;
12175 return BLOCK_ABORT;
12176 }
12177 dir = (fd->buf+offset);
12178 if (HOLE_BLKADDR(*block_nr)) {
12179 memset(dir, 0, fs->blocksize);
12180 dirent = (struct ext2_dir_entry *) dir;
12181 dirent->rec_len = fs->blocksize;
12182 } else {
12183 fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
12184 if (fd->err)
12185 return BLOCK_ABORT;
12186 }
12187 /* While the directory block is "hot", index it. */
12188 dir_offset = 0;
12189 while (dir_offset < fs->blocksize) {
12190 dirent = (struct ext2_dir_entry *) (dir + dir_offset);
12191 if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
12192 (dirent->rec_len < 8) ||
12193 ((dirent->rec_len % 4) != 0) ||
12194 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
12195 fd->err = EXT2_ET_DIR_CORRUPTED;
12196 return BLOCK_ABORT;
12197 }
12198 dir_offset += dirent->rec_len;
12199 if (dirent->inode == 0)
12200 continue;
12201 if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
12202 (dirent->name[0] == '.'))
12203 continue;
12204 if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
12205 (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
12206 fd->parent = dirent->inode;
12207 continue;
12208 }
12209 if (fd->num_array >= fd->max_array) {
12210 new_array = realloc(fd->harray,
12211 sizeof(struct hash_entry) * (fd->max_array+500));
12212 if (!new_array) {
12213 fd->err = ENOMEM;
12214 return BLOCK_ABORT;
12215 }
12216 fd->harray = new_array;
12217 fd->max_array += 500;
12218 }
12219 ent = fd->harray + fd->num_array++;
12220 ent->dir = dirent;
12221 fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
12222 if (fd->compress)
12223 ent->hash = ent->minor_hash = 0;
12224 else {
12225 fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
12226 dirent->name,
12227 dirent->name_len & 0xFF,
12228 fs->super->s_hash_seed,
12229 &ent->hash, &ent->minor_hash);
12230 if (fd->err)
12231 return BLOCK_ABORT;
12232 }
12233 }
12234
12235 return 0;
12236}
12237
12238/* Used for sorting the hash entry */
12239static EXT2_QSORT_TYPE name_cmp(const void *a, const void *b)
12240{
12241 const struct hash_entry *he_a = (const struct hash_entry *) a;
12242 const struct hash_entry *he_b = (const struct hash_entry *) b;
12243 int ret;
12244 int min_len;
12245
12246 min_len = he_a->dir->name_len;
12247 if (min_len > he_b->dir->name_len)
12248 min_len = he_b->dir->name_len;
12249
12250 ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
12251 if (ret == 0) {
12252 if (he_a->dir->name_len > he_b->dir->name_len)
12253 ret = 1;
12254 else if (he_a->dir->name_len < he_b->dir->name_len)
12255 ret = -1;
12256 else
12257 ret = he_b->dir->inode - he_a->dir->inode;
12258 }
12259 return ret;
12260}
12261
12262/* Used for sorting the hash entry */
12263static EXT2_QSORT_TYPE hash_cmp(const void *a, const void *b)
12264{
12265 const struct hash_entry *he_a = (const struct hash_entry *) a;
12266 const struct hash_entry *he_b = (const struct hash_entry *) b;
12267 int ret;
12268
12269 if (he_a->hash > he_b->hash)
12270 ret = 1;
12271 else if (he_a->hash < he_b->hash)
12272 ret = -1;
12273 else {
12274 if (he_a->minor_hash > he_b->minor_hash)
12275 ret = 1;
12276 else if (he_a->minor_hash < he_b->minor_hash)
12277 ret = -1;
12278 else
12279 ret = name_cmp(a, b);
12280 }
12281 return ret;
12282}
12283
12284static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
12285 int blocks)
12286{
12287 void *new_mem;
12288
12289 if (outdir->max) {
12290 new_mem = realloc(outdir->buf, blocks * fs->blocksize);
12291 if (!new_mem)
12292 return ENOMEM;
12293 outdir->buf = new_mem;
12294 new_mem = realloc(outdir->hashes,
12295 blocks * sizeof(ext2_dirhash_t));
12296 if (!new_mem)
12297 return ENOMEM;
12298 outdir->hashes = new_mem;
12299 } else {
12300 outdir->buf = malloc(blocks * fs->blocksize);
12301 outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
12302 outdir->num = 0;
12303 }
12304 outdir->max = blocks;
12305 return 0;
12306}
12307
12308static void free_out_dir(struct out_dir *outdir)
12309{
Rob Landleye7c43b62006-03-01 16:39:45 +000012310 free(outdir->buf);
12311 free(outdir->hashes);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012312 outdir->max = 0;
12313 outdir->num =0;
12314}
12315
12316static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
12317 char ** ret)
12318{
12319 errcode_t retval;
12320
12321 if (outdir->num >= outdir->max) {
12322 retval = alloc_size_dir(fs, outdir, outdir->max + 50);
12323 if (retval)
12324 return retval;
12325 }
12326 *ret = outdir->buf + (outdir->num++ * fs->blocksize);
12327 memset(*ret, 0, fs->blocksize);
12328 return 0;
12329}
12330
12331/*
12332 * This function is used to make a unique filename. We do this by
12333 * appending ~0, and then incrementing the number. However, we cannot
12334 * expand the length of the filename beyond the padding available in
12335 * the directory entry.
12336 */
12337static void mutate_name(char *str, __u16 *len)
12338{
12339 int i;
12340 __u16 l = *len & 0xFF, h = *len & 0xff00;
12341
12342 /*
12343 * First check to see if it looks the name has been mutated
12344 * already
12345 */
12346 for (i = l-1; i > 0; i--) {
12347 if (!isdigit(str[i]))
12348 break;
12349 }
12350 if ((i == l-1) || (str[i] != '~')) {
12351 if (((l-1) & 3) < 2)
12352 l += 2;
12353 else
12354 l = (l+3) & ~3;
12355 str[l-2] = '~';
12356 str[l-1] = '0';
12357 *len = l | h;
12358 return;
12359 }
12360 for (i = l-1; i >= 0; i--) {
12361 if (isdigit(str[i])) {
12362 if (str[i] == '9')
12363 str[i] = '0';
12364 else {
12365 str[i]++;
12366 return;
12367 }
12368 continue;
12369 }
12370 if (i == 1) {
12371 if (str[0] == 'z')
12372 str[0] = 'A';
12373 else if (str[0] == 'Z') {
12374 str[0] = '~';
12375 str[1] = '0';
12376 } else
12377 str[0]++;
12378 } else if (i > 0) {
12379 str[i] = '1';
12380 str[i-1] = '~';
12381 } else {
12382 if (str[0] == '~')
12383 str[0] = 'a';
12384 else
12385 str[0]++;
12386 }
12387 break;
12388 }
12389}
12390
12391static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
12392 ext2_ino_t ino,
12393 struct fill_dir_struct *fd)
12394{
12395 struct problem_context pctx;
12396 struct hash_entry *ent, *prev;
12397 int i, j;
12398 int fixed = 0;
12399 char new_name[256];
12400 __u16 new_len;
12401
12402 clear_problem_context(&pctx);
12403 pctx.ino = ino;
12404
12405 for (i=1; i < fd->num_array; i++) {
12406 ent = fd->harray + i;
12407 prev = ent - 1;
12408 if (!ent->dir->inode ||
12409 ((ent->dir->name_len & 0xFF) !=
12410 (prev->dir->name_len & 0xFF)) ||
12411 (strncmp(ent->dir->name, prev->dir->name,
12412 ent->dir->name_len & 0xFF)))
12413 continue;
12414 pctx.dirent = ent->dir;
12415 if ((ent->dir->inode == prev->dir->inode) &&
12416 fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
12417 e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
12418 ent->dir->inode = 0;
12419 fixed++;
12420 continue;
12421 }
12422 memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
12423 new_len = ent->dir->name_len;
12424 mutate_name(new_name, &new_len);
12425 for (j=0; j < fd->num_array; j++) {
12426 if ((i==j) ||
12427 ((ent->dir->name_len & 0xFF) !=
12428 (fd->harray[j].dir->name_len & 0xFF)) ||
12429 (strncmp(new_name, fd->harray[j].dir->name,
12430 new_len & 0xFF)))
12431 continue;
12432 mutate_name(new_name, &new_len);
12433
12434 j = -1;
12435 }
12436 new_name[new_len & 0xFF] = 0;
12437 pctx.str = new_name;
12438 if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
12439 memcpy(ent->dir->name, new_name, new_len & 0xFF);
12440 ent->dir->name_len = new_len;
12441 ext2fs_dirhash(fs->super->s_def_hash_version,
12442 ent->dir->name,
12443 ent->dir->name_len & 0xFF,
12444 fs->super->s_hash_seed,
12445 &ent->hash, &ent->minor_hash);
12446 fixed++;
12447 }
12448 }
12449 return fixed;
12450}
12451
12452
12453static errcode_t copy_dir_entries(ext2_filsys fs,
12454 struct fill_dir_struct *fd,
12455 struct out_dir *outdir)
12456{
12457 errcode_t retval;
12458 char *block_start;
12459 struct hash_entry *ent;
12460 struct ext2_dir_entry *dirent;
12461 int i, rec_len, left;
12462 ext2_dirhash_t prev_hash;
12463 int offset;
12464
12465 outdir->max = 0;
12466 retval = alloc_size_dir(fs, outdir,
12467 (fd->dir_size / fs->blocksize) + 2);
12468 if (retval)
12469 return retval;
12470 outdir->num = fd->compress ? 0 : 1;
12471 offset = 0;
12472 outdir->hashes[0] = 0;
12473 prev_hash = 1;
12474 if ((retval = get_next_block(fs, outdir, &block_start)))
12475 return retval;
12476 dirent = (struct ext2_dir_entry *) block_start;
12477 left = fs->blocksize;
12478 for (i=0; i < fd->num_array; i++) {
12479 ent = fd->harray + i;
12480 if (ent->dir->inode == 0)
12481 continue;
12482 rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
12483 if (rec_len > left) {
12484 if (left)
12485 dirent->rec_len += left;
12486 if ((retval = get_next_block(fs, outdir,
12487 &block_start)))
12488 return retval;
12489 offset = 0;
12490 }
12491 left = fs->blocksize - offset;
12492 dirent = (struct ext2_dir_entry *) (block_start + offset);
12493 if (offset == 0) {
12494 if (ent->hash == prev_hash)
12495 outdir->hashes[outdir->num-1] = ent->hash | 1;
12496 else
12497 outdir->hashes[outdir->num-1] = ent->hash;
12498 }
12499 dirent->inode = ent->dir->inode;
12500 dirent->name_len = ent->dir->name_len;
12501 dirent->rec_len = rec_len;
12502 memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
12503 offset += rec_len;
12504 left -= rec_len;
12505 if (left < 12) {
12506 dirent->rec_len += left;
12507 offset += left;
12508 left = 0;
12509 }
12510 prev_hash = ent->hash;
12511 }
12512 if (left)
12513 dirent->rec_len += left;
12514
12515 return 0;
12516}
12517
12518
12519static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
12520 ext2_ino_t ino, ext2_ino_t parent)
12521{
12522 struct ext2_dir_entry *dir;
12523 struct ext2_dx_root_info *root;
12524 struct ext2_dx_countlimit *limits;
12525 int filetype = 0;
12526
12527 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
12528 filetype = EXT2_FT_DIR << 8;
12529
12530 memset(buf, 0, fs->blocksize);
12531 dir = (struct ext2_dir_entry *) buf;
12532 dir->inode = ino;
12533 dir->name[0] = '.';
12534 dir->name_len = 1 | filetype;
12535 dir->rec_len = 12;
12536 dir = (struct ext2_dir_entry *) (buf + 12);
12537 dir->inode = parent;
12538 dir->name[0] = '.';
12539 dir->name[1] = '.';
12540 dir->name_len = 2 | filetype;
12541 dir->rec_len = fs->blocksize - 12;
12542
12543 root = (struct ext2_dx_root_info *) (buf+24);
12544 root->reserved_zero = 0;
12545 root->hash_version = fs->super->s_def_hash_version;
12546 root->info_length = 8;
12547 root->indirect_levels = 0;
12548 root->unused_flags = 0;
12549
12550 limits = (struct ext2_dx_countlimit *) (buf+32);
12551 limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
12552 limits->count = 0;
12553
12554 return root;
12555}
12556
12557
12558static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
12559{
12560 struct ext2_dir_entry *dir;
12561 struct ext2_dx_countlimit *limits;
12562
12563 memset(buf, 0, fs->blocksize);
12564 dir = (struct ext2_dir_entry *) buf;
12565 dir->inode = 0;
12566 dir->rec_len = fs->blocksize;
12567
12568 limits = (struct ext2_dx_countlimit *) (buf+8);
12569 limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
12570 limits->count = 0;
12571
12572 return (struct ext2_dx_entry *) limits;
12573}
12574
12575/*
12576 * This function takes the leaf nodes which have been written in
12577 * outdir, and populates the root node and any necessary interior nodes.
12578 */
12579static errcode_t calculate_tree(ext2_filsys fs,
12580 struct out_dir *outdir,
12581 ext2_ino_t ino,
12582 ext2_ino_t parent)
12583{
12584 struct ext2_dx_root_info *root_info;
12585 struct ext2_dx_entry *root, *dx_ent = 0;
12586 struct ext2_dx_countlimit *root_limit, *limit;
12587 errcode_t retval;
12588 char * block_start;
12589 int i, c1, c2, nblks;
12590 int limit_offset, root_offset;
12591
12592 root_info = set_root_node(fs, outdir->buf, ino, parent);
12593 root_offset = limit_offset = ((char *) root_info - outdir->buf) +
12594 root_info->info_length;
12595 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
12596 c1 = root_limit->limit;
12597 nblks = outdir->num;
12598
12599 /* Write out the pointer blocks */
12600 if (nblks-1 <= c1) {
12601 /* Just write out the root block, and we're done */
12602 root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
12603 for (i=1; i < nblks; i++) {
12604 root->block = ext2fs_cpu_to_le32(i);
12605 if (i != 1)
12606 root->hash =
12607 ext2fs_cpu_to_le32(outdir->hashes[i]);
12608 root++;
12609 c1--;
12610 }
12611 } else {
12612 c2 = 0;
12613 limit = 0;
12614 root_info->indirect_levels = 1;
12615 for (i=1; i < nblks; i++) {
12616 if (c1 == 0)
12617 return ENOSPC;
12618 if (c2 == 0) {
12619 if (limit)
12620 limit->limit = limit->count =
12621 ext2fs_cpu_to_le16(limit->limit);
12622 root = (struct ext2_dx_entry *)
12623 (outdir->buf + root_offset);
12624 root->block = ext2fs_cpu_to_le32(outdir->num);
12625 if (i != 1)
12626 root->hash =
12627 ext2fs_cpu_to_le32(outdir->hashes[i]);
12628 if ((retval = get_next_block(fs, outdir,
12629 &block_start)))
12630 return retval;
12631 dx_ent = set_int_node(fs, block_start);
12632 limit = (struct ext2_dx_countlimit *) dx_ent;
12633 c2 = limit->limit;
12634 root_offset += sizeof(struct ext2_dx_entry);
12635 c1--;
12636 }
12637 dx_ent->block = ext2fs_cpu_to_le32(i);
12638 if (c2 != limit->limit)
12639 dx_ent->hash =
12640 ext2fs_cpu_to_le32(outdir->hashes[i]);
12641 dx_ent++;
12642 c2--;
12643 }
12644 limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
12645 limit->limit = ext2fs_cpu_to_le16(limit->limit);
12646 }
12647 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
12648 root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
12649 root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
12650
12651 return 0;
12652}
12653
12654struct write_dir_struct {
12655 struct out_dir *outdir;
12656 errcode_t err;
12657 e2fsck_t ctx;
12658 int cleared;
12659};
12660
12661/*
12662 * Helper function which writes out a directory block.
12663 */
12664static int write_dir_block(ext2_filsys fs,
12665 blk_t *block_nr,
12666 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000012667 blk_t ref_block FSCK_ATTR((unused)),
12668 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012669 void *priv_data)
12670{
12671 struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
12672 blk_t blk;
12673 char *dir;
12674
12675 if (*block_nr == 0)
12676 return 0;
12677 if (blockcnt >= wd->outdir->num) {
12678 e2fsck_read_bitmaps(wd->ctx);
12679 blk = *block_nr;
12680 ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
12681 ext2fs_block_alloc_stats(fs, blk, -1);
12682 *block_nr = 0;
12683 wd->cleared++;
12684 return BLOCK_CHANGED;
12685 }
12686 if (blockcnt < 0)
12687 return 0;
12688
12689 dir = wd->outdir->buf + (blockcnt * fs->blocksize);
12690 wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
12691 if (wd->err)
12692 return BLOCK_ABORT;
12693 return 0;
12694}
12695
12696static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
12697 struct out_dir *outdir,
12698 ext2_ino_t ino, int compress)
12699{
12700 struct write_dir_struct wd;
12701 errcode_t retval;
12702 struct ext2_inode inode;
12703
12704 retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
12705 if (retval)
12706 return retval;
12707
12708 wd.outdir = outdir;
12709 wd.err = 0;
12710 wd.ctx = ctx;
12711 wd.cleared = 0;
12712
12713 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
12714 write_dir_block, &wd);
12715 if (retval)
12716 return retval;
12717 if (wd.err)
12718 return wd.err;
12719
12720 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
12721 if (compress)
12722 inode.i_flags &= ~EXT2_INDEX_FL;
12723 else
12724 inode.i_flags |= EXT2_INDEX_FL;
12725 inode.i_size = outdir->num * fs->blocksize;
12726 inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
12727 e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
12728
12729 return 0;
12730}
12731
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012732static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012733{
12734 ext2_filsys fs = ctx->fs;
12735 errcode_t retval;
12736 struct ext2_inode inode;
12737 char *dir_buf = 0;
12738 struct fill_dir_struct fd;
12739 struct out_dir outdir;
12740
12741 outdir.max = outdir.num = 0;
12742 outdir.buf = 0;
12743 outdir.hashes = 0;
12744 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
12745
12746 retval = ENOMEM;
12747 fd.harray = 0;
12748 dir_buf = malloc(inode.i_size);
12749 if (!dir_buf)
12750 goto errout;
12751
12752 fd.max_array = inode.i_size / 32;
12753 fd.num_array = 0;
12754 fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
12755 if (!fd.harray)
12756 goto errout;
12757
12758 fd.ctx = ctx;
12759 fd.buf = dir_buf;
12760 fd.inode = &inode;
12761 fd.err = 0;
12762 fd.dir_size = 0;
12763 fd.compress = 0;
12764 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
12765 (inode.i_size / fs->blocksize) < 2)
12766 fd.compress = 1;
12767 fd.parent = 0;
12768
12769 /* Read in the entire directory into memory */
12770 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
12771 fill_dir_block, &fd);
12772 if (fd.err) {
12773 retval = fd.err;
12774 goto errout;
12775 }
12776
12777#if 0
12778 printf("%d entries (%d bytes) found in inode %d\n",
12779 fd.num_array, fd.dir_size, ino);
12780#endif
12781
12782 /* Sort the list */
12783resort:
12784 if (fd.compress)
12785 qsort(fd.harray+2, fd.num_array-2,
12786 sizeof(struct hash_entry), name_cmp);
12787 else
12788 qsort(fd.harray, fd.num_array,
12789 sizeof(struct hash_entry), hash_cmp);
12790
12791 /*
12792 * Look for duplicates
12793 */
12794 if (duplicate_search_and_fix(ctx, fs, ino, &fd))
12795 goto resort;
12796
12797 if (ctx->options & E2F_OPT_NO) {
12798 retval = 0;
12799 goto errout;
12800 }
12801
12802 /*
12803 * Copy the directory entries. In a htree directory these
12804 * will become the leaf nodes.
12805 */
12806 retval = copy_dir_entries(fs, &fd, &outdir);
12807 if (retval)
12808 goto errout;
12809
12810 free(dir_buf); dir_buf = 0;
12811
12812 if (!fd.compress) {
12813 /* Calculate the interior nodes */
12814 retval = calculate_tree(fs, &outdir, ino, fd.parent);
12815 if (retval)
12816 goto errout;
12817 }
12818
12819 retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012820
12821errout:
Rob Landleye7c43b62006-03-01 16:39:45 +000012822 free(dir_buf);
12823 free(fd.harray);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012824
12825 free_out_dir(&outdir);
12826 return retval;
12827}
12828
12829void e2fsck_rehash_directories(e2fsck_t ctx)
12830{
12831 struct problem_context pctx;
12832#ifdef RESOURCE_TRACK
12833 struct resource_track rtrack;
12834#endif
12835 struct dir_info *dir;
12836 ext2_u32_iterate iter;
12837 ext2_ino_t ino;
12838 errcode_t retval;
12839 int i, cur, max, all_dirs, dir_index, first = 1;
12840
12841#ifdef RESOURCE_TRACK
12842 init_resource_track(&rtrack);
12843#endif
12844
12845 all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
12846
12847 if (!ctx->dirs_to_hash && !all_dirs)
12848 return;
12849
12850 e2fsck_get_lost_and_found(ctx, 0);
12851
12852 clear_problem_context(&pctx);
12853
12854 dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
12855 cur = 0;
12856 if (all_dirs) {
12857 i = 0;
12858 max = e2fsck_get_num_dirinfo(ctx);
12859 } else {
12860 retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
12861 &iter);
12862 if (retval) {
12863 pctx.errcode = retval;
12864 fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
12865 return;
12866 }
12867 max = ext2fs_u32_list_count(ctx->dirs_to_hash);
12868 }
12869 while (1) {
12870 if (all_dirs) {
12871 if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
12872 break;
12873 ino = dir->ino;
12874 } else {
12875 if (!ext2fs_u32_list_iterate(iter, &ino))
12876 break;
12877 }
12878 if (ino == ctx->lost_and_found)
12879 continue;
12880 pctx.dir = ino;
12881 if (first) {
12882 fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
12883 first = 0;
12884 }
12885#if 0
12886 fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx);
12887#endif
12888 pctx.errcode = e2fsck_rehash_dir(ctx, ino);
12889 if (pctx.errcode) {
12890 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
12891 fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
12892 }
12893 if (ctx->progress && !ctx->progress_fd)
12894 e2fsck_simple_progress(ctx, "Rebuilding directory",
12895 100.0 * (float) (++cur) / (float) max, ino);
12896 }
12897 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
12898 if (!all_dirs)
12899 ext2fs_u32_list_iterate_end(iter);
12900
Rob Landleye7c43b62006-03-01 16:39:45 +000012901 ext2fs_u32_list_free(ctx->dirs_to_hash);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012902 ctx->dirs_to_hash = 0;
12903
12904#ifdef RESOURCE_TRACK
12905 if (ctx->options & E2F_OPT_TIME2) {
12906 e2fsck_clear_progbar(ctx);
12907 print_resource_track("Pass 3A", &rtrack);
12908 }
12909#endif
12910}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012911
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012912/*
12913 * linux/fs/revoke.c
12914 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012915 * Journal revoke routines for the generic filesystem journaling code;
12916 * part of the ext2fs journaling system.
12917 *
12918 * Revoke is the mechanism used to prevent old log records for deleted
12919 * metadata from being replayed on top of newer data using the same
12920 * blocks. The revoke mechanism is used in two separate places:
12921 *
12922 * + Commit: during commit we write the entire list of the current
12923 * transaction's revoked blocks to the journal
12924 *
12925 * + Recovery: during recovery we record the transaction ID of all
12926 * revoked blocks. If there are multiple revoke records in the log
12927 * for a single block, only the last one counts, and if there is a log
12928 * entry for a block beyond the last revoke, then that log entry still
12929 * gets replayed.
12930 *
12931 * We can get interactions between revokes and new log data within a
12932 * single transaction:
12933 *
12934 * Block is revoked and then journaled:
12935 * The desired end result is the journaling of the new block, so we
12936 * cancel the revoke before the transaction commits.
12937 *
12938 * Block is journaled and then revoked:
12939 * The revoke must take precedence over the write of the block, so we
12940 * need either to cancel the journal entry or to write the revoke
12941 * later in the log than the log block. In this case, we choose the
12942 * latter: journaling a block cancels any revoke record for that block
12943 * in the current transaction, so any revoke for that block in the
12944 * transaction must have happened after the block was journaled and so
12945 * the revoke must take precedence.
12946 *
12947 * Block is revoked and then written as data:
12948 * The data write is allowed to succeed, but the revoke is _not_
12949 * cancelled. We still need to prevent old log records from
12950 * overwriting the new data. We don't even need to clear the revoke
12951 * bit here.
12952 *
12953 * Revoke information on buffers is a tri-state value:
12954 *
12955 * RevokeValid clear: no cached revoke status, need to look it up
12956 * RevokeValid set, Revoked clear:
12957 * buffer has not been revoked, and cancel_revoke
12958 * need do nothing.
12959 * RevokeValid set, Revoked set:
12960 * buffer has been revoked.
12961 */
12962
12963static kmem_cache_t *revoke_record_cache;
12964static kmem_cache_t *revoke_table_cache;
12965
12966/* Each revoke record represents one single revoked block. During
12967 journal replay, this involves recording the transaction ID of the
12968 last transaction to revoke this block. */
12969
12970struct jbd_revoke_record_s
12971{
12972 struct list_head hash;
12973 tid_t sequence; /* Used for recovery only */
12974 unsigned long blocknr;
12975};
12976
12977
12978/* The revoke table is just a simple hash table of revoke records. */
12979struct jbd_revoke_table_s
12980{
12981 /* It is conceivable that we might want a larger hash table
12982 * for recovery. Must be a power of two. */
12983 int hash_size;
12984 int hash_shift;
12985 struct list_head *hash_table;
12986};
12987
12988
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012989/* Utility functions to maintain the revoke table */
12990
12991/* Borrowed from buffer.c: this is a tried and tested block hash function */
12992static inline int hash(journal_t *journal, unsigned long block)
12993{
12994 struct jbd_revoke_table_s *table = journal->j_revoke;
12995 int hash_shift = table->hash_shift;
12996
12997 return ((block << (hash_shift - 6)) ^
12998 (block >> 13) ^
12999 (block << (hash_shift - 12))) & (table->hash_size - 1);
13000}
13001
13002static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
13003 tid_t seq)
13004{
13005 struct list_head *hash_list;
13006 struct jbd_revoke_record_s *record;
13007
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013008 record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
13009 if (!record)
13010 goto oom;
13011
13012 record->sequence = seq;
13013 record->blocknr = blocknr;
13014 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13015 list_add(&record->hash, hash_list);
13016 return 0;
13017
13018oom:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013019 return -ENOMEM;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013020}
13021
13022/* Find a revoke record in the journal's hash table. */
13023
13024static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
13025 unsigned long blocknr)
13026{
13027 struct list_head *hash_list;
13028 struct jbd_revoke_record_s *record;
13029
13030 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13031
13032 record = (struct jbd_revoke_record_s *) hash_list->next;
13033 while (&(record->hash) != hash_list) {
13034 if (record->blocknr == blocknr)
13035 return record;
13036 record = (struct jbd_revoke_record_s *) record->hash.next;
13037 }
13038 return NULL;
13039}
13040
13041int journal_init_revoke_caches(void)
13042{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013043 revoke_record_cache = do_cache_create(sizeof(struct jbd_revoke_record_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013044 if (revoke_record_cache == 0)
13045 return -ENOMEM;
13046
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013047 revoke_table_cache = do_cache_create(sizeof(struct jbd_revoke_table_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013048 if (revoke_table_cache == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013049 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013050 revoke_record_cache = NULL;
13051 return -ENOMEM;
13052 }
13053 return 0;
13054}
13055
13056void journal_destroy_revoke_caches(void)
13057{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013058 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013059 revoke_record_cache = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013060 do_cache_destroy(revoke_table_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013061 revoke_table_cache = 0;
13062}
13063
13064/* Initialise the revoke table for a given journal to a given size. */
13065
13066int journal_init_revoke(journal_t *journal, int hash_size)
13067{
13068 int shift, tmp;
13069
13070 J_ASSERT (journal->j_revoke == NULL);
13071
13072 journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
13073 if (!journal->j_revoke)
13074 return -ENOMEM;
13075
13076 /* Check that the hash_size is a power of two */
13077 J_ASSERT ((hash_size & (hash_size-1)) == 0);
13078
13079 journal->j_revoke->hash_size = hash_size;
13080
13081 shift = 0;
13082 tmp = hash_size;
13083 while((tmp >>= 1UL) != 0UL)
13084 shift++;
13085 journal->j_revoke->hash_shift = shift;
13086
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013087 journal->j_revoke->hash_table = malloc(hash_size * sizeof(struct list_head));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013088 if (!journal->j_revoke->hash_table) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013089 free(journal->j_revoke);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013090 journal->j_revoke = NULL;
13091 return -ENOMEM;
13092 }
13093
13094 for (tmp = 0; tmp < hash_size; tmp++)
13095 INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
13096
13097 return 0;
13098}
13099
13100/* Destoy a journal's revoke table. The table must already be empty! */
13101
13102void journal_destroy_revoke(journal_t *journal)
13103{
13104 struct jbd_revoke_table_s *table;
13105 struct list_head *hash_list;
13106 int i;
13107
13108 table = journal->j_revoke;
13109 if (!table)
13110 return;
13111
13112 for (i=0; i<table->hash_size; i++) {
13113 hash_list = &table->hash_table[i];
13114 J_ASSERT (list_empty(hash_list));
13115 }
13116
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013117 free(table->hash_table);
13118 free(table);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013119 journal->j_revoke = NULL;
13120}
13121
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013122/*
13123 * Revoke support for recovery.
13124 *
13125 * Recovery needs to be able to:
13126 *
13127 * record all revoke records, including the tid of the latest instance
13128 * of each revoke in the journal
13129 *
13130 * check whether a given block in a given transaction should be replayed
13131 * (ie. has not been revoked by a revoke record in that or a subsequent
13132 * transaction)
13133 *
13134 * empty the revoke table after recovery.
13135 */
13136
13137/*
13138 * First, setting revoke records. We create a new revoke record for
13139 * every block ever revoked in the log as we scan it for recovery, and
13140 * we update the existing records if we find multiple revokes for a
13141 * single block.
13142 */
13143
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013144int journal_set_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013145 tid_t sequence)
13146{
13147 struct jbd_revoke_record_s *record;
13148
13149 record = find_revoke_record(journal, blocknr);
13150 if (record) {
13151 /* If we have multiple occurences, only record the
13152 * latest sequence number in the hashed record */
13153 if (tid_gt(sequence, record->sequence))
13154 record->sequence = sequence;
13155 return 0;
13156 }
13157 return insert_revoke_hash(journal, blocknr, sequence);
13158}
13159
13160/*
13161 * Test revoke records. For a given block referenced in the log, has
13162 * that block been revoked? A revoke record with a given transaction
13163 * sequence number revokes all blocks in that transaction and earlier
13164 * ones, but later transactions still need replayed.
13165 */
13166
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013167int journal_test_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013168 tid_t sequence)
13169{
13170 struct jbd_revoke_record_s *record;
13171
13172 record = find_revoke_record(journal, blocknr);
13173 if (!record)
13174 return 0;
13175 if (tid_gt(sequence, record->sequence))
13176 return 0;
13177 return 1;
13178}
13179
13180/*
13181 * Finally, once recovery is over, we need to clear the revoke table so
13182 * that it can be reused by the running filesystem.
13183 */
13184
13185void journal_clear_revoke(journal_t *journal)
13186{
13187 int i;
13188 struct list_head *hash_list;
13189 struct jbd_revoke_record_s *record;
13190 struct jbd_revoke_table_s *revoke_var;
13191
13192 revoke_var = journal->j_revoke;
13193
13194 for (i = 0; i < revoke_var->hash_size; i++) {
13195 hash_list = &revoke_var->hash_table[i];
13196 while (!list_empty(hash_list)) {
13197 record = (struct jbd_revoke_record_s*) hash_list->next;
13198 list_del(&record->hash);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013199 free(record);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013200 }
13201 }
13202}
13203
13204/*
13205 * e2fsck.c - superblock checks
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013206 */
13207
13208#define MIN_CHECK 1
13209#define MAX_CHECK 2
13210
13211static void check_super_value(e2fsck_t ctx, const char *descr,
13212 unsigned long value, int flags,
13213 unsigned long min_val, unsigned long max_val)
13214{
13215 struct problem_context pctx;
13216
13217 if (((flags & MIN_CHECK) && (value < min_val)) ||
13218 ((flags & MAX_CHECK) && (value > max_val))) {
13219 clear_problem_context(&pctx);
13220 pctx.num = value;
13221 pctx.str = descr;
13222 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
13223 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
13224 }
13225}
13226
13227/*
13228 * This routine may get stubbed out in special compilations of the
13229 * e2fsck code..
13230 */
13231#ifndef EXT2_SPECIAL_DEVICE_SIZE
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013232static errcode_t e2fsck_get_device_size(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013233{
13234 return (ext2fs_get_device_size(ctx->filesystem_name,
13235 EXT2_BLOCK_SIZE(ctx->fs->super),
13236 &ctx->num_blocks));
13237}
13238#endif
13239
13240/*
13241 * helper function to release an inode
13242 */
13243struct process_block_struct {
13244 e2fsck_t ctx;
13245 char *buf;
13246 struct problem_context *pctx;
13247 int truncating;
13248 int truncate_offset;
13249 e2_blkcnt_t truncate_block;
13250 int truncated_blocks;
13251 int abort;
13252 errcode_t errcode;
13253};
13254
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013255static int release_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013256 e2_blkcnt_t blockcnt,
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000013257 blk_t ref_blk FSCK_ATTR((unused)),
13258 int ref_offset FSCK_ATTR((unused)),
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013259 void *priv_data)
13260{
13261 struct process_block_struct *pb;
13262 e2fsck_t ctx;
13263 struct problem_context *pctx;
13264 blk_t blk = *block_nr;
13265 int retval = 0;
13266
13267 pb = (struct process_block_struct *) priv_data;
13268 ctx = pb->ctx;
13269 pctx = pb->pctx;
13270
13271 pctx->blk = blk;
13272 pctx->blkcount = blockcnt;
13273
13274 if (HOLE_BLKADDR(blk))
13275 return 0;
13276
13277 if ((blk < fs->super->s_first_data_block) ||
13278 (blk >= fs->super->s_blocks_count)) {
13279 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
13280 return_abort:
13281 pb->abort = 1;
13282 return BLOCK_ABORT;
13283 }
13284
13285 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
13286 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
13287 goto return_abort;
13288 }
13289
13290 /*
13291 * If we are deleting an orphan, then we leave the fields alone.
13292 * If we are truncating an orphan, then update the inode fields
13293 * and clean up any partial block data.
13294 */
13295 if (pb->truncating) {
13296 /*
13297 * We only remove indirect blocks if they are
13298 * completely empty.
13299 */
13300 if (blockcnt < 0) {
13301 int i, limit;
13302 blk_t *bp;
13303
13304 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
13305 pb->buf);
13306 if (pb->errcode)
13307 goto return_abort;
13308
13309 limit = fs->blocksize >> 2;
13310 for (i = 0, bp = (blk_t *) pb->buf;
13311 i < limit; i++, bp++)
13312 if (*bp)
13313 return 0;
13314 }
13315 /*
13316 * We don't remove direct blocks until we've reached
13317 * the truncation block.
13318 */
13319 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
13320 return 0;
13321 /*
13322 * If part of the last block needs truncating, we do
13323 * it here.
13324 */
13325 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
13326 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
13327 pb->buf);
13328 if (pb->errcode)
13329 goto return_abort;
13330 memset(pb->buf + pb->truncate_offset, 0,
13331 fs->blocksize - pb->truncate_offset);
13332 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
13333 pb->buf);
13334 if (pb->errcode)
13335 goto return_abort;
13336 }
13337 pb->truncated_blocks++;
13338 *block_nr = 0;
13339 retval |= BLOCK_CHANGED;
13340 }
13341
13342 ext2fs_block_alloc_stats(fs, blk, -1);
13343 return retval;
13344}
13345
13346/*
13347 * This function releases an inode. Returns 1 if an inconsistency was
13348 * found. If the inode has a link count, then it is being truncated and
13349 * not deleted.
13350 */
13351static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
13352 struct ext2_inode *inode, char *block_buf,
13353 struct problem_context *pctx)
13354{
13355 struct process_block_struct pb;
13356 ext2_filsys fs = ctx->fs;
13357 errcode_t retval;
13358 __u32 count;
13359
13360 if (!ext2fs_inode_has_valid_blocks(inode))
13361 return 0;
13362
13363 pb.buf = block_buf + 3 * ctx->fs->blocksize;
13364 pb.ctx = ctx;
13365 pb.abort = 0;
13366 pb.errcode = 0;
13367 pb.pctx = pctx;
13368 if (inode->i_links_count) {
13369 pb.truncating = 1;
13370 pb.truncate_block = (e2_blkcnt_t)
13371 ((((long long)inode->i_size_high << 32) +
13372 inode->i_size + fs->blocksize - 1) /
13373 fs->blocksize);
13374 pb.truncate_offset = inode->i_size % fs->blocksize;
13375 } else {
13376 pb.truncating = 0;
13377 pb.truncate_block = 0;
13378 pb.truncate_offset = 0;
13379 }
13380 pb.truncated_blocks = 0;
13381 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
13382 block_buf, release_inode_block, &pb);
13383 if (retval) {
13384 com_err("release_inode_blocks", retval,
13385 _("while calling ext2fs_block_iterate for inode %d"),
13386 ino);
13387 return 1;
13388 }
13389 if (pb.abort)
13390 return 1;
13391
13392 /* Refresh the inode since ext2fs_block_iterate may have changed it */
13393 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
13394
13395 if (pb.truncated_blocks)
13396 inode->i_blocks -= pb.truncated_blocks *
13397 (fs->blocksize / 512);
13398
13399 if (inode->i_file_acl) {
13400 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
13401 block_buf, -1, &count);
13402 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
13403 retval = 0;
13404 count = 1;
13405 }
13406 if (retval) {
13407 com_err("release_inode_blocks", retval,
13408 _("while calling ext2fs_adjust_ea_refocunt for inode %d"),
13409 ino);
13410 return 1;
13411 }
13412 if (count == 0)
13413 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
13414 inode->i_file_acl = 0;
13415 }
13416 return 0;
13417}
13418
13419/*
13420 * This function releases all of the orphan inodes. It returns 1 if
13421 * it hit some error, and 0 on success.
13422 */
13423static int release_orphan_inodes(e2fsck_t ctx)
13424{
13425 ext2_filsys fs = ctx->fs;
13426 ext2_ino_t ino, next_ino;
13427 struct ext2_inode inode;
13428 struct problem_context pctx;
13429 char *block_buf;
13430
13431 if ((ino = fs->super->s_last_orphan) == 0)
13432 return 0;
13433
13434 /*
13435 * Win or lose, we won't be using the head of the orphan inode
13436 * list again.
13437 */
13438 fs->super->s_last_orphan = 0;
13439 ext2fs_mark_super_dirty(fs);
13440
13441 /*
13442 * If the filesystem contains errors, don't run the orphan
13443 * list, since the orphan list can't be trusted; and we're
13444 * going to be running a full e2fsck run anyway...
13445 */
13446 if (fs->super->s_state & EXT2_ERROR_FS)
13447 return 0;
13448
13449 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
13450 (ino > fs->super->s_inodes_count)) {
13451 clear_problem_context(&pctx);
13452 pctx.ino = ino;
13453 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
13454 return 1;
13455 }
13456
13457 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
13458 "block iterate buffer");
13459 e2fsck_read_bitmaps(ctx);
13460
13461 while (ino) {
13462 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
13463 clear_problem_context(&pctx);
13464 pctx.ino = ino;
13465 pctx.inode = &inode;
13466 pctx.str = inode.i_links_count ? _("Truncating") :
13467 _("Clearing");
13468
13469 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
13470
13471 next_ino = inode.i_dtime;
13472 if (next_ino &&
13473 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
13474 (next_ino > fs->super->s_inodes_count))) {
13475 pctx.ino = next_ino;
13476 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
13477 goto return_abort;
13478 }
13479
13480 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
13481 goto return_abort;
13482
13483 if (!inode.i_links_count) {
13484 ext2fs_inode_alloc_stats2(fs, ino, -1,
13485 LINUX_S_ISDIR(inode.i_mode));
13486 inode.i_dtime = time(0);
13487 } else {
13488 inode.i_dtime = 0;
13489 }
13490 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
13491 ino = next_ino;
13492 }
13493 ext2fs_free_mem(&block_buf);
13494 return 0;
13495return_abort:
13496 ext2fs_free_mem(&block_buf);
13497 return 1;
13498}
13499
13500/*
13501 * Check the resize inode to make sure it is sane. We check both for
13502 * the case where on-line resizing is not enabled (in which case the
13503 * resize inode should be cleared) as well as the case where on-line
13504 * resizing is enabled.
13505 */
13506static void check_resize_inode(e2fsck_t ctx)
13507{
13508 ext2_filsys fs = ctx->fs;
13509 struct ext2_inode inode;
13510 struct problem_context pctx;
13511 int i, j, gdt_off, ind_off;
13512 blk_t blk, pblk, expect;
13513 __u32 *dind_buf = 0, *ind_buf;
13514 errcode_t retval;
13515
13516 clear_problem_context(&pctx);
13517
13518 /*
13519 * If the resize inode feature isn't set, then
13520 * s_reserved_gdt_blocks must be zero.
13521 */
13522 if (!(fs->super->s_feature_compat &
13523 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
13524 if (fs->super->s_reserved_gdt_blocks) {
13525 pctx.num = fs->super->s_reserved_gdt_blocks;
13526 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
13527 &pctx)) {
13528 fs->super->s_reserved_gdt_blocks = 0;
13529 ext2fs_mark_super_dirty(fs);
13530 }
13531 }
13532 }
13533
Mike Frysinger874af852006-03-08 07:03:27 +000013534 /* Read the resize inode */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013535 pctx.ino = EXT2_RESIZE_INO;
13536 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
13537 if (retval) {
13538 if (fs->super->s_feature_compat &
13539 EXT2_FEATURE_COMPAT_RESIZE_INODE)
13540 ctx->flags |= E2F_FLAG_RESIZE_INODE;
13541 return;
13542 }
13543
13544 /*
13545 * If the resize inode feature isn't set, check to make sure
13546 * the resize inode is cleared; then we're done.
13547 */
13548 if (!(fs->super->s_feature_compat &
13549 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
13550 for (i=0; i < EXT2_N_BLOCKS; i++) {
13551 if (inode.i_block[i])
13552 break;
13553 }
13554 if ((i < EXT2_N_BLOCKS) &&
13555 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
13556 memset(&inode, 0, sizeof(inode));
13557 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
13558 "clear_resize");
13559 }
13560 return;
13561 }
13562
13563 /*
13564 * The resize inode feature is enabled; check to make sure the
13565 * only block in use is the double indirect block
13566 */
13567 blk = inode.i_block[EXT2_DIND_BLOCK];
13568 for (i=0; i < EXT2_N_BLOCKS; i++) {
13569 if (i != EXT2_DIND_BLOCK && inode.i_block[i])
13570 break;
13571 }
13572 if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
13573 !(inode.i_mode & LINUX_S_IFREG) ||
13574 (blk < fs->super->s_first_data_block ||
13575 blk >= fs->super->s_blocks_count)) {
13576 resize_inode_invalid:
13577 if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
13578 memset(&inode, 0, sizeof(inode));
13579 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
13580 "clear_resize");
13581 ctx->flags |= E2F_FLAG_RESIZE_INODE;
13582 }
13583 if (!(ctx->options & E2F_OPT_READONLY)) {
13584 fs->super->s_state &= ~EXT2_VALID_FS;
13585 ext2fs_mark_super_dirty(fs);
13586 }
13587 goto cleanup;
13588 }
13589 dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
13590 "resize dind buffer");
13591 ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
13592
13593 retval = ext2fs_read_ind_block(fs, blk, dind_buf);
13594 if (retval)
13595 goto resize_inode_invalid;
13596
13597 gdt_off = fs->desc_blocks;
13598 pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
13599 for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
13600 i++, gdt_off++, pblk++) {
13601 gdt_off %= fs->blocksize/4;
13602 if (dind_buf[gdt_off] != pblk)
13603 goto resize_inode_invalid;
13604 retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
13605 if (retval)
13606 goto resize_inode_invalid;
13607 ind_off = 0;
13608 for (j = 1; j < fs->group_desc_count; j++) {
13609 if (!ext2fs_bg_has_super(fs, j))
13610 continue;
13611 expect = pblk + (j * fs->super->s_blocks_per_group);
13612 if (ind_buf[ind_off] != expect)
13613 goto resize_inode_invalid;
13614 ind_off++;
13615 }
13616 }
13617
13618cleanup:
Rob Landleye7c43b62006-03-01 16:39:45 +000013619 ext2fs_free_mem(&dind_buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013620
13621 }
13622
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013623static void check_super_block(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013624{
13625 ext2_filsys fs = ctx->fs;
13626 blk_t first_block, last_block;
13627 struct ext2_super_block *sb = fs->super;
13628 struct ext2_group_desc *gd;
13629 blk_t blocks_per_group = fs->super->s_blocks_per_group;
13630 blk_t bpg_max;
13631 int inodes_per_block;
13632 int ipg_max;
13633 int inode_size;
13634 dgrp_t i;
13635 blk_t should_be;
13636 struct problem_context pctx;
13637 __u32 free_blocks = 0, free_inodes = 0;
13638
13639 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
13640 ipg_max = inodes_per_block * (blocks_per_group - 4);
13641 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
13642 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
13643 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
13644 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
13645 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
13646
13647 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
13648 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
13649 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
13650 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
13651 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
13652 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
13653
13654 clear_problem_context(&pctx);
13655
13656 /*
13657 * Verify the super block constants...
13658 */
13659 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
13660 MIN_CHECK, 1, 0);
13661 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
13662 MIN_CHECK, 1, 0);
13663 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
13664 MAX_CHECK, 0, sb->s_blocks_count);
13665 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
13666 MIN_CHECK | MAX_CHECK, 0,
13667 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
13668 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
13669 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
13670 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
13671 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
13672 bpg_max);
13673 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
13674 MIN_CHECK | MAX_CHECK, 8, bpg_max);
13675 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
13676 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
13677 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
13678 MAX_CHECK, 0, sb->s_blocks_count / 2);
13679 check_super_value(ctx, "reserved_gdt_blocks",
13680 sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
13681 fs->blocksize/4);
13682 inode_size = EXT2_INODE_SIZE(sb);
13683 check_super_value(ctx, "inode_size",
13684 inode_size, MIN_CHECK | MAX_CHECK,
13685 EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
13686 if (inode_size & (inode_size - 1)) {
13687 pctx.num = inode_size;
13688 pctx.str = "inode_size";
13689 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
13690 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
13691 return;
13692 }
13693
13694 if (!ctx->num_blocks) {
13695 pctx.errcode = e2fsck_get_device_size(ctx);
13696 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
13697 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
13698 ctx->flags |= E2F_FLAG_ABORT;
13699 return;
13700 }
13701 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
13702 (ctx->num_blocks < sb->s_blocks_count)) {
13703 pctx.blk = sb->s_blocks_count;
13704 pctx.blk2 = ctx->num_blocks;
13705 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
13706 ctx->flags |= E2F_FLAG_ABORT;
13707 return;
13708 }
13709 }
13710 }
13711
13712 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
13713 pctx.blk = EXT2_BLOCK_SIZE(sb);
13714 pctx.blk2 = EXT2_FRAG_SIZE(sb);
13715 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
13716 ctx->flags |= E2F_FLAG_ABORT;
13717 return;
13718 }
13719
13720 should_be = sb->s_frags_per_group >>
13721 (sb->s_log_block_size - sb->s_log_frag_size);
13722 if (sb->s_blocks_per_group != should_be) {
13723 pctx.blk = sb->s_blocks_per_group;
13724 pctx.blk2 = should_be;
13725 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
13726 ctx->flags |= E2F_FLAG_ABORT;
13727 return;
13728 }
13729
13730 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
13731 if (sb->s_first_data_block != should_be) {
13732 pctx.blk = sb->s_first_data_block;
13733 pctx.blk2 = should_be;
13734 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
13735 ctx->flags |= E2F_FLAG_ABORT;
13736 return;
13737 }
13738
13739 should_be = sb->s_inodes_per_group * fs->group_desc_count;
13740 if (sb->s_inodes_count != should_be) {
13741 pctx.ino = sb->s_inodes_count;
13742 pctx.ino2 = should_be;
13743 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
13744 sb->s_inodes_count = should_be;
13745 ext2fs_mark_super_dirty(fs);
13746 }
13747 }
13748
13749 /*
13750 * Verify the group descriptors....
13751 */
13752 first_block = sb->s_first_data_block;
13753 last_block = first_block + blocks_per_group;
13754
13755 for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
13756 pctx.group = i;
13757
13758 if (i == fs->group_desc_count - 1)
13759 last_block = sb->s_blocks_count;
13760 if ((gd->bg_block_bitmap < first_block) ||
13761 (gd->bg_block_bitmap >= last_block)) {
13762 pctx.blk = gd->bg_block_bitmap;
13763 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
13764 gd->bg_block_bitmap = 0;
13765 }
13766 if (gd->bg_block_bitmap == 0) {
13767 ctx->invalid_block_bitmap_flag[i]++;
13768 ctx->invalid_bitmaps++;
13769 }
13770 if ((gd->bg_inode_bitmap < first_block) ||
13771 (gd->bg_inode_bitmap >= last_block)) {
13772 pctx.blk = gd->bg_inode_bitmap;
13773 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
13774 gd->bg_inode_bitmap = 0;
13775 }
13776 if (gd->bg_inode_bitmap == 0) {
13777 ctx->invalid_inode_bitmap_flag[i]++;
13778 ctx->invalid_bitmaps++;
13779 }
13780 if ((gd->bg_inode_table < first_block) ||
13781 ((gd->bg_inode_table +
13782 fs->inode_blocks_per_group - 1) >= last_block)) {
13783 pctx.blk = gd->bg_inode_table;
13784 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
13785 gd->bg_inode_table = 0;
13786 }
13787 if (gd->bg_inode_table == 0) {
13788 ctx->invalid_inode_table_flag[i]++;
13789 ctx->invalid_bitmaps++;
13790 }
13791 free_blocks += gd->bg_free_blocks_count;
13792 free_inodes += gd->bg_free_inodes_count;
13793 first_block += sb->s_blocks_per_group;
13794 last_block += sb->s_blocks_per_group;
13795
13796 if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
13797 (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
13798 (gd->bg_used_dirs_count > sb->s_inodes_per_group))
13799 ext2fs_unmark_valid(fs);
13800
13801 }
13802
13803 /*
13804 * Update the global counts from the block group counts. This
13805 * is needed for an experimental patch which eliminates
13806 * locking the entire filesystem when allocating blocks or
13807 * inodes; if the filesystem is not unmounted cleanly, the
13808 * global counts may not be accurate.
13809 */
13810 if ((free_blocks != sb->s_free_blocks_count) ||
13811 (free_inodes != sb->s_free_inodes_count)) {
13812 if (ctx->options & E2F_OPT_READONLY)
13813 ext2fs_unmark_valid(fs);
13814 else {
13815 sb->s_free_blocks_count = free_blocks;
13816 sb->s_free_inodes_count = free_inodes;
13817 ext2fs_mark_super_dirty(fs);
13818 }
13819 }
13820
13821 if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
13822 (sb->s_free_inodes_count > sb->s_inodes_count))
13823 ext2fs_unmark_valid(fs);
13824
13825
13826 /*
13827 * If we have invalid bitmaps, set the error state of the
13828 * filesystem.
13829 */
13830 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
13831 sb->s_state &= ~EXT2_VALID_FS;
13832 ext2fs_mark_super_dirty(fs);
13833 }
13834
13835 clear_problem_context(&pctx);
13836
13837#ifndef EXT2_SKIP_UUID
13838 /*
13839 * If the UUID field isn't assigned, assign it.
13840 */
13841 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
13842 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
13843 uuid_generate(sb->s_uuid);
13844 ext2fs_mark_super_dirty(fs);
13845 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
13846 }
13847 }
13848#endif
13849
13850 /*
13851 * For the Hurd, check to see if the filetype option is set,
13852 * since it doesn't support it.
13853 */
13854 if (!(ctx->options & E2F_OPT_READONLY) &&
13855 fs->super->s_creator_os == EXT2_OS_HURD &&
13856 (fs->super->s_feature_incompat &
13857 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
13858 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
13859 fs->super->s_feature_incompat &=
13860 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
13861 ext2fs_mark_super_dirty(fs);
13862
13863 }
13864 }
13865
13866 /*
13867 * If we have any of the compatibility flags set, we need to have a
13868 * revision 1 filesystem. Most kernels will not check the flags on
13869 * a rev 0 filesystem and we may have corruption issues because of
13870 * the incompatible changes to the filesystem.
13871 */
13872 if (!(ctx->options & E2F_OPT_READONLY) &&
13873 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
13874 (fs->super->s_feature_compat ||
13875 fs->super->s_feature_ro_compat ||
13876 fs->super->s_feature_incompat) &&
13877 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
13878 ext2fs_update_dynamic_rev(fs);
13879 ext2fs_mark_super_dirty(fs);
13880 }
13881
13882 check_resize_inode(ctx);
13883
13884 /*
13885 * Clean up any orphan inodes, if present.
13886 */
13887 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
13888 fs->super->s_state &= ~EXT2_VALID_FS;
13889 ext2fs_mark_super_dirty(fs);
13890 }
13891
13892 /*
13893 * Move the ext3 journal file, if necessary.
13894 */
13895 e2fsck_move_ext3_journal(ctx);
13896 return;
13897}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013898
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013899/*
13900 * swapfs.c --- byte-swap an ext2 filesystem
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013901 */
13902
13903#ifdef ENABLE_SWAPFS
13904
13905struct swap_block_struct {
13906 ext2_ino_t ino;
13907 int isdir;
13908 errcode_t errcode;
13909 char *dir_buf;
13910 struct ext2_inode *inode;
13911};
13912
13913/*
13914 * This is a helper function for block_iterate. We mark all of the
13915 * indirect and direct blocks as changed, so that block_iterate will
13916 * write them out.
13917 */
13918static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
13919 void *priv_data)
13920{
13921 errcode_t retval;
13922
13923 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
13924
13925 if (sb->isdir && (blockcnt >= 0) && *block_nr) {
13926 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
13927 if (retval) {
13928 sb->errcode = retval;
13929 return BLOCK_ABORT;
13930 }
13931 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
13932 if (retval) {
13933 sb->errcode = retval;
13934 return BLOCK_ABORT;
13935 }
13936 }
13937 if (blockcnt >= 0) {
13938 if (blockcnt < EXT2_NDIR_BLOCKS)
13939 return 0;
13940 return BLOCK_CHANGED;
13941 }
13942 if (blockcnt == BLOCK_COUNT_IND) {
13943 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
13944 return 0;
13945 return BLOCK_CHANGED;
13946 }
13947 if (blockcnt == BLOCK_COUNT_DIND) {
13948 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
13949 return 0;
13950 return BLOCK_CHANGED;
13951 }
13952 if (blockcnt == BLOCK_COUNT_TIND) {
13953 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
13954 return 0;
13955 return BLOCK_CHANGED;
13956 }
13957 return BLOCK_CHANGED;
13958}
13959
13960/*
13961 * This function is responsible for byte-swapping all of the indirect,
13962 * block pointers. It is also responsible for byte-swapping directories.
13963 */
13964static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
13965 struct ext2_inode *inode)
13966{
13967 errcode_t retval;
13968 struct swap_block_struct sb;
13969
13970 sb.ino = ino;
13971 sb.inode = inode;
13972 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
13973 sb.errcode = 0;
13974 sb.isdir = 0;
13975 if (LINUX_S_ISDIR(inode->i_mode))
13976 sb.isdir = 1;
13977
13978 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
13979 swap_block, &sb);
13980 if (retval) {
13981 com_err("swap_inode_blocks", retval,
13982 _("while calling ext2fs_block_iterate"));
13983 ctx->flags |= E2F_FLAG_ABORT;
13984 return;
13985 }
13986 if (sb.errcode) {
13987 com_err("swap_inode_blocks", sb.errcode,
13988 _("while calling iterator function"));
13989 ctx->flags |= E2F_FLAG_ABORT;
13990 return;
13991 }
13992}
13993
13994static void swap_inodes(e2fsck_t ctx)
13995{
13996 ext2_filsys fs = ctx->fs;
13997 dgrp_t group;
13998 unsigned int i;
13999 ext2_ino_t ino = 1;
14000 char *buf, *block_buf;
14001 errcode_t retval;
14002 struct ext2_inode * inode;
14003
14004 e2fsck_use_inode_shortcuts(ctx, 1);
14005
14006 retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
14007 &buf);
14008 if (retval) {
14009 com_err("swap_inodes", retval,
14010 _("while allocating inode buffer"));
14011 ctx->flags |= E2F_FLAG_ABORT;
14012 return;
14013 }
14014 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
14015 "block interate buffer");
14016 for (group = 0; group < fs->group_desc_count; group++) {
14017 retval = io_channel_read_blk(fs->io,
14018 fs->group_desc[group].bg_inode_table,
14019 fs->inode_blocks_per_group, buf);
14020 if (retval) {
14021 com_err("swap_inodes", retval,
14022 _("while reading inode table (group %d)"),
14023 group);
14024 ctx->flags |= E2F_FLAG_ABORT;
14025 return;
14026 }
14027 inode = (struct ext2_inode *) buf;
14028 for (i=0; i < fs->super->s_inodes_per_group;
14029 i++, ino++, inode++) {
14030 ctx->stashed_ino = ino;
14031 ctx->stashed_inode = inode;
14032
14033 if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
14034 ext2fs_swap_inode(fs, inode, inode, 0);
14035
14036 /*
14037 * Skip deleted files.
14038 */
14039 if (inode->i_links_count == 0)
14040 continue;
14041
14042 if (LINUX_S_ISDIR(inode->i_mode) ||
14043 ((inode->i_block[EXT2_IND_BLOCK] ||
14044 inode->i_block[EXT2_DIND_BLOCK] ||
14045 inode->i_block[EXT2_TIND_BLOCK]) &&
14046 ext2fs_inode_has_valid_blocks(inode)))
14047 swap_inode_blocks(ctx, ino, block_buf, inode);
14048
14049 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14050 return;
14051
14052 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14053 ext2fs_swap_inode(fs, inode, inode, 1);
14054 }
14055 retval = io_channel_write_blk(fs->io,
14056 fs->group_desc[group].bg_inode_table,
14057 fs->inode_blocks_per_group, buf);
14058 if (retval) {
14059 com_err("swap_inodes", retval,
14060 _("while writing inode table (group %d)"),
14061 group);
14062 ctx->flags |= E2F_FLAG_ABORT;
14063 return;
14064 }
14065 }
14066 ext2fs_free_mem(&buf);
14067 ext2fs_free_mem(&block_buf);
14068 e2fsck_use_inode_shortcuts(ctx, 0);
14069 ext2fs_flush_icache(fs);
14070}
14071
14072#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
14073/*
14074 * On the PowerPC, the big-endian variant of the ext2 filesystem
14075 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
14076 * of each word. Thus a bitmap with only bit 0 set would be, as
14077 * a string of bytes, 00 00 00 01 00 ...
14078 * To cope with this, we byte-reverse each word of a bitmap if
14079 * we have a big-endian filesystem, that is, if we are *not*
14080 * byte-swapping other word-sized numbers.
14081 */
14082#define EXT2_BIG_ENDIAN_BITMAPS
14083#endif
14084
14085#ifdef EXT2_BIG_ENDIAN_BITMAPS
14086static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
14087{
14088 __u32 *p = (__u32 *) bmap->bitmap;
14089 int n, nbytes = (bmap->end - bmap->start + 7) / 8;
14090
14091 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
14092 *p = ext2fs_swab32(*p);
14093}
14094#endif
14095
14096
14097#ifdef ENABLE_SWAPFS
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014098static void swap_filesys(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014099{
14100 ext2_filsys fs = ctx->fs;
14101#ifdef RESOURCE_TRACK
14102 struct resource_track rtrack;
14103
14104 init_resource_track(&rtrack);
14105#endif
14106
14107 if (!(ctx->options & E2F_OPT_PREEN))
14108 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
14109
14110#ifdef MTRACE
14111 mtrace_print("Byte swap");
14112#endif
14113
14114 if (fs->super->s_mnt_count) {
14115 fprintf(stderr, _("%s: the filesystem must be freshly "
14116 "checked using fsck\n"
14117 "and not mounted before trying to "
14118 "byte-swap it.\n"), ctx->device_name);
14119 ctx->flags |= E2F_FLAG_ABORT;
14120 return;
14121 }
14122 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
14123 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
14124 EXT2_FLAG_SWAP_BYTES_WRITE);
14125 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
14126 } else {
14127 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
14128 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
14129 }
14130 swap_inodes(ctx);
14131 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14132 return;
14133 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14134 fs->flags |= EXT2_FLAG_SWAP_BYTES;
14135 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
14136 EXT2_FLAG_SWAP_BYTES_WRITE);
14137
14138#ifdef EXT2_BIG_ENDIAN_BITMAPS
14139 e2fsck_read_bitmaps(ctx);
14140 ext2fs_swap_bitmap(fs->inode_map);
14141 ext2fs_swap_bitmap(fs->block_map);
14142 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
14143#endif
14144 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
14145 ext2fs_flush(fs);
14146 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
14147
14148#ifdef RESOURCE_TRACK
14149 if (ctx->options & E2F_OPT_TIME2)
14150 print_resource_track(_("Byte swap"), &rtrack);
14151#endif
14152}
14153#endif /* ENABLE_SWAPFS */
14154
14155#endif
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014156
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014157/*
14158 * util.c --- miscellaneous utilities
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014159 */
14160
14161#ifdef HAVE_CONIO_H
14162#undef HAVE_TERMIOS_H
14163#include <conio.h>
14164#define read_a_char() getch()
14165#else
14166#ifdef HAVE_TERMIOS_H
14167#include <termios.h>
14168#endif
14169#endif
14170
14171#if 0
14172void fatal_error(e2fsck_t ctx, const char *msg)
14173{
14174 if (msg)
14175 fprintf (stderr, "e2fsck: %s\n", msg);
14176 if (ctx->fs && ctx->fs->io) {
14177 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
14178 io_channel_flush(ctx->fs->io);
14179 else
14180 fprintf(stderr, "e2fsck: io manager magic bad!\n");
14181 }
14182 ctx->flags |= E2F_FLAG_ABORT;
14183 if (ctx->flags & E2F_FLAG_SETJMP_OK)
14184 longjmp(ctx->abort_loc, 1);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014185 exit(EXIT_ERROR);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014186}
14187#endif
14188
14189void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
14190 const char *description)
14191{
14192 void *ret;
14193 char buf[256];
14194
14195#ifdef DEBUG_ALLOCATE_MEMORY
14196 printf("Allocating %d bytes for %s...\n", size, description);
14197#endif
14198 ret = malloc(size);
14199 if (!ret) {
14200 sprintf(buf, "Can't allocate %s\n", description);
14201 fatal_error(ctx, buf);
14202 }
14203 memset(ret, 0, size);
14204 return ret;
14205}
14206
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014207static char *string_copy(const char *str, int len)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014208{
14209 char *ret;
14210
14211 if (!str)
14212 return NULL;
14213 if (!len)
14214 len = strlen(str);
14215 ret = malloc(len+1);
14216 if (ret) {
14217 strncpy(ret, str, len);
14218 ret[len] = 0;
14219 }
14220 return ret;
14221}
14222
14223#ifndef HAVE_CONIO_H
14224static int read_a_char(void)
14225{
14226 char c;
14227 int r;
14228 int fail = 0;
14229
14230 while(1) {
14231 if (e2fsck_global_ctx &&
14232 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
14233 return 3;
14234 }
14235 r = read(0, &c, 1);
14236 if (r == 1)
14237 return c;
14238 if (fail++ > 100)
14239 break;
14240 }
14241 return EOF;
14242}
14243#endif
14244
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014245static int ask_yn(const char * string, int def)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014246{
14247 int c;
14248 const char *defstr;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014249 static const char short_yes[] = "yY";
14250 static const char short_no[] = "nN";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014251
14252#ifdef HAVE_TERMIOS_H
14253 struct termios termios, tmp;
14254
14255 tcgetattr (0, &termios);
14256 tmp = termios;
14257 tmp.c_lflag &= ~(ICANON | ECHO);
14258 tmp.c_cc[VMIN] = 1;
14259 tmp.c_cc[VTIME] = 0;
14260 tcsetattr (0, TCSANOW, &tmp);
14261#endif
14262
14263 if (def == 1)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014264 defstr = "<y>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014265 else if (def == 0)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014266 defstr = "<n>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014267 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014268 defstr = " (y/n)";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014269 printf("%s%s? ", string, defstr);
14270 while (1) {
14271 fflush (stdout);
14272 if ((c = read_a_char()) == EOF)
14273 break;
14274 if (c == 3) {
14275#ifdef HAVE_TERMIOS_H
14276 tcsetattr (0, TCSANOW, &termios);
14277#endif
14278 if (e2fsck_global_ctx &&
14279 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
14280 puts("\n");
14281 longjmp(e2fsck_global_ctx->abort_loc, 1);
14282 }
14283 puts(_("cancelled!\n"));
14284 return 0;
14285 }
14286 if (strchr(short_yes, (char) c)) {
14287 def = 1;
14288 break;
14289 }
14290 else if (strchr(short_no, (char) c)) {
14291 def = 0;
14292 break;
14293 }
14294 else if ((c == ' ' || c == '\n') && (def != -1))
14295 break;
14296 }
14297 if (def)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014298 puts("yes\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014299 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014300 puts ("no\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014301#ifdef HAVE_TERMIOS_H
14302 tcsetattr (0, TCSANOW, &termios);
14303#endif
14304 return def;
14305}
14306
14307int ask (e2fsck_t ctx, const char * string, int def)
14308{
14309 if (ctx->options & E2F_OPT_NO) {
14310 printf (_("%s? no\n\n"), string);
14311 return 0;
14312 }
14313 if (ctx->options & E2F_OPT_YES) {
14314 printf (_("%s? yes\n\n"), string);
14315 return 1;
14316 }
14317 if (ctx->options & E2F_OPT_PREEN) {
14318 printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
14319 return def;
14320 }
14321 return ask_yn(string, def);
14322}
14323
14324void e2fsck_read_bitmaps(e2fsck_t ctx)
14325{
14326 ext2_filsys fs = ctx->fs;
14327 errcode_t retval;
14328
14329 if (ctx->invalid_bitmaps) {
14330 com_err(ctx->program_name, 0,
14331 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
14332 ctx->device_name);
14333 fatal_error(ctx, 0);
14334 }
14335
14336 ehandler_operation(_("reading inode and block bitmaps"));
14337 retval = ext2fs_read_bitmaps(fs);
14338 ehandler_operation(0);
14339 if (retval) {
14340 com_err(ctx->program_name, retval,
14341 _("while retrying to read bitmaps for %s"),
14342 ctx->device_name);
14343 fatal_error(ctx, 0);
14344 }
14345}
14346
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014347static void e2fsck_write_bitmaps(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014348{
14349 ext2_filsys fs = ctx->fs;
14350 errcode_t retval;
14351
14352 if (ext2fs_test_bb_dirty(fs)) {
14353 ehandler_operation(_("writing block bitmaps"));
14354 retval = ext2fs_write_block_bitmap(fs);
14355 ehandler_operation(0);
14356 if (retval) {
14357 com_err(ctx->program_name, retval,
14358 _("while retrying to write block bitmaps for %s"),
14359 ctx->device_name);
14360 fatal_error(ctx, 0);
14361 }
14362 }
14363
14364 if (ext2fs_test_ib_dirty(fs)) {
14365 ehandler_operation(_("writing inode bitmaps"));
14366 retval = ext2fs_write_inode_bitmap(fs);
14367 ehandler_operation(0);
14368 if (retval) {
14369 com_err(ctx->program_name, retval,
14370 _("while retrying to write inode bitmaps for %s"),
14371 ctx->device_name);
14372 fatal_error(ctx, 0);
14373 }
14374 }
14375}
14376
14377void preenhalt(e2fsck_t ctx)
14378{
14379 ext2_filsys fs = ctx->fs;
14380
14381 if (!(ctx->options & E2F_OPT_PREEN))
14382 return;
14383 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
14384 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
14385 ctx->device_name);
14386 if (fs != NULL) {
14387 fs->super->s_state |= EXT2_ERROR_FS;
14388 ext2fs_mark_super_dirty(fs);
14389 ext2fs_close(fs);
14390 }
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014391 exit(EXIT_UNCORRECTED);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014392}
14393
14394#ifdef RESOURCE_TRACK
14395void init_resource_track(struct resource_track *track)
14396{
14397#ifdef HAVE_GETRUSAGE
14398 struct rusage r;
14399#endif
14400
14401 track->brk_start = sbrk(0);
14402 gettimeofday(&track->time_start, 0);
14403#ifdef HAVE_GETRUSAGE
14404#ifdef sun
14405 memset(&r, 0, sizeof(struct rusage));
14406#endif
14407 getrusage(RUSAGE_SELF, &r);
14408 track->user_start = r.ru_utime;
14409 track->system_start = r.ru_stime;
14410#else
14411 track->user_start.tv_sec = track->user_start.tv_usec = 0;
14412 track->system_start.tv_sec = track->system_start.tv_usec = 0;
14413#endif
14414}
14415
14416static _INLINE_ float timeval_subtract(struct timeval *tv1,
14417 struct timeval *tv2)
14418{
14419 return ((tv1->tv_sec - tv2->tv_sec) +
14420 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
14421}
14422
14423void print_resource_track(const char *desc, struct resource_track *track)
14424{
14425#ifdef HAVE_GETRUSAGE
14426 struct rusage r;
14427#endif
14428#ifdef HAVE_MALLINFO
14429 struct mallinfo malloc_info;
14430#endif
14431 struct timeval time_end;
14432
14433 gettimeofday(&time_end, 0);
14434
14435 if (desc)
14436 printf("%s: ", desc);
14437
14438#ifdef HAVE_MALLINFO
14439#define kbytes(x) (((x) + 1023) / 1024)
14440
14441 malloc_info = mallinfo();
14442 printf(_("Memory used: %dk/%dk (%dk/%dk), "),
14443 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
14444 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
14445#else
14446 printf(_("Memory used: %d, "),
14447 (int) (((char *) sbrk(0)) - ((char *) track->brk_start)));
14448#endif
14449#ifdef HAVE_GETRUSAGE
14450 getrusage(RUSAGE_SELF, &r);
14451
14452 printf(_("time: %5.2f/%5.2f/%5.2f\n"),
14453 timeval_subtract(&time_end, &track->time_start),
14454 timeval_subtract(&r.ru_utime, &track->user_start),
14455 timeval_subtract(&r.ru_stime, &track->system_start));
14456#else
14457 printf(_("elapsed time: %6.3f\n"),
14458 timeval_subtract(&time_end, &track->time_start));
14459#endif
14460}
14461#endif /* RESOURCE_TRACK */
14462
14463void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
14464 struct ext2_inode * inode, const char *proc)
14465{
14466 int retval;
14467
14468 retval = ext2fs_read_inode(ctx->fs, ino, inode);
14469 if (retval) {
14470 com_err("ext2fs_read_inode", retval,
14471 _("while reading inode %ld in %s"), ino, proc);
14472 fatal_error(ctx, 0);
14473 }
14474}
14475
14476extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
14477 struct ext2_inode * inode, int bufsize,
14478 const char *proc)
14479{
14480 int retval;
14481
14482 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
14483 if (retval) {
14484 com_err("ext2fs_write_inode", retval,
14485 _("while writing inode %ld in %s"), ino, proc);
14486 fatal_error(ctx, 0);
14487 }
14488}
14489
14490extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
14491 struct ext2_inode * inode, const char *proc)
14492{
14493 int retval;
14494
14495 retval = ext2fs_write_inode(ctx->fs, ino, inode);
14496 if (retval) {
14497 com_err("ext2fs_write_inode", retval,
14498 _("while writing inode %ld in %s"), ino, proc);
14499 fatal_error(ctx, 0);
14500 }
14501}
14502
14503#ifdef MTRACE
14504void mtrace_print(char *mesg)
14505{
14506 FILE *malloc_get_mallstream();
14507 FILE *f = malloc_get_mallstream();
14508
14509 if (f)
14510 fprintf(f, "============= %s\n", mesg);
14511}
14512#endif
14513
14514blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
14515 io_manager manager)
14516{
14517 struct ext2_super_block *sb;
14518 io_channel io = NULL;
14519 void *buf = NULL;
14520 int blocksize;
14521 blk_t superblock, ret_sb = 8193;
14522
14523 if (fs && fs->super) {
14524 ret_sb = (fs->super->s_blocks_per_group +
14525 fs->super->s_first_data_block);
14526 if (ctx) {
14527 ctx->superblock = ret_sb;
14528 ctx->blocksize = fs->blocksize;
14529 }
14530 return ret_sb;
14531 }
14532
14533 if (ctx) {
14534 if (ctx->blocksize) {
14535 ret_sb = ctx->blocksize * 8;
14536 if (ctx->blocksize == 1024)
14537 ret_sb++;
14538 ctx->superblock = ret_sb;
14539 return ret_sb;
14540 }
14541 ctx->superblock = ret_sb;
14542 ctx->blocksize = 1024;
14543 }
14544
14545 if (!name || !manager)
14546 goto cleanup;
14547
14548 if (manager->open(name, 0, &io) != 0)
14549 goto cleanup;
14550
14551 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
14552 goto cleanup;
14553 sb = (struct ext2_super_block *) buf;
14554
14555 for (blocksize = EXT2_MIN_BLOCK_SIZE;
14556 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
14557 superblock = blocksize*8;
14558 if (blocksize == 1024)
14559 superblock++;
14560 io_channel_set_blksize(io, blocksize);
14561 if (io_channel_read_blk(io, superblock,
14562 -SUPERBLOCK_SIZE, buf))
14563 continue;
14564#ifdef EXT2FS_ENABLE_SWAPFS
14565 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
14566 ext2fs_swap_super(sb);
14567#endif
14568 if (sb->s_magic == EXT2_SUPER_MAGIC) {
14569 ret_sb = superblock;
14570 if (ctx) {
14571 ctx->superblock = superblock;
14572 ctx->blocksize = blocksize;
14573 }
14574 break;
14575 }
14576 }
14577
14578cleanup:
14579 if (io)
14580 io_channel_close(io);
Rob Landleye7c43b62006-03-01 16:39:45 +000014581 ext2fs_free_mem(&buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014582 return (ret_sb);
14583}
14584
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014585
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014586/*
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014587 * This function runs through the e2fsck passes and calls them all,
14588 * returning restart, abort, or cancel as necessary...
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014589 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014590typedef void (*pass_t)(e2fsck_t ctx);
14591
14592static const pass_t e2fsck_passes[] = {
14593 e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
14594 e2fsck_pass5, 0 };
14595
14596#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
14597
14598static int e2fsck_run(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014599{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014600 int i;
14601 pass_t e2fsck_pass;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014602
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014603 if (setjmp(ctx->abort_loc)) {
14604 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
14605 return (ctx->flags & E2F_FLAG_RUN_RETURN);
14606 }
14607 ctx->flags |= E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014608
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014609 for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
14610 if (ctx->flags & E2F_FLAG_RUN_RETURN)
14611 break;
14612 e2fsck_pass(ctx);
14613 if (ctx->progress)
14614 (void) (ctx->progress)(ctx, 0, 0, 0);
14615 }
14616 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014617
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014618 if (ctx->flags & E2F_FLAG_RUN_RETURN)
14619 return (ctx->flags & E2F_FLAG_RUN_RETURN);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014620 return 0;
14621}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014622
14623
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014624/*
14625 * unix.c - The unix-specific code for e2fsck
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014626 */
14627
14628
Mike Frysinger51a43b42005-09-24 07:11:16 +000014629/* Command line options */
14630static int swapfs;
14631#ifdef ENABLE_SWAPFS
14632static int normalize_swapfs;
14633#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014634static int cflag; /* check disk */
Mike Frysinger51a43b42005-09-24 07:11:16 +000014635static int show_version_only;
14636static int verbose;
14637
14638static int replace_bad_blocks;
14639static int keep_bad_blocks;
14640static char *bad_blocks_file;
14641
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014642#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
Mike Frysinger51a43b42005-09-24 07:11:16 +000014643int journal_enable_debug = -1;
14644#endif
14645
14646#if 0
14647static void usage(e2fsck_t ctx)
14648{
14649 fprintf(stderr,
14650 _("Usage: %s [-panyrcdfvstDFSV] [-b superblock] [-B blocksize]\n"
14651 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
Mike Frysinger874af852006-03-08 07:03:27 +000014652 "\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n"
Mike Frysinger51a43b42005-09-24 07:11:16 +000014653 "\t\t[-E extended-options] device\n"),
14654 ctx->program_name);
14655
14656 fprintf(stderr, _("\nEmergency help:\n"
14657 " -p Automatic repair (no questions)\n"
14658 " -n Make no changes to the filesystem\n"
14659 " -y Assume \"yes\" to all questions\n"
14660 " -c Check for bad blocks and add them to the badblock list\n"
14661 " -f Force checking even if filesystem is marked clean\n"));
14662 fprintf(stderr, _(""
14663 " -v Be verbose\n"
14664 " -b superblock Use alternative superblock\n"
14665 " -B blocksize Force blocksize when looking for superblock\n"
Mike Frysinger874af852006-03-08 07:03:27 +000014666 " -j external_journal Set location of the external journal\n"
Mike Frysinger51a43b42005-09-24 07:11:16 +000014667 " -l bad_blocks_file Add to badblocks list\n"
14668 " -L bad_blocks_file Set badblocks list\n"
14669 ));
14670
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014671 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014672}
14673#endif
14674
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014675#define P_E2(singular, plural, n) n, ((n) == 1 ? singular : plural)
14676
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014677static void show_stats(e2fsck_t ctx)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014678{
14679 ext2_filsys fs = ctx->fs;
14680 int inodes, inodes_used, blocks, blocks_used;
14681 int dir_links;
14682 int num_files, num_links;
14683 int frag_percent;
14684
14685 dir_links = 2 * ctx->fs_directory_count - 1;
14686 num_files = ctx->fs_total_count - dir_links;
14687 num_links = ctx->fs_links_count - dir_links;
14688 inodes = fs->super->s_inodes_count;
14689 inodes_used = (fs->super->s_inodes_count -
14690 fs->super->s_free_inodes_count);
14691 blocks = fs->super->s_blocks_count;
14692 blocks_used = (fs->super->s_blocks_count -
14693 fs->super->s_free_blocks_count);
14694
14695 frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
14696 frag_percent = (frag_percent + 5) / 10;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014697
Mike Frysinger51a43b42005-09-24 07:11:16 +000014698 if (!verbose) {
14699 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
14700 ctx->device_name, inodes_used, inodes,
14701 frag_percent / 10, frag_percent % 10,
14702 blocks_used, blocks);
14703 return;
14704 }
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014705 printf ("\n%8d inode%s used (%d%%)\n", P_E2("", "s", inodes_used),
14706 100 * inodes_used / inodes);
14707 printf ("%8d non-contiguous inode%s (%0d.%d%%)\n",
14708 P_E2("", "s", ctx->fs_fragmented),
14709 frag_percent / 10, frag_percent % 10);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014710 printf (_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"),
14711 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014712 printf ("%8d block%s used (%d%%)\n", P_E2("", "s", blocks_used),
14713 (int) ((long long) 100 * blocks_used / blocks));
14714 printf ("%8d bad block%s\n", P_E2("", "s", ctx->fs_badblocks_count));
14715 printf ("%8d large file%s\n", P_E2("", "s", ctx->large_files));
14716 printf ("\n%8d regular file%s\n", P_E2("", "s", ctx->fs_regular_count));
14717 printf ("%8d director%s\n", P_E2("y", "ies", ctx->fs_directory_count));
14718 printf ("%8d character device file%s\n", P_E2("", "s", ctx->fs_chardev_count));
14719 printf ("%8d block device file%s\n", P_E2("", "s", ctx->fs_blockdev_count));
14720 printf ("%8d fifo%s\n", P_E2("", "s", ctx->fs_fifo_count));
14721 printf ("%8d link%s\n", P_E2("", "s", ctx->fs_links_count - dir_links));
14722 printf ("%8d symbolic link%s", P_E2("", "s", ctx->fs_symlinks_count));
14723 printf (" (%d fast symbolic link%s)\n", P_E2("", "s", ctx->fs_fast_symlinks_count));
14724 printf ("%8d socket%s--------\n\n", P_E2("", "s", ctx->fs_sockets_count));
14725 printf ("%8d file%s\n", P_E2("", "s", ctx->fs_total_count - dir_links));
Mike Frysinger51a43b42005-09-24 07:11:16 +000014726}
14727
14728static void check_mount(e2fsck_t ctx)
14729{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014730 errcode_t retval;
14731 int cont;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014732
14733 retval = ext2fs_check_if_mounted(ctx->filesystem_name,
14734 &ctx->mount_flags);
14735 if (retval) {
14736 com_err("ext2fs_check_if_mount", retval,
14737 _("while determining whether %s is mounted."),
14738 ctx->filesystem_name);
14739 return;
14740 }
14741
14742 /*
14743 * If the filesystem isn't mounted, or it's the root filesystem
14744 * and it's mounted read-only, then everything's fine.
14745 */
14746 if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) ||
14747 ((ctx->mount_flags & EXT2_MF_ISROOT) &&
14748 (ctx->mount_flags & EXT2_MF_READONLY)))
14749 return;
14750
14751 if (ctx->options & E2F_OPT_READONLY) {
14752 printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name);
14753 return;
14754 }
14755
14756 printf(_("%s is mounted. "), ctx->filesystem_name);
14757 if (!ctx->interactive)
14758 fatal_error(ctx, _("Cannot continue, aborting.\n\n"));
14759 printf(_("\n\n\007\007\007\007WARNING!!! "
14760 "Running e2fsck on a mounted filesystem may cause\n"
14761 "SEVERE filesystem damage.\007\007\007\n\n"));
14762 cont = ask_yn(_("Do you really want to continue"), -1);
14763 if (!cont) {
14764 printf (_("check aborted.\n"));
14765 exit (0);
14766 }
14767 return;
14768}
14769
14770static int is_on_batt(void)
14771{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014772 FILE *f;
14773 DIR *d;
14774 char tmp[80], tmp2[80], fname[80];
14775 unsigned int acflag;
14776 struct dirent* de;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014777
14778 f = fopen("/proc/apm", "r");
14779 if (f) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014780 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014781 acflag = 1;
14782 fclose(f);
14783 return (acflag != 1);
14784 }
14785 d = opendir("/proc/acpi/ac_adapter");
14786 if (d) {
14787 while ((de=readdir(d)) != NULL) {
14788 if (!strncmp(".", de->d_name, 1))
14789 continue;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014790 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state",
Mike Frysinger51a43b42005-09-24 07:11:16 +000014791 de->d_name);
14792 f = fopen(fname, "r");
14793 if (!f)
14794 continue;
14795 if (fscanf(f, "%s %s", tmp2, tmp) != 2)
14796 tmp[0] = 0;
14797 fclose(f);
14798 if (strncmp(tmp, "off-line", 8) == 0) {
14799 closedir(d);
14800 return 1;
14801 }
14802 }
14803 closedir(d);
14804 }
14805 return 0;
14806}
14807
14808/*
14809 * This routine checks to see if a filesystem can be skipped; if so,
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014810 * it will exit with EXIT_OK. Under some conditions it will print a
Mike Frysinger51a43b42005-09-24 07:11:16 +000014811 * message explaining why a check is being forced.
14812 */
14813static void check_if_skip(e2fsck_t ctx)
14814{
14815 ext2_filsys fs = ctx->fs;
14816 const char *reason = NULL;
14817 unsigned int reason_arg = 0;
14818 long next_check;
14819 int batt = is_on_batt();
14820 time_t now = time(0);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014821
Mike Frysinger51a43b42005-09-24 07:11:16 +000014822 if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file ||
14823 cflag || swapfs)
14824 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014825
Mike Frysinger51a43b42005-09-24 07:11:16 +000014826 if ((fs->super->s_state & EXT2_ERROR_FS) ||
14827 !ext2fs_test_valid(fs))
14828 reason = _(" contains a file system with errors");
14829 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
14830 reason = _(" was not cleanly unmounted");
14831 else if ((fs->super->s_max_mnt_count > 0) &&
14832 (fs->super->s_mnt_count >=
14833 (unsigned) fs->super->s_max_mnt_count)) {
14834 reason = _(" has been mounted %u times without being checked");
14835 reason_arg = fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014836 if (batt && (fs->super->s_mnt_count <
Mike Frysinger51a43b42005-09-24 07:11:16 +000014837 (unsigned) fs->super->s_max_mnt_count*2))
14838 reason = 0;
14839 } else if (fs->super->s_checkinterval &&
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014840 ((now - fs->super->s_lastcheck) >=
Mike Frysinger51a43b42005-09-24 07:11:16 +000014841 fs->super->s_checkinterval)) {
14842 reason = _(" has gone %u days without being checked");
14843 reason_arg = (now - fs->super->s_lastcheck)/(3600*24);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014844 if (batt && ((now - fs->super->s_lastcheck) <
Mike Frysinger51a43b42005-09-24 07:11:16 +000014845 fs->super->s_checkinterval*2))
14846 reason = 0;
14847 }
14848 if (reason) {
14849 fputs(ctx->device_name, stdout);
14850 printf(reason, reason_arg);
14851 fputs(_(", check forced.\n"), stdout);
14852 return;
14853 }
14854 printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name,
14855 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
14856 fs->super->s_inodes_count,
14857 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
14858 fs->super->s_blocks_count);
14859 next_check = 100000;
14860 if (fs->super->s_max_mnt_count > 0) {
14861 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014862 if (next_check <= 0)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014863 next_check = 1;
14864 }
14865 if (fs->super->s_checkinterval &&
14866 ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval))
14867 next_check = 1;
14868 if (next_check <= 5) {
14869 if (next_check == 1)
14870 fputs(_(" (check after next mount)"), stdout);
14871 else
14872 printf(_(" (check in %ld mounts)"), next_check);
14873 }
14874 fputc('\n', stdout);
14875 ext2fs_close(fs);
14876 ctx->fs = NULL;
14877 e2fsck_free_context(ctx);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000014878 exit(EXIT_OK);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014879}
14880
14881/*
14882 * For completion notice
14883 */
14884struct percent_tbl {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014885 int max_pass;
14886 int table[32];
Mike Frysinger51a43b42005-09-24 07:11:16 +000014887};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014888static const struct percent_tbl e2fsck_tbl = {
Mike Frysinger51a43b42005-09-24 07:11:16 +000014889 5, { 0, 70, 90, 92, 95, 100 }
14890};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014891
Mike Frysinger51a43b42005-09-24 07:11:16 +000014892static char bar[128], spaces[128];
14893
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014894static float calc_percent(const struct percent_tbl *tbl, int pass, int curr,
Mike Frysinger51a43b42005-09-24 07:11:16 +000014895 int max)
14896{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014897 float percent;
14898
Mike Frysinger51a43b42005-09-24 07:11:16 +000014899 if (pass <= 0)
14900 return 0.0;
14901 if (pass > tbl->max_pass || max == 0)
14902 return 100.0;
14903 percent = ((float) curr) / ((float) max);
14904 return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
14905 + tbl->table[pass-1]);
14906}
14907
Rob Landleydfba7412006-03-06 20:47:33 +000014908void e2fsck_clear_progbar(e2fsck_t ctx)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014909{
14910 if (!(ctx->flags & E2F_FLAG_PROG_BAR))
14911 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014912
Mike Frysinger51a43b42005-09-24 07:11:16 +000014913 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80),
14914 ctx->stop_meta);
14915 fflush(stdout);
14916 ctx->flags &= ~E2F_FLAG_PROG_BAR;
14917}
14918
14919int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
14920 unsigned int dpynum)
14921{
14922 static const char spinner[] = "\\|/-";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014923 int i;
14924 unsigned int tick;
14925 struct timeval tv;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014926 int dpywidth;
14927 int fixed_percent;
14928
14929 if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
14930 return 0;
14931
14932 /*
14933 * Calculate the new progress position. If the
14934 * percentage hasn't changed, then we skip out right
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014935 * away.
Mike Frysinger51a43b42005-09-24 07:11:16 +000014936 */
14937 fixed_percent = (int) ((10 * percent) + 0.5);
14938 if (ctx->progress_last_percent == fixed_percent)
14939 return 0;
14940 ctx->progress_last_percent = fixed_percent;
14941
14942 /*
14943 * If we've already updated the spinner once within
14944 * the last 1/8th of a second, no point doing it
14945 * again.
14946 */
14947 gettimeofday(&tv, NULL);
14948 tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8));
14949 if ((tick == ctx->progress_last_time) &&
14950 (fixed_percent != 0) && (fixed_percent != 1000))
14951 return 0;
14952 ctx->progress_last_time = tick;
14953
14954 /*
14955 * Advance the spinner, and note that the progress bar
14956 * will be on the screen
14957 */
14958 ctx->progress_pos = (ctx->progress_pos+1) & 3;
14959 ctx->flags |= E2F_FLAG_PROG_BAR;
14960
14961 dpywidth = 66 - strlen(label);
14962 dpywidth = 8 * (dpywidth / 8);
14963 if (dpynum)
14964 dpywidth -= 8;
14965
14966 i = ((percent * dpywidth) + 50) / 100;
14967 printf("%s%s: |%s%s", ctx->start_meta, label,
14968 bar + (sizeof(bar) - (i+1)),
14969 spaces + (sizeof(spaces) - (dpywidth - i + 1)));
14970 if (fixed_percent == 1000)
14971 fputc('|', stdout);
14972 else
14973 fputc(spinner[ctx->progress_pos & 3], stdout);
14974 printf(" %4.1f%% ", percent);
14975 if (dpynum)
14976 printf("%u\r", dpynum);
14977 else
14978 fputs(" \r", stdout);
14979 fputs(ctx->stop_meta, stdout);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014980
Mike Frysinger51a43b42005-09-24 07:11:16 +000014981 if (fixed_percent == 1000)
14982 e2fsck_clear_progbar(ctx);
14983 fflush(stdout);
14984
14985 return 0;
14986}
14987
14988static int e2fsck_update_progress(e2fsck_t ctx, int pass,
14989 unsigned long cur, unsigned long max)
14990{
14991 char buf[80];
14992 float percent;
14993
14994 if (pass == 0)
14995 return 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014996
Mike Frysinger51a43b42005-09-24 07:11:16 +000014997 if (ctx->progress_fd) {
14998 sprintf(buf, "%d %lu %lu\n", pass, cur, max);
14999 write(ctx->progress_fd, buf, strlen(buf));
15000 } else {
15001 percent = calc_percent(&e2fsck_tbl, pass, cur, max);
15002 e2fsck_simple_progress(ctx, ctx->device_name,
15003 percent, 0);
15004 }
15005 return 0;
15006}
15007
Mike Frysinger51a43b42005-09-24 07:11:16 +000015008static void reserve_stdio_fds(void)
15009{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015010 int fd;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015011
15012 while (1) {
"Vladimir N. Oleynik"6c35c7c2005-10-12 15:34:25 +000015013 fd = open(bb_dev_null, O_RDWR);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015014 if (fd > 2)
15015 break;
15016 if (fd < 0) {
15017 fprintf(stderr, _("ERROR: Couldn't open "
15018 "/dev/null (%s)\n"),
15019 strerror(errno));
15020 break;
15021 }
15022 }
15023 close(fd);
15024}
15025
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000015026static void signal_progress_on(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000015027{
15028 e2fsck_t ctx = e2fsck_global_ctx;
15029
15030 if (!ctx)
15031 return;
15032
15033 ctx->progress = e2fsck_update_progress;
15034 ctx->progress_fd = 0;
15035}
15036
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000015037static void signal_progress_off(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000015038{
15039 e2fsck_t ctx = e2fsck_global_ctx;
15040
15041 if (!ctx)
15042 return;
15043
15044 e2fsck_clear_progbar(ctx);
15045 ctx->progress = 0;
15046}
15047
"Vladimir N. Oleynik"3ebb8952005-10-12 12:24:01 +000015048static void signal_cancel(int sig FSCK_ATTR((unused)))
Mike Frysinger51a43b42005-09-24 07:11:16 +000015049{
15050 e2fsck_t ctx = e2fsck_global_ctx;
15051
15052 if (!ctx)
15053 exit(FSCK_CANCELED);
15054
15055 ctx->flags |= E2F_FLAG_CANCEL;
15056}
Mike Frysinger51a43b42005-09-24 07:11:16 +000015057
15058static void parse_extended_opts(e2fsck_t ctx, const char *opts)
15059{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015060 char *buf, *token, *next, *p, *arg;
15061 int ea_ver;
15062 int extended_usage = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015063
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015064 buf = string_copy(opts, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015065 for (token = buf; token && *token; token = next) {
15066 p = strchr(token, ',');
15067 next = 0;
15068 if (p) {
15069 *p = 0;
15070 next = p+1;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015071 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000015072 arg = strchr(token, '=');
15073 if (arg) {
15074 *arg = 0;
15075 arg++;
15076 }
15077 if (strcmp(token, "ea_ver") == 0) {
15078 if (!arg) {
15079 extended_usage++;
15080 continue;
15081 }
15082 ea_ver = strtoul(arg, &p, 0);
15083 if (*p ||
15084 ((ea_ver != 1) && (ea_ver != 2))) {
15085 fprintf(stderr,
15086 _("Invalid EA version.\n"));
15087 extended_usage++;
15088 continue;
15089 }
15090 ctx->ext_attr_ver = ea_ver;
Mike Frysinger874af852006-03-08 07:03:27 +000015091 } else {
15092 fprintf(stderr, _("Unknown extended option: %s\n"),
15093 token);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015094 extended_usage++;
Mike Frysinger874af852006-03-08 07:03:27 +000015095 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000015096 }
15097 if (extended_usage) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015098 bb_error_msg_and_die(
15099 "Extended options are separated by commas, "
Mike Frysinger51a43b42005-09-24 07:11:16 +000015100 "and may take an argument which\n"
15101 "is set off by an equals ('=') sign. "
Mike Frysinger874af852006-03-08 07:03:27 +000015102 "Valid extended options are:\n"
15103 "\tea_ver=<ea_version (1 or 2)>\n\n");
Mike Frysinger51a43b42005-09-24 07:11:16 +000015104 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015105}
Mike Frysinger51a43b42005-09-24 07:11:16 +000015106
15107
15108static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
15109{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015110 int flush = 0;
15111 int c, fd;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015112#ifdef MTRACE
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015113 extern void *mallwatch;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015114#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015115 e2fsck_t ctx;
15116 errcode_t retval;
15117 struct sigaction sa;
15118 char *extended_opts = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015119
15120 retval = e2fsck_allocate_context(&ctx);
15121 if (retval)
15122 return retval;
15123
15124 *ret_ctx = ctx;
15125
15126 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
15127 setvbuf(stderr, NULL, _IONBF, BUFSIZ);
15128 if (isatty(0) && isatty(1)) {
15129 ctx->interactive = 1;
15130 } else {
15131 ctx->start_meta[0] = '\001';
15132 ctx->stop_meta[0] = '\002';
15133 }
15134 memset(bar, '=', sizeof(bar)-1);
15135 memset(spaces, ' ', sizeof(spaces)-1);
15136 blkid_get_cache(&ctx->blkid, NULL);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015137
Mike Frysinger51a43b42005-09-24 07:11:16 +000015138 if (argc && *argv)
15139 ctx->program_name = *argv;
15140 else
15141 ctx->program_name = "e2fsck";
15142 while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
15143 switch (c) {
15144 case 'C':
15145 ctx->progress = e2fsck_update_progress;
15146 ctx->progress_fd = atoi(optarg);
15147 if (!ctx->progress_fd)
15148 break;
15149 /* Validate the file descriptor to avoid disasters */
15150 fd = dup(ctx->progress_fd);
15151 if (fd < 0) {
15152 fprintf(stderr,
15153 _("Error validating file descriptor %d: %s\n"),
15154 ctx->progress_fd,
15155 error_message(errno));
15156 fatal_error(ctx,
15157 _("Invalid completion information file descriptor"));
15158 } else
15159 close(fd);
15160 break;
15161 case 'D':
15162 ctx->options |= E2F_OPT_COMPRESS_DIRS;
15163 break;
15164 case 'E':
15165 extended_opts = optarg;
15166 break;
15167 case 'p':
15168 case 'a':
15169 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) {
15170 conflict_opt:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015171 fatal_error(ctx,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015172 _("Only one the options -p/-a, -n or -y may be specified."));
15173 }
15174 ctx->options |= E2F_OPT_PREEN;
15175 break;
15176 case 'n':
15177 if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
15178 goto conflict_opt;
15179 ctx->options |= E2F_OPT_NO;
15180 break;
15181 case 'y':
15182 if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO))
15183 goto conflict_opt;
15184 ctx->options |= E2F_OPT_YES;
15185 break;
15186 case 't':
15187#ifdef RESOURCE_TRACK
15188 if (ctx->options & E2F_OPT_TIME)
15189 ctx->options |= E2F_OPT_TIME2;
15190 else
15191 ctx->options |= E2F_OPT_TIME;
15192#else
15193 fprintf(stderr, _("The -t option is not "
15194 "supported on this version of e2fsck.\n"));
15195#endif
15196 break;
15197 case 'c':
15198 if (cflag++)
15199 ctx->options |= E2F_OPT_WRITECHECK;
15200 ctx->options |= E2F_OPT_CHECKBLOCKS;
15201 break;
15202 case 'r':
15203 /* What we do by default, anyway! */
15204 break;
15205 case 'b':
15206 ctx->use_superblock = atoi(optarg);
15207 ctx->flags |= E2F_FLAG_SB_SPECIFIED;
15208 break;
15209 case 'B':
15210 ctx->blocksize = atoi(optarg);
15211 break;
15212 case 'I':
15213 ctx->inode_buffer_blocks = atoi(optarg);
15214 break;
15215 case 'j':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015216 ctx->journal_name = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015217 break;
15218 case 'P':
15219 ctx->process_inode_size = atoi(optarg);
15220 break;
15221 case 'L':
15222 replace_bad_blocks++;
15223 case 'l':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015224 bad_blocks_file = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015225 break;
15226 case 'd':
15227 ctx->options |= E2F_OPT_DEBUG;
15228 break;
15229 case 'f':
15230 ctx->options |= E2F_OPT_FORCE;
15231 break;
15232 case 'F':
15233 flush = 1;
15234 break;
15235 case 'v':
15236 verbose = 1;
15237 break;
15238 case 'V':
15239 show_version_only = 1;
15240 break;
15241#ifdef MTRACE
15242 case 'M':
15243 mallwatch = (void *) strtol(optarg, NULL, 0);
15244 break;
15245#endif
15246 case 'N':
15247 ctx->device_name = optarg;
15248 break;
15249#ifdef ENABLE_SWAPFS
15250 case 's':
15251 normalize_swapfs = 1;
15252 case 'S':
15253 swapfs = 1;
15254 break;
15255#else
15256 case 's':
15257 case 'S':
15258 fprintf(stderr, _("Byte-swapping filesystems "
15259 "not compiled in this version "
15260 "of e2fsck\n"));
15261 exit(1);
15262#endif
15263 case 'k':
15264 keep_bad_blocks++;
15265 break;
15266 default:
15267 usage();
15268 }
15269 if (show_version_only)
15270 return 0;
15271 if (optind != argc - 1)
15272 usage();
15273 if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
15274 !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
15275 ctx->options |= E2F_OPT_READONLY;
15276 ctx->io_options = strchr(argv[optind], '?');
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015277 if (ctx->io_options)
Mike Frysinger51a43b42005-09-24 07:11:16 +000015278 *ctx->io_options++ = 0;
15279 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
15280 if (!ctx->filesystem_name) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015281 com_err(ctx->program_name, 0, _("Unable to resolve '%s'"),
Mike Frysinger51a43b42005-09-24 07:11:16 +000015282 argv[optind]);
15283 fatal_error(ctx, 0);
15284 }
15285 if (extended_opts)
15286 parse_extended_opts(ctx, extended_opts);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015287
Mike Frysinger51a43b42005-09-24 07:11:16 +000015288 if (flush) {
15289 fd = open(ctx->filesystem_name, O_RDONLY, 0);
15290 if (fd < 0) {
15291 com_err("open", errno,
15292 _("while opening %s for flushing"),
15293 ctx->filesystem_name);
15294 fatal_error(ctx, 0);
15295 }
15296 if ((retval = ext2fs_sync_device(fd, 1))) {
15297 com_err("ext2fs_sync_device", retval,
15298 _("while trying to flush %s"),
15299 ctx->filesystem_name);
15300 fatal_error(ctx, 0);
15301 }
15302 close(fd);
15303 }
15304#ifdef ENABLE_SWAPFS
15305 if (swapfs) {
15306 if (cflag || bad_blocks_file) {
15307 fprintf(stderr, _("Incompatible options not "
15308 "allowed when byte-swapping.\n"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015309 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015310 }
15311 }
15312#endif
15313 if (cflag && bad_blocks_file) {
15314 fprintf(stderr, _("The -c and the -l/-L options may "
15315 "not be both used at the same time.\n"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015316 exit(EXIT_USAGE);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015317 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000015318 /*
15319 * Set up signal action
15320 */
15321 memset(&sa, 0, sizeof(struct sigaction));
15322 sa.sa_handler = signal_cancel;
15323 sigaction(SIGINT, &sa, 0);
15324 sigaction(SIGTERM, &sa, 0);
15325#ifdef SA_RESTART
15326 sa.sa_flags = SA_RESTART;
15327#endif
15328 e2fsck_global_ctx = ctx;
15329 sa.sa_handler = signal_progress_on;
15330 sigaction(SIGUSR1, &sa, 0);
15331 sa.sa_handler = signal_progress_off;
15332 sigaction(SIGUSR2, &sa, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015333
15334 /* Update our PATH to include /sbin if we need to run badblocks */
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015335 if (cflag)
15336 e2fs_set_sbin_path();
Mike Frysinger51a43b42005-09-24 07:11:16 +000015337#ifdef __CONFIG_JBD_DEBUG__E2FS
15338 if (getenv("E2FSCK_JBD_DEBUG"))
15339 journal_enable_debug = atoi(getenv("E2FSCK_JBD_DEBUG"));
15340#endif
15341 return 0;
15342}
15343
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015344static const char my_ver_string[] = E2FSPROGS_VERSION;
15345static const char my_ver_date[] = E2FSPROGS_DATE;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015346
Mike Frysinger51a43b42005-09-24 07:11:16 +000015347int e2fsck_main (int argc, char *argv[])
15348{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015349 errcode_t retval;
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015350 int exit_value = EXIT_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015351 ext2_filsys fs = 0;
15352 io_manager io_ptr;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015353 struct ext2_super_block *sb;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015354 const char *lib_ver_date;
15355 int my_ver, lib_ver;
15356 e2fsck_t ctx;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015357 struct problem_context pctx;
15358 int flags, run_result;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015359
Mike Frysinger51a43b42005-09-24 07:11:16 +000015360 clear_problem_context(&pctx);
15361#ifdef MTRACE
15362 mtrace();
15363#endif
15364#ifdef MCHECK
15365 mcheck(0);
15366#endif
15367#ifdef ENABLE_NLS
15368 setlocale(LC_MESSAGES, "");
15369 setlocale(LC_CTYPE, "");
15370 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
15371 textdomain(NLS_CAT_NAME);
15372#endif
15373 my_ver = ext2fs_parse_version_string(my_ver_string);
15374 lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
15375 if (my_ver > lib_ver) {
15376 fprintf( stderr, _("Error: ext2fs library version "
15377 "out of date!\n"));
15378 show_version_only++;
15379 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015380
Mike Frysinger51a43b42005-09-24 07:11:16 +000015381 retval = PRS(argc, argv, &ctx);
15382 if (retval) {
15383 com_err("e2fsck", retval,
15384 _("while trying to initialize program"));
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015385 exit(EXIT_ERROR);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015386 }
15387 reserve_stdio_fds();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015388
Mike Frysinger51a43b42005-09-24 07:11:16 +000015389#ifdef RESOURCE_TRACK
15390 init_resource_track(&ctx->global_rtrack);
15391#endif
15392
15393 if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
15394 fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string,
15395 my_ver_date);
15396
15397 if (show_version_only) {
15398 fprintf(stderr, _("\tUsing %s, %s\n"),
15399 error_message(EXT2_ET_BASE), lib_ver_date);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015400 exit(EXIT_OK);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015401 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015402
Mike Frysinger51a43b42005-09-24 07:11:16 +000015403 check_mount(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015404
Mike Frysinger51a43b42005-09-24 07:11:16 +000015405 if (!(ctx->options & E2F_OPT_PREEN) &&
15406 !(ctx->options & E2F_OPT_NO) &&
15407 !(ctx->options & E2F_OPT_YES)) {
15408 if (!ctx->interactive)
15409 fatal_error(ctx,
15410 _("need terminal for interactive repairs"));
15411 }
15412 ctx->superblock = ctx->use_superblock;
15413restart:
15414#ifdef CONFIG_TESTIO_DEBUG
15415 io_ptr = test_io_manager;
15416 test_io_backing_manager = unix_io_manager;
15417#else
15418 io_ptr = unix_io_manager;
15419#endif
15420 flags = 0;
15421 if ((ctx->options & E2F_OPT_READONLY) == 0)
15422 flags |= EXT2_FLAG_RW;
15423
15424 if (ctx->superblock && ctx->blocksize) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015425 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015426 flags, ctx->superblock, ctx->blocksize,
15427 io_ptr, &fs);
15428 } else if (ctx->superblock) {
15429 int blocksize;
15430 for (blocksize = EXT2_MIN_BLOCK_SIZE;
15431 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015432 retval = ext2fs_open2(ctx->filesystem_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015433 ctx->io_options, flags,
15434 ctx->superblock, blocksize,
15435 io_ptr, &fs);
15436 if (!retval)
15437 break;
15438 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015439 } else
15440 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015441 flags, 0, 0, io_ptr, &fs);
15442 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
15443 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
15444 ((retval == EXT2_ET_BAD_MAGIC) ||
15445 ((retval == 0) && ext2fs_check_desc(fs)))) {
15446 if (!fs || (fs->group_desc_count > 1)) {
15447 printf(_("%s trying backup blocks...\n"),
15448 retval ? _("Couldn't find ext2 superblock,") :
15449 _("Group descriptors look bad..."));
15450 get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
15451 if (fs)
15452 ext2fs_close(fs);
15453 goto restart;
15454 }
15455 }
15456 if (retval) {
15457 com_err(ctx->program_name, retval, _("while trying to open %s"),
15458 ctx->filesystem_name);
15459 if (retval == EXT2_ET_REV_TOO_HIGH) {
15460 printf(_("The filesystem revision is apparently "
15461 "too high for this version of e2fsck.\n"
15462 "(Or the filesystem superblock "
15463 "is corrupt)\n\n"));
15464 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
15465 } else if (retval == EXT2_ET_SHORT_READ)
15466 printf(_("Could this be a zero-length partition?\n"));
15467 else if ((retval == EPERM) || (retval == EACCES))
15468 printf(_("You must have %s access to the "
15469 "filesystem or be root\n"),
15470 (ctx->options & E2F_OPT_READONLY) ?
15471 "r/o" : "r/w");
15472 else if (retval == ENXIO)
15473 printf(_("Possibly non-existent or swap device?\n"));
15474#ifdef EROFS
15475 else if (retval == EROFS)
15476 printf(_("Disk write-protected; use the -n option "
15477 "to do a read-only\n"
15478 "check of the device.\n"));
15479#endif
15480 else
15481 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
15482 fatal_error(ctx, 0);
15483 }
15484 ctx->fs = fs;
15485 fs->priv_data = ctx;
15486 sb = fs->super;
15487 if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
15488 com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH,
15489 _("while trying to open %s"),
15490 ctx->filesystem_name);
15491 get_newer:
15492 fatal_error(ctx, _("Get a newer version of e2fsck!"));
15493 }
15494
15495 /*
15496 * Set the device name, which is used whenever we print error
15497 * or informational messages to the user.
15498 */
15499 if (ctx->device_name == 0 &&
15500 (sb->s_volume_name[0] != 0)) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015501 ctx->device_name = string_copy(sb->s_volume_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015502 sizeof(sb->s_volume_name));
15503 }
15504 if (ctx->device_name == 0)
15505 ctx->device_name = ctx->filesystem_name;
15506
15507 /*
15508 * Make sure the ext3 superblock fields are consistent.
15509 */
15510 retval = e2fsck_check_ext3_journal(ctx);
15511 if (retval) {
15512 com_err(ctx->program_name, retval,
15513 _("while checking ext3 journal for %s"),
15514 ctx->device_name);
15515 fatal_error(ctx, 0);
15516 }
15517
15518 /*
15519 * Check to see if we need to do ext3-style recovery. If so,
15520 * do it, and then restart the fsck.
15521 */
15522 if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
15523 if (ctx->options & E2F_OPT_READONLY) {
15524 printf(_("Warning: skipping journal recovery "
15525 "because doing a read-only filesystem "
15526 "check.\n"));
15527 io_channel_flush(ctx->fs->io);
15528 } else {
15529 if (ctx->flags & E2F_FLAG_RESTARTED) {
15530 /*
15531 * Whoops, we attempted to run the
15532 * journal twice. This should never
15533 * happen, unless the hardware or
15534 * device driver is being bogus.
15535 */
15536 com_err(ctx->program_name, 0,
15537 _("unable to set superblock flags on %s\n"), ctx->device_name);
15538 fatal_error(ctx, 0);
15539 }
15540 retval = e2fsck_run_ext3_journal(ctx);
15541 if (retval) {
15542 com_err(ctx->program_name, retval,
15543 _("while recovering ext3 journal of %s"),
15544 ctx->device_name);
15545 fatal_error(ctx, 0);
15546 }
15547 ext2fs_close(ctx->fs);
15548 ctx->fs = 0;
15549 ctx->flags |= E2F_FLAG_RESTARTED;
15550 goto restart;
15551 }
15552 }
15553
15554 /*
15555 * Check for compatibility with the feature sets. We need to
15556 * be more stringent than ext2fs_open().
15557 */
15558 if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
15559 (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
15560 com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
15561 "(%s)", ctx->device_name);
15562 goto get_newer;
15563 }
15564 if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
15565 com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE,
15566 "(%s)", ctx->device_name);
15567 goto get_newer;
15568 }
15569#ifdef ENABLE_COMPRESSION
15570 if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
15571 com_err(ctx->program_name, 0,
15572 _("Warning: compression support is experimental.\n"));
15573#endif
15574#ifndef ENABLE_HTREE
15575 if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
15576 com_err(ctx->program_name, 0,
15577 _("E2fsck not compiled with HTREE support,\n\t"
15578 "but filesystem %s has HTREE directories.\n"),
15579 ctx->device_name);
15580 goto get_newer;
15581 }
15582#endif
15583
15584 /*
15585 * If the user specified a specific superblock, presumably the
15586 * master superblock has been trashed. So we mark the
15587 * superblock as dirty, so it can be written out.
15588 */
15589 if (ctx->superblock &&
15590 !(ctx->options & E2F_OPT_READONLY))
15591 ext2fs_mark_super_dirty(fs);
15592
15593 /*
15594 * We only update the master superblock because (a) paranoia;
15595 * we don't want to corrupt the backup superblocks, and (b) we
15596 * don't need to update the mount count and last checked
15597 * fields in the backup superblock (the kernel doesn't
15598 * update the backup superblocks anyway).
15599 */
15600 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
15601
15602 ehandler_init(fs->io);
15603
15604 if (ctx->superblock)
15605 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
15606 ext2fs_mark_valid(fs);
15607 check_super_block(ctx);
15608 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15609 fatal_error(ctx, 0);
15610 check_if_skip(ctx);
15611 if (bad_blocks_file)
15612 read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks);
15613 else if (cflag)
15614 read_bad_blocks_file(ctx, 0, !keep_bad_blocks); /* Test disk */
15615 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15616 fatal_error(ctx, 0);
15617#ifdef ENABLE_SWAPFS
Rob Landley391a9042006-01-23 21:38:06 +000015618
15619#ifdef WORDS_BIGENDIAN
Rob Landley8b606342006-01-24 02:38:28 +000015620#define NATIVE_FLAG EXT2_FLAG_SWAP_BYTES
Rob Landley391a9042006-01-23 21:38:06 +000015621#else
Rob Landley8b606342006-01-24 02:38:28 +000015622#define NATIVE_FLAG 0
Rob Landley391a9042006-01-23 21:38:06 +000015623#endif
15624
15625
Mike Frysinger51a43b42005-09-24 07:11:16 +000015626 if (normalize_swapfs) {
Rob Landley391a9042006-01-23 21:38:06 +000015627 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == NATIVE_FLAG) {
Mike Frysinger51a43b42005-09-24 07:11:16 +000015628 fprintf(stderr, _("%s: Filesystem byte order "
15629 "already normalized.\n"), ctx->device_name);
15630 fatal_error(ctx, 0);
15631 }
15632 }
15633 if (swapfs) {
15634 swap_filesys(ctx);
15635 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15636 fatal_error(ctx, 0);
15637 }
15638#endif
15639
15640 /*
15641 * Mark the system as valid, 'til proven otherwise
15642 */
15643 ext2fs_mark_valid(fs);
15644
15645 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
15646 if (retval) {
15647 com_err(ctx->program_name, retval,
15648 _("while reading bad blocks inode"));
15649 preenhalt(ctx);
15650 printf(_("This doesn't bode well,"
15651 " but we'll try to go on...\n"));
15652 }
15653
15654 run_result = e2fsck_run(ctx);
15655 e2fsck_clear_progbar(ctx);
15656 if (run_result == E2F_FLAG_RESTART) {
15657 printf(_("Restarting e2fsck from the beginning...\n"));
15658 retval = e2fsck_reset_context(ctx);
15659 if (retval) {
15660 com_err(ctx->program_name, retval,
15661 _("while resetting context"));
15662 fatal_error(ctx, 0);
15663 }
15664 ext2fs_close(fs);
15665 goto restart;
15666 }
15667 if (run_result & E2F_FLAG_CANCEL) {
15668 printf(_("%s: e2fsck canceled.\n"), ctx->device_name ?
15669 ctx->device_name : ctx->filesystem_name);
15670 exit_value |= FSCK_CANCELED;
15671 }
15672 if (run_result & E2F_FLAG_ABORT)
15673 fatal_error(ctx, _("aborted"));
15674
15675#ifdef MTRACE
15676 mtrace_print("Cleanup");
15677#endif
15678 if (ext2fs_test_changed(fs)) {
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015679 exit_value |= EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015680 if (!(ctx->options & E2F_OPT_PREEN))
15681 printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
15682 ctx->device_name);
15683 if (ctx->mount_flags & EXT2_MF_ISROOT) {
15684 printf(_("%s: ***** REBOOT LINUX *****\n"),
15685 ctx->device_name);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015686 exit_value |= EXIT_DESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015687 }
15688 }
15689 if (!ext2fs_test_valid(fs)) {
15690 printf(_("\n%s: ********** WARNING: Filesystem still has "
15691 "errors **********\n\n"), ctx->device_name);
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015692 exit_value |= EXIT_UNCORRECTED;
15693 exit_value &= ~EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015694 }
15695 if (exit_value & FSCK_CANCELED)
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015696 exit_value &= ~EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015697 else {
15698 show_stats(ctx);
15699 if (!(ctx->options & E2F_OPT_READONLY)) {
15700 if (ext2fs_test_valid(fs)) {
15701 if (!(sb->s_state & EXT2_VALID_FS))
"Vladimir N. Oleynik"d20cfbd2005-10-12 16:22:19 +000015702 exit_value |= EXIT_NONDESTRUCT;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015703 sb->s_state = EXT2_VALID_FS;
15704 } else
15705 sb->s_state &= ~EXT2_VALID_FS;
15706 sb->s_mnt_count = 0;
15707 sb->s_lastcheck = time(NULL);
15708 ext2fs_mark_super_dirty(fs);
15709 }
15710 }
15711
15712 e2fsck_write_bitmaps(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015713
Mike Frysinger51a43b42005-09-24 07:11:16 +000015714 ext2fs_close(fs);
15715 ctx->fs = NULL;
15716 free(ctx->filesystem_name);
15717 free(ctx->journal_name);
15718 e2fsck_free_context(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015719
Mike Frysinger51a43b42005-09-24 07:11:16 +000015720#ifdef RESOURCE_TRACK
15721 if (ctx->options & E2F_OPT_TIME)
15722 print_resource_track(NULL, &ctx->global_rtrack);
15723#endif
15724
15725 return exit_value;
15726}