summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-12-26 01:30:59 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-12-26 01:30:59 +0000
commitc4f623ef2a7980a63de7c9f1d539a656b83f10e7 (patch)
treea294e28b0112052cb9d58b403554b3390e76f50c
parent64c54025842f205ad722675105b88044a5b6845a (diff)
downloadbusybox-w32-c4f623ef2a7980a63de7c9f1d539a656b83f10e7.tar.gz
busybox-w32-c4f623ef2a7980a63de7c9f1d539a656b83f10e7.tar.bz2
busybox-w32-c4f623ef2a7980a63de7c9f1d539a656b83f10e7.zip
put small subset of e2fsprogs back in the tree:
lsattr, chattr, fsck. Old e2fsprogs tree is in e2fsprogs/old_e2fsprogs/*.
-rw-r--r--e2fsprogs/Config.in67
-rw-r--r--e2fsprogs/Kbuild12
-rw-r--r--e2fsprogs/README12
-rw-r--r--e2fsprogs/chattr.c199
-rw-r--r--e2fsprogs/e2fs_defs.h561
-rw-r--r--e2fsprogs/e2fs_lib.c197
-rw-r--r--e2fsprogs/e2fs_lib.h30
-rw-r--r--e2fsprogs/fsck.c1319
-rw-r--r--e2fsprogs/lsattr.c114
-rw-r--r--e2fsprogs/old_e2fsprogs/Config.in67
-rw-r--r--e2fsprogs/old_e2fsprogs/Kbuild16
-rw-r--r--e2fsprogs/old_e2fsprogs/README3
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/Kbuild23
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/blkid.h105
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/blkidP.h187
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c179
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/cache.c126
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/dev.c214
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/devname.c368
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/devno.c223
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/list.c110
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/list.h73
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/probe.c721
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/probe.h375
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/read.c462
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/resolve.c139
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/save.c189
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/tag.c432
-rw-r--r--e2fsprogs/old_e2fsprogs/chattr.c219
-rw-r--r--e2fsprogs/old_e2fsprogs/e2fsbb.h43
-rw-r--r--e2fsprogs/old_e2fsprogs/e2fsck.c13552
-rw-r--r--e2fsprogs/old_e2fsprogs/e2fsck.h640
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/Kbuild15
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/e2p.h64
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/feature.c187
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/fgetsetflags.c70
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/fgetsetversion.c70
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/hashstr.c70
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/iod.c52
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/ls.c273
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/mntopts.c134
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/ostype.c74
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/parse_num.c65
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/pe.c32
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/pf.c74
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/ps.c27
-rw-r--r--e2fsprogs/old_e2fsprogs/e2p/uuid.c78
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/Kbuild23
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/alloc.c174
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/alloc_sb.c58
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/alloc_stats.c53
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c118
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/badblocks.c328
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/bb_compat.c64
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c268
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/bitmaps.c213
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/bitops.c91
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/bitops.h107
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/block.c438
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/bmap.c264
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/bmove.c156
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/brel.h87
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/brel_ma.c196
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/check_desc.c69
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/closefs.c381
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c73
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/dblist.c260
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/dblist_dir.c76
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c220
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c133
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c234
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c97
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/e2image.h52
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/expanddir.c127
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ext2_err.h116
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h53
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h570
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h114
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ext2_types.h2
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h923
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h89
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c367
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ext_attr.c101
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/fileio.c377
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/finddev.c199
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/flushb.c83
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/freefs.c128
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/gen_bitmap.c49
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c157
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/getsectsize.c58
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/getsize.c291
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/icount.c467
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/imager.c377
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c71
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/initialize.c388
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/inline.c33
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/inode.c768
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c271
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/io_manager.c70
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/irel.h115
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/irel_ma.c367
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c357
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h65
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h236
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h113
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/link.c135
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/lookup.c70
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c142
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c428
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/namei.c205
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/newdir.c73
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/openfs.c330
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c98
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c98
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c221
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c107
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c296
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/sparse.c79
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c236
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/test_io.c380
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c703
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/unlink.c100
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/valid_blk.c57
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/version.c51
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/write_bb_file.c35
-rw-r--r--e2fsprogs/old_e2fsprogs/fsck.c1392
-rw-r--r--e2fsprogs/old_e2fsprogs/fsck.h16
-rw-r--r--e2fsprogs/old_e2fsprogs/lsattr.c128
-rw-r--r--e2fsprogs/old_e2fsprogs/mke2fs.c1336
-rw-r--r--e2fsprogs/old_e2fsprogs/tune2fs.c729
-rw-r--r--e2fsprogs/old_e2fsprogs/util.c267
-rw-r--r--e2fsprogs/old_e2fsprogs/util.h22
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/Kbuild14
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/compare.c55
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c305
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/pack.c69
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/parse.c80
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/unpack.c63
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/unparse.c77
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/uuid.h104
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/uuidP.h60
-rw-r--r--e2fsprogs/old_e2fsprogs/uuid/uuid_time.c161
142 files changed, 42719 insertions, 0 deletions
diff --git a/e2fsprogs/Config.in b/e2fsprogs/Config.in
new file mode 100644
index 000000000..521273e45
--- /dev/null
+++ b/e2fsprogs/Config.in
@@ -0,0 +1,67 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6menu "Linux Ext2 FS Progs"
7
8config CHATTR
9 bool "chattr"
10 default n
11 help
12 chattr changes the file attributes on a second extended file system.
13
14### config E2FSCK
15### bool "e2fsck"
16### default n
17### help
18### e2fsck is used to check Linux second extended file systems (ext2fs).
19### e2fsck also supports ext2 filesystems countaining a journal (ext3).
20### The normal compat symlinks 'fsck.ext2' and 'fsck.ext3' are also
21### provided.
22
23config FSCK
24 bool "fsck"
25 default n
26 help
27 fsck is used to check and optionally repair one or more filesystems.
28 In actuality, fsck is simply a front-end for the various file system
29 checkers (fsck.fstype) available under Linux.
30
31config LSATTR
32 bool "lsattr"
33 default n
34 help
35 lsattr lists the file attributes on a second extended file system.
36
37### config MKE2FS
38### bool "mke2fs"
39### default n
40### help
41### mke2fs is used to create an ext2/ext3 filesystem. The normal compat
42### symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided.
43
44### config TUNE2FS
45### bool "tune2fs"
46### default n
47### help
48### tune2fs allows the system administrator to adjust various tunable
49### filesystem parameters on Linux ext2/ext3 filesystems.
50
51### config E2LABEL
52### bool "e2label"
53### default n
54### depends on TUNE2FS
55### help
56### e2label will display or change the filesystem label on the ext2
57### filesystem located on device.
58
59### config FINDFS
60### bool "findfs"
61### default n
62### depends on TUNE2FS
63### help
64### findfs will search the disks in the system looking for a filesystem
65### which has a label matching label or a UUID equal to uuid.
66
67endmenu
diff --git a/e2fsprogs/Kbuild b/e2fsprogs/Kbuild
new file mode 100644
index 000000000..9f58ce092
--- /dev/null
+++ b/e2fsprogs/Kbuild
@@ -0,0 +1,12 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7lib-y:=
8
9lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o
10lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o
11
12lib-$(CONFIG_FSCK) += fsck.o
diff --git a/e2fsprogs/README b/e2fsprogs/README
new file mode 100644
index 000000000..eb158e588
--- /dev/null
+++ b/e2fsprogs/README
@@ -0,0 +1,12 @@
1Authors and contributors of original e2fsprogs:
2
3Remy Card <card@masi.ibp.fr>
4Theodore Ts'o <tytso@mit.edu>
5Stephen C. Tweedie <sct@redhat.com>
6Andreas Gruenbacher, <a.gruenbacher@computer.org>
7Kaz Kylheku <kaz@ashi.footprints.net>
8F.W. ten Wolde <franky@duteca.et.tudelft.nl>
9Jeremy Fitzhardinge <jeremy@zip.com.au>
10M.J.E. Mol <marcel@duteca.et.tudelft.nl>
11Miquel van Smoorenburg <miquels@drinkel.ow.org>
12Uwe Ohse <uwe@tirka.gun.de>
diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c
new file mode 100644
index 000000000..28a391771
--- /dev/null
+++ b/e2fsprogs/chattr.c
@@ -0,0 +1,199 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * chattr.c - Change file attributes on an ext2 file system
4 *
5 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * This file can be redistributed under the terms of the GNU General
10 * Public License
11 */
12
13/*
14 * History:
15 * 93/10/30 - Creation
16 * 93/11/13 - Replace stat() calls by lstat() to avoid loops
17 * 94/02/27 - Integrated in Ted's distribution
18 * 98/12/29 - Ignore symlinks when working recursively (G M Sipe)
19 * 98/12/29 - Display version info only when -V specified (G M Sipe)
20 */
21
22#include "busybox.h"
23#include "e2fs_lib.h"
24
25#define OPT_ADD 1
26#define OPT_REM 2
27#define OPT_SET 4
28#define OPT_SET_VER 8
29static int flags;
30static int recursive;
31
32static unsigned long version;
33
34static unsigned long af;
35static unsigned long rf;
36static unsigned long sf;
37
38struct flags_char {
39 unsigned long flag;
40 char optchar;
41};
42
43static const struct flags_char flags_array[] = {
44 { EXT2_NOATIME_FL, 'A' },
45 { EXT2_SYNC_FL, 'S' },
46 { EXT2_DIRSYNC_FL, 'D' },
47 { EXT2_APPEND_FL, 'a' },
48 { EXT2_COMPR_FL, 'c' },
49 { EXT2_NODUMP_FL, 'd' },
50 { EXT2_IMMUTABLE_FL, 'i' },
51 { EXT3_JOURNAL_DATA_FL, 'j' },
52 { EXT2_SECRM_FL, 's' },
53 { EXT2_UNRM_FL, 'u' },
54 { EXT2_NOTAIL_FL, 't' },
55 { EXT2_TOPDIR_FL, 'T' },
56 { 0, 0 }
57};
58
59static unsigned long get_flag(char c)
60{
61 const struct flags_char *fp;
62 for (fp = flags_array; fp->flag; fp++)
63 if (fp->optchar == c)
64 return fp->flag;
65 bb_show_usage();
66 /*return 0;*/
67}
68
69static int decode_arg(char *arg)
70{
71 unsigned long *fl;
72 char opt = *arg++;
73
74 if (opt == '-') {
75 flags |= OPT_REM;
76 fl = &rf;
77 } else if (opt == '+') {
78 flags |= OPT_ADD;
79 fl = &af;
80 } else if (opt == '=') {
81 flags |= OPT_SET;
82 fl = &sf;
83 } else
84 return 0;
85
86 while (*arg)
87 *fl |= get_flag(*arg++);
88
89 return 1;
90}
91
92static int chattr_dir_proc(const char *, struct dirent *, void *);
93
94static void change_attributes(const char * name)
95{
96 unsigned long fsflags;
97 struct stat st;
98
99 if (lstat(name, &st) == -1) {
100 bb_error_msg("stat %s failed", name);
101 return;
102 }
103 if (S_ISLNK(st.st_mode) && recursive)
104 return;
105
106 /* Don't try to open device files, fifos etc. We probably
107 * ought to display an error if the file was explicitly given
108 * on the command line (whether or not recursive was
109 * requested). */
110 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
111 return;
112
113 if (flags & OPT_SET_VER)
114 if (fsetversion(name, version) == -1)
115 bb_error_msg("setting version on %s", name);
116
117 if (flags & OPT_SET) {
118 fsflags = sf;
119 } else {
120 if (fgetflags(name, &fsflags) == -1) {
121 bb_error_msg("reading flags on %s", name);
122 goto skip_setflags;
123 }
124 if (flags & OPT_REM)
125 fsflags &= ~rf;
126 if (flags & OPT_ADD)
127 fsflags |= af;
128 if (!S_ISDIR(st.st_mode))
129 fsflags &= ~EXT2_DIRSYNC_FL;
130 }
131 if (fsetflags(name, fsflags) == -1)
132 bb_error_msg("setting flags on %s", name);
133
134 skip_setflags:
135 if (S_ISDIR(st.st_mode) && recursive)
136 iterate_on_dir(name, chattr_dir_proc, NULL);
137}
138
139static int chattr_dir_proc(const char *dir_name, struct dirent *de,
140 void *private ATTRIBUTE_UNUSED)
141{
142 /*if (strcmp(de->d_name, ".") || strcmp(de->d_name, "..")) {*/
143 if (de->d_name[0] == '.'
144 && (!de->d_name[1] || LONE_CHAR(de->d_name+1, '.'))
145 ) {
146 char *path = concat_subpath_file(dir_name, de->d_name);
147 if (path) {
148 change_attributes(path);
149 free(path);
150 }
151 }
152 return 0;
153}
154
155int chattr_main(int argc, char **argv)
156{
157 int i;
158 char *arg;
159
160 /* parse the args */
161 for (i = 1; i < argc; ++i) {
162 arg = argv[i];
163
164 /* take care of -R and -v <version> */
165 if (arg[0] == '-') {
166 if (arg[1] == 'R' && arg[2] == '\0') {
167 recursive = 1;
168 continue;
169 }
170 if (arg[1] == 'v' && arg[2] == '\0') {
171 ++i;
172 if (i >= argc)
173 bb_show_usage();
174 version = xatoul(argv[i]);
175 flags |= OPT_SET_VER;
176 continue;
177 }
178 }
179
180 if (!decode_arg(arg))
181 break;
182 }
183
184 /* run sanity checks on all the arguments given us */
185 if (i >= argc)
186 bb_show_usage();
187 if ((flags & OPT_SET) && (flags & (OPT_ADD|OPT_REM)))
188 bb_error_msg_and_die("= is incompatible with - and +");
189 if (rf & af)
190 bb_error_msg_and_die("Can't set and unset a flag");
191 if (!flags)
192 bb_error_msg_and_die("Must use '-v', =, - or +");
193
194 /* now run chattr on all the files passed to us */
195 while (i < argc)
196 change_attributes(argv[i++]);
197
198 return EXIT_SUCCESS;
199}
diff --git a/e2fsprogs/e2fs_defs.h b/e2fsprogs/e2fs_defs.h
new file mode 100644
index 000000000..b3ea3ae34
--- /dev/null
+++ b/e2fsprogs/e2fs_defs.h
@@ -0,0 +1,561 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * linux/include/linux/ext2_fs.h
4 *
5 * Copyright (C) 1992, 1993, 1994, 1995
6 * Remy Card (card@masi.ibp.fr)
7 * Laboratoire MASI - Institut Blaise Pascal
8 * Universite Pierre et Marie Curie (Paris VI)
9 *
10 * Copyright (C) 1991, 1992 Linus Torvalds
11 */
12
13#ifndef _LINUX_EXT2_FS_H
14#define _LINUX_EXT2_FS_H
15
16/*
17 * Special inode numbers
18 */
19#define EXT2_BAD_INO 1 /* Bad blocks inode */
20#define EXT2_ROOT_INO 2 /* Root inode */
21#define EXT2_ACL_IDX_INO 3 /* ACL inode */
22#define EXT2_ACL_DATA_INO 4 /* ACL inode */
23#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
24#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
25#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */
26#define EXT2_JOURNAL_INO 8 /* Journal inode */
27
28/* First non-reserved inode for old ext2 filesystems */
29#define EXT2_GOOD_OLD_FIRST_INO 11
30
31/*
32 * The second extended file system magic number
33 */
34#define EXT2_SUPER_MAGIC 0xEF53
35
36/* Assume that user mode programs are passing in an ext2fs superblock, not
37 * a kernel struct super_block. This will allow us to call the feature-test
38 * macros from user land. */
39#define EXT2_SB(sb) (sb)
40
41/*
42 * Maximal count of links to a file
43 */
44#define EXT2_LINK_MAX 32000
45
46/*
47 * Macro-instructions used to manage several block sizes
48 */
49#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
50#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */
51#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE)
52#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE)
53#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
54#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
55#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
56 EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
57#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
58 EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
59#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(uint32_t))
60
61/*
62 * Macro-instructions used to manage fragments
63 */
64#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE
65#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE
66#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE
67#define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
68#define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
69
70/*
71 * ACL structures
72 */
73struct ext2_acl_header { /* Header of Access Control Lists */
74 uint32_t aclh_size;
75 uint32_t aclh_file_count;
76 uint32_t aclh_acle_count;
77 uint32_t aclh_first_acle;
78};
79
80struct ext2_acl_entry { /* Access Control List Entry */
81 uint32_t acle_size;
82 uint16_t acle_perms; /* Access permissions */
83 uint16_t acle_type; /* Type of entry */
84 uint16_t acle_tag; /* User or group identity */
85 uint16_t acle_pad1;
86 uint32_t acle_next; /* Pointer on next entry for the */
87 /* same inode or on next free entry */
88};
89
90/*
91 * Structure of a blocks group descriptor
92 */
93struct ext2_group_desc {
94 uint32_t bg_block_bitmap; /* Blocks bitmap block */
95 uint32_t bg_inode_bitmap; /* Inodes bitmap block */
96 uint32_t bg_inode_table; /* Inodes table block */
97 uint16_t bg_free_blocks_count; /* Free blocks count */
98 uint16_t bg_free_inodes_count; /* Free inodes count */
99 uint16_t bg_used_dirs_count; /* Directories count */
100 uint16_t bg_pad;
101 uint32_t bg_reserved[3];
102};
103
104/*
105 * Data structures used by the directory indexing feature
106 *
107 * Note: all of the multibyte integer fields are little endian.
108 */
109
110/*
111 * Note: dx_root_info is laid out so that if it should somehow get
112 * overlaid by a dirent the two low bits of the hash version will be
113 * zero. Therefore, the hash version mod 4 should never be 0.
114 * Sincerely, the paranoia department.
115 */
116struct ext2_dx_root_info {
117 uint32_t reserved_zero;
118 uint8_t hash_version; /* 0 now, 1 at release */
119 uint8_t info_length; /* 8 */
120 uint8_t indirect_levels;
121 uint8_t unused_flags;
122};
123
124#define EXT2_HASH_LEGACY 0
125#define EXT2_HASH_HALF_MD4 1
126#define EXT2_HASH_TEA 2
127
128#define EXT2_HASH_FLAG_INCOMPAT 0x1
129
130struct ext2_dx_entry {
131 uint32_t hash;
132 uint32_t block;
133};
134
135struct ext2_dx_countlimit {
136 uint16_t limit;
137 uint16_t count;
138};
139
140
141/*
142 * Macro-instructions used to manage group descriptors
143 */
144#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group)
145#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group)
146#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
147/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
148#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((1 << 16) - 8)
149#define EXT2_MAX_INODES_PER_GROUP(s) ((1 << 16) - EXT2_INODES_PER_BLOCK(s))
150#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
151
152/*
153 * Constants relative to the data blocks
154 */
155#define EXT2_NDIR_BLOCKS 12
156#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
157#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
158#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
159#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
160
161/*
162 * Inode flags
163 */
164#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
165#define EXT2_UNRM_FL 0x00000002 /* Undelete */
166#define EXT2_COMPR_FL 0x00000004 /* Compress file */
167#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
168#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
169#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
170#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
171#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
172/* Reserved for compression usage... */
173#define EXT2_DIRTY_FL 0x00000100
174#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
175#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */
176#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
177/* End compression flags --- maybe not all used */
178#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
179#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
180#define EXT2_IMAGIC_FL 0x00002000
181#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
182#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
183#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */
184#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
185#define EXT3_EXTENTS_FL 0x00080000 /* Inode uses extents */
186#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
187
188#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
189#define EXT2_FL_USER_MODIFIABLE 0x000080FF /* User modifiable flags */
190
191/*
192 * ioctl commands
193 */
194#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
195#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
196#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
197#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
198
199/*
200 * Structure of an inode on the disk
201 */
202struct ext2_inode {
203 uint16_t i_mode; /* File mode */
204 uint16_t i_uid; /* Low 16 bits of Owner Uid */
205 uint32_t i_size; /* Size in bytes */
206 uint32_t i_atime; /* Access time */
207 uint32_t i_ctime; /* Creation time */
208 uint32_t i_mtime; /* Modification time */
209 uint32_t i_dtime; /* Deletion Time */
210 uint16_t i_gid; /* Low 16 bits of Group Id */
211 uint16_t i_links_count; /* Links count */
212 uint32_t i_blocks; /* Blocks count */
213 uint32_t i_flags; /* File flags */
214 union {
215 struct {
216 uint32_t l_i_reserved1;
217 } linux1;
218 struct {
219 uint32_t h_i_translator;
220 } hurd1;
221 struct {
222 uint32_t m_i_reserved1;
223 } masix1;
224 } osd1; /* OS dependent 1 */
225 uint32_t i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
226 uint32_t i_generation; /* File version (for NFS) */
227 uint32_t i_file_acl; /* File ACL */
228 uint32_t i_dir_acl; /* Directory ACL */
229 uint32_t i_faddr; /* Fragment address */
230 union {
231 struct {
232 uint8_t l_i_frag; /* Fragment number */
233 uint8_t l_i_fsize; /* Fragment size */
234 uint16_t i_pad1;
235 uint16_t l_i_uid_high; /* these 2 fields */
236 uint16_t l_i_gid_high; /* were reserved2[0] */
237 uint32_t l_i_reserved2;
238 } linux2;
239 struct {
240 uint8_t h_i_frag; /* Fragment number */
241 uint8_t h_i_fsize; /* Fragment size */
242 uint16_t h_i_mode_high;
243 uint16_t h_i_uid_high;
244 uint16_t h_i_gid_high;
245 uint32_t h_i_author;
246 } hurd2;
247 struct {
248 uint8_t m_i_frag; /* Fragment number */
249 uint8_t m_i_fsize; /* Fragment size */
250 uint16_t m_pad1;
251 uint32_t m_i_reserved2[2];
252 } masix2;
253 } osd2; /* OS dependent 2 */
254};
255
256/*
257 * Permanent part of an large inode on the disk
258 */
259struct ext2_inode_large {
260 uint16_t i_mode; /* File mode */
261 uint16_t i_uid; /* Low 16 bits of Owner Uid */
262 uint32_t i_size; /* Size in bytes */
263 uint32_t i_atime; /* Access time */
264 uint32_t i_ctime; /* Creation time */
265 uint32_t i_mtime; /* Modification time */
266 uint32_t i_dtime; /* Deletion Time */
267 uint16_t i_gid; /* Low 16 bits of Group Id */
268 uint16_t i_links_count; /* Links count */
269 uint32_t i_blocks; /* Blocks count */
270 uint32_t i_flags; /* File flags */
271 union {
272 struct {
273 uint32_t l_i_reserved1;
274 } linux1;
275 struct {
276 uint32_t h_i_translator;
277 } hurd1;
278 struct {
279 uint32_t m_i_reserved1;
280 } masix1;
281 } osd1; /* OS dependent 1 */
282 uint32_t i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
283 uint32_t i_generation; /* File version (for NFS) */
284 uint32_t i_file_acl; /* File ACL */
285 uint32_t i_dir_acl; /* Directory ACL */
286 uint32_t i_faddr; /* Fragment address */
287 union {
288 struct {
289 uint8_t l_i_frag; /* Fragment number */
290 uint8_t l_i_fsize; /* Fragment size */
291 uint16_t i_pad1;
292 uint16_t l_i_uid_high; /* these 2 fields */
293 uint16_t l_i_gid_high; /* were reserved2[0] */
294 uint32_t l_i_reserved2;
295 } linux2;
296 struct {
297 uint8_t h_i_frag; /* Fragment number */
298 uint8_t h_i_fsize; /* Fragment size */
299 uint16_t h_i_mode_high;
300 uint16_t h_i_uid_high;
301 uint16_t h_i_gid_high;
302 uint32_t h_i_author;
303 } hurd2;
304 struct {
305 uint8_t m_i_frag; /* Fragment number */
306 uint8_t m_i_fsize; /* Fragment size */
307 uint16_t m_pad1;
308 uint32_t m_i_reserved2[2];
309 } masix2;
310 } osd2; /* OS dependent 2 */
311 uint16_t i_extra_isize;
312 uint16_t i_pad1;
313};
314
315#define i_size_high i_dir_acl
316
317/*
318 * File system states
319 */
320#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
321#define EXT2_ERROR_FS 0x0002 /* Errors detected */
322
323/*
324 * Mount flags
325 */
326#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
327#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
328#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
329#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
330#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
331#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
332#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
333#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
334
335#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
336#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
337#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
338 EXT2_MOUNT_##opt)
339/*
340 * Maximal mount counts between two filesystem checks
341 */
342#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
343#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
344
345/*
346 * Behaviour when detecting errors
347 */
348#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
349#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
350#define EXT2_ERRORS_PANIC 3 /* Panic */
351#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
352
353/*
354 * Structure of the super block
355 */
356struct ext2_super_block {
357 uint32_t s_inodes_count; /* Inodes count */
358 uint32_t s_blocks_count; /* Blocks count */
359 uint32_t s_r_blocks_count; /* Reserved blocks count */
360 uint32_t s_free_blocks_count; /* Free blocks count */
361 uint32_t s_free_inodes_count; /* Free inodes count */
362 uint32_t s_first_data_block; /* First Data Block */
363 uint32_t s_log_block_size; /* Block size */
364 int32_t s_log_frag_size; /* Fragment size */
365 uint32_t s_blocks_per_group; /* # Blocks per group */
366 uint32_t s_frags_per_group; /* # Fragments per group */
367 uint32_t s_inodes_per_group; /* # Inodes per group */
368 uint32_t s_mtime; /* Mount time */
369 uint32_t s_wtime; /* Write time */
370 uint16_t s_mnt_count; /* Mount count */
371 int16_t s_max_mnt_count; /* Maximal mount count */
372 uint16_t s_magic; /* Magic signature */
373 uint16_t s_state; /* File system state */
374 uint16_t s_errors; /* Behaviour when detecting errors */
375 uint16_t s_minor_rev_level; /* minor revision level */
376 uint32_t s_lastcheck; /* time of last check */
377 uint32_t s_checkinterval; /* max. time between checks */
378 uint32_t s_creator_os; /* OS */
379 uint32_t s_rev_level; /* Revision level */
380 uint16_t s_def_resuid; /* Default uid for reserved blocks */
381 uint16_t s_def_resgid; /* Default gid for reserved blocks */
382 /*
383 * These fields are for EXT2_DYNAMIC_REV superblocks only.
384 *
385 * Note: the difference between the compatible feature set and
386 * the incompatible feature set is that if there is a bit set
387 * in the incompatible feature set that the kernel doesn't
388 * know about, it should refuse to mount the filesystem.
389 *
390 * e2fsck's requirements are more strict; if it doesn't know
391 * about a feature in either the compatible or incompatible
392 * feature set, it must abort and not try to meddle with
393 * things it doesn't understand...
394 */
395 uint32_t s_first_ino; /* First non-reserved inode */
396 uint16_t s_inode_size; /* size of inode structure */
397 uint16_t s_block_group_nr; /* block group # of this superblock */
398 uint32_t s_feature_compat; /* compatible feature set */
399 uint32_t s_feature_incompat; /* incompatible feature set */
400 uint32_t s_feature_ro_compat; /* readonly-compatible feature set */
401 uint8_t s_uuid[16]; /* 128-bit uuid for volume */
402 char s_volume_name[16]; /* volume name */
403 char s_last_mounted[64]; /* directory where last mounted */
404 uint32_t s_algorithm_usage_bitmap; /* For compression */
405 /*
406 * Performance hints. Directory preallocation should only
407 * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
408 */
409 uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
410 uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
411 uint16_t s_reserved_gdt_blocks; /* Per group table for online growth */
412 /*
413 * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
414 */
415 uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
416 uint32_t s_journal_inum; /* inode number of journal file */
417 uint32_t s_journal_dev; /* device number of journal file */
418 uint32_t s_last_orphan; /* start of list of inodes to delete */
419 uint32_t s_hash_seed[4]; /* HTREE hash seed */
420 uint8_t s_def_hash_version; /* Default hash version to use */
421 uint8_t s_jnl_backup_type; /* Default type of journal backup */
422 uint16_t s_reserved_word_pad;
423 uint32_t s_default_mount_opts;
424 uint32_t s_first_meta_bg; /* First metablock group */
425 uint32_t s_mkfs_time; /* When the filesystem was created */
426 uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */
427 uint32_t s_reserved[172]; /* Padding to the end of the block */
428};
429
430/*
431 * Codes for operating systems
432 */
433#define EXT2_OS_LINUX 0
434#define EXT2_OS_HURD 1
435#define EXT2_OS_MASIX 2
436#define EXT2_OS_FREEBSD 3
437#define EXT2_OS_LITES 4
438
439/*
440 * Revision levels
441 */
442#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
443#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
444
445#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
446#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
447
448#define EXT2_GOOD_OLD_INODE_SIZE 128
449
450/*
451 * Journal inode backup types
452 */
453#define EXT3_JNL_BACKUP_BLOCKS 1
454
455/*
456 * Feature set definitions
457 */
458
459#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
460 ( EXT2_SB(sb)->s_feature_compat & (mask) )
461#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
462 ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
463#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
464 ( EXT2_SB(sb)->s_feature_incompat & (mask) )
465
466#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
467#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
468#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
469#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
470#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
471#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
472
473#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
474#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
475/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */
476
477#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
478#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
479#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
480#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
481#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
482#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
483
484
485#define EXT2_FEATURE_COMPAT_SUPP 0
486#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE)
487#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
488 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
489 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
490
491/*
492 * Default values for user and/or group using reserved blocks
493 */
494#define EXT2_DEF_RESUID 0
495#define EXT2_DEF_RESGID 0
496
497/*
498 * Default mount options
499 */
500#define EXT2_DEFM_DEBUG 0x0001
501#define EXT2_DEFM_BSDGROUPS 0x0002
502#define EXT2_DEFM_XATTR_USER 0x0004
503#define EXT2_DEFM_ACL 0x0008
504#define EXT2_DEFM_UID16 0x0010
505#define EXT3_DEFM_JMODE 0x0060
506#define EXT3_DEFM_JMODE_DATA 0x0020
507#define EXT3_DEFM_JMODE_ORDERED 0x0040
508#define EXT3_DEFM_JMODE_WBACK 0x0060
509
510/*
511 * Structure of a directory entry
512 */
513#define EXT2_NAME_LEN 255
514
515struct ext2_dir_entry {
516 uint32_t inode; /* Inode number */
517 uint16_t rec_len; /* Directory entry length */
518 uint16_t name_len; /* Name length */
519 char name[EXT2_NAME_LEN]; /* File name */
520};
521
522/*
523 * The new version of the directory entry. Since EXT2 structures are
524 * stored in intel byte order, and the name_len field could never be
525 * bigger than 255 chars, it's safe to reclaim the extra byte for the
526 * file_type field.
527 */
528struct ext2_dir_entry_2 {
529 uint32_t inode; /* Inode number */
530 uint16_t rec_len; /* Directory entry length */
531 uint8_t name_len; /* Name length */
532 uint8_t file_type;
533 char name[EXT2_NAME_LEN]; /* File name */
534};
535
536/*
537 * Ext2 directory file types. Only the low 3 bits are used. The
538 * other bits are reserved for now.
539 */
540#define EXT2_FT_UNKNOWN 0
541#define EXT2_FT_REG_FILE 1
542#define EXT2_FT_DIR 2
543#define EXT2_FT_CHRDEV 3
544#define EXT2_FT_BLKDEV 4
545#define EXT2_FT_FIFO 5
546#define EXT2_FT_SOCK 6
547#define EXT2_FT_SYMLINK 7
548
549#define EXT2_FT_MAX 8
550
551/*
552 * EXT2_DIR_PAD defines the directory entries boundaries
553 *
554 * NOTE: It must be a multiple of 4
555 */
556#define EXT2_DIR_PAD 4
557#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
558#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
559 ~EXT2_DIR_ROUND)
560
561#endif /* _LINUX_EXT2_FS_H */
diff --git a/e2fsprogs/e2fs_lib.c b/e2fsprogs/e2fs_lib.c
new file mode 100644
index 000000000..cdf97352a
--- /dev/null
+++ b/e2fsprogs/e2fs_lib.c
@@ -0,0 +1,197 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * See README for additional information
4 *
5 * This file can be redistributed under the terms of the GNU Library General
6 * Public License
7 */
8
9#include "libbb.h"
10#include "e2fs_lib.h"
11
12#define HAVE_EXT2_IOCTLS 1
13
14#if INT_MAX == LONG_MAX
15#define IF_LONG_IS_SAME(x) x
16#define IF_LONG_IS_WIDER(x)
17#else
18#define IF_LONG_IS_SAME(x)
19#define IF_LONG_IS_WIDER(x) x
20#endif
21
22static void close_silently(int fd)
23{
24 int e = errno;
25 close(fd);
26 errno = e;
27}
28
29
30/* Iterate a function on each entry of a directory */
31int iterate_on_dir(const char *dir_name,
32 int (*func)(const char *, struct dirent *, void *),
33 void * private)
34{
35 DIR *dir;
36 struct dirent *de, *dep;
37 int max_len, len;
38
39 max_len = PATH_MAX + sizeof(struct dirent);
40 de = xmalloc(max_len+1);
41 memset(de, 0, max_len+1);
42
43 dir = opendir(dir_name);
44 if (dir == NULL) {
45 free(de);
46 return -1;
47 }
48 while ((dep = readdir(dir))) {
49 len = sizeof(struct dirent);
50 if (len < dep->d_reclen)
51 len = dep->d_reclen;
52 if (len > max_len)
53 len = max_len;
54 memcpy(de, dep, len);
55 func(dir_name, de, private);
56 }
57 closedir(dir);
58 free(de);
59 return 0;
60}
61
62
63/* Get/set a file version on an ext2 file system */
64int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version)
65{
66#if HAVE_EXT2_IOCTLS
67 int fd, r;
68 IF_LONG_IS_WIDER(int ver;)
69
70 fd = open(name, O_NONBLOCK);
71 if (fd == -1)
72 return -1;
73 if (!get_version) {
74 IF_LONG_IS_WIDER(
75 ver = (int) set_version;
76 r = ioctl(fd, EXT2_IOC_SETVERSION, &ver);
77 )
78 IF_LONG_IS_SAME(
79 r = ioctl(fd, EXT2_IOC_SETVERSION, (void*)&set_version);
80 )
81 } else {
82 IF_LONG_IS_WIDER(
83 r = ioctl(fd, EXT2_IOC_GETVERSION, &ver);
84 *get_version = ver;
85 )
86 IF_LONG_IS_SAME(
87 r = ioctl(fd, EXT2_IOC_GETVERSION, (void*)get_version);
88 )
89 }
90 close_silently(fd);
91 return r;
92#else /* ! HAVE_EXT2_IOCTLS */
93 errno = EOPNOTSUPP;
94 return -1;
95#endif /* ! HAVE_EXT2_IOCTLS */
96}
97
98
99/* Get/set a file flags on an ext2 file system */
100int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags)
101{
102#if HAVE_EXT2_IOCTLS
103 struct stat buf;
104 int fd, r;
105 IF_LONG_IS_WIDER(int f;)
106
107 if (stat(name, &buf) == 0 /* stat is ok */
108 && !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)
109 ) {
110 goto notsupp;
111 }
112 fd = open(name, O_NONBLOCK); /* neither read nor write asked for */
113 if (fd == -1)
114 return -1;
115
116 if (!get_flags) {
117 IF_LONG_IS_WIDER(
118 f = (int) set_flags;
119 r = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
120 )
121 IF_LONG_IS_SAME(
122 r = ioctl(fd, EXT2_IOC_SETFLAGS, (void*)&set_flags);
123 )
124 } else {
125 IF_LONG_IS_WIDER(
126 r = ioctl(fd, EXT2_IOC_GETFLAGS, &f);
127 *get_flags = f;
128 )
129 IF_LONG_IS_SAME(
130 r = ioctl(fd, EXT2_IOC_GETFLAGS, (void*)get_flags);
131 )
132 }
133
134 close_silently(fd);
135 return r;
136 notsupp:
137#endif /* HAVE_EXT2_IOCTLS */
138 errno = EOPNOTSUPP;
139 return -1;
140}
141
142
143/* Print file attributes on an ext2 file system */
144struct flags_name {
145 unsigned long flag;
146 const char *short_name;
147 const char *long_name;
148};
149
150static const struct flags_name flags_array[] = {
151 { EXT2_SECRM_FL, "s", "Secure_Deletion" },
152 { EXT2_UNRM_FL, "u" , "Undelete" },
153 { EXT2_SYNC_FL, "S", "Synchronous_Updates" },
154 { EXT2_DIRSYNC_FL, "D", "Synchronous_Directory_Updates" },
155 { EXT2_IMMUTABLE_FL, "i", "Immutable" },
156 { EXT2_APPEND_FL, "a", "Append_Only" },
157 { EXT2_NODUMP_FL, "d", "No_Dump" },
158 { EXT2_NOATIME_FL, "A", "No_Atime" },
159 { EXT2_COMPR_FL, "c", "Compression_Requested" },
160#ifdef ENABLE_COMPRESSION
161 { EXT2_COMPRBLK_FL, "B", "Compressed_File" },
162 { EXT2_DIRTY_FL, "Z", "Compressed_Dirty_File" },
163 { EXT2_NOCOMPR_FL, "X", "Compression_Raw_Access" },
164 { EXT2_ECOMPR_FL, "E", "Compression_Error" },
165#endif
166 { EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" },
167 { EXT2_INDEX_FL, "I", "Indexed_direcctory" },
168 { EXT2_NOTAIL_FL, "t", "No_Tailmerging" },
169 { EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" },
170 { 0, NULL, NULL }
171};
172
173void print_flags(FILE *f, unsigned long flags, unsigned options)
174{
175 const struct flags_name *fp;
176
177 if (options & PFOPT_LONG) {
178 int first = 1;
179 for (fp = flags_array; fp->flag != 0; fp++) {
180 if (flags & fp->flag) {
181 if (!first)
182 fputs(", ", f);
183 fputs(fp->long_name, f);
184 first = 0;
185 }
186 }
187 if (first)
188 fputs("---", f);
189 } else {
190 for (fp = flags_array; fp->flag != 0; fp++) {
191 const char *p = "-";
192 if (flags & fp->flag)
193 p = fp->short_name;
194 fputs(p, f);
195 }
196 }
197}
diff --git a/e2fsprogs/e2fs_lib.h b/e2fsprogs/e2fs_lib.h
new file mode 100644
index 000000000..1a7d3a16b
--- /dev/null
+++ b/e2fsprogs/e2fs_lib.h
@@ -0,0 +1,30 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * See README for additional information
4 *
5 * This file can be redistributed under the terms of the GNU Library General
6 * Public License
7 */
8
9/* Constants and structures */
10#include "e2fs_defs.h"
11
12/* Iterate a function on each entry of a directory */
13int iterate_on_dir(const char *dir_name,
14 int (*func)(const char *, struct dirent *, void *),
15 void *private);
16
17/* Get/set a file version on an ext2 file system */
18int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version);
19#define fgetversion(name, version) fgetsetversion(name, version, 0)
20#define fsetversion(name, version) fgetsetversion(name, NULL, version)
21
22/* Get/set a file flags on an ext2 file system */
23int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags);
24#define fgetflags(name, flags) fgetsetflags(name, flags, 0)
25#define fsetflags(name, flags) fgetsetflags(name, NULL, flags)
26
27/* Must be 1 for compatibility with `int long_format'. */
28#define PFOPT_LONG 1
29/* Print file attributes on an ext2 file system */
30void print_flags(FILE *f, unsigned long flags, unsigned options);
diff --git a/e2fsprogs/fsck.c b/e2fsprogs/fsck.c
new file mode 100644
index 000000000..d59206ca2
--- /dev/null
+++ b/e2fsprogs/fsck.c
@@ -0,0 +1,1319 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fsck --- A generic, parallelizing front-end for the fsck program.
4 * It will automatically try to run fsck programs in parallel if the
5 * devices are on separate spindles. It is based on the same ideas as
6 * the generic front end for fsck by David Engel and Fred van Kempen,
7 * but it has been completely rewritten from scratch to support
8 * parallel execution.
9 *
10 * Written by Theodore Ts'o, <tytso@mit.edu>
11 *
12 * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994:
13 * o Changed -t fstype to behave like with mount when -A (all file
14 * systems) or -M (like mount) is specified.
15 * o fsck looks if it can find the fsck.type program to decide
16 * if it should ignore the fs type. This way more fsck programs
17 * can be added without changing this front-end.
18 * o -R flag skip root file system.
19 *
20 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
21 * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
22 *
23 * %Begin-Header%
24 * This file may be redistributed under the terms of the GNU Public
25 * License.
26 * %End-Header%
27 */
28
29#include "busybox.h"
30/*#include "e2fs_lib.h"*/
31
32#define EXIT_OK 0
33#define EXIT_NONDESTRUCT 1
34#define EXIT_DESTRUCT 2
35#define EXIT_UNCORRECTED 4
36#define EXIT_ERROR 8
37#define EXIT_USAGE 16
38#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
39
40#ifndef DEFAULT_FSTYPE
41#define DEFAULT_FSTYPE "ext2"
42#endif
43
44#define MAX_DEVICES 32
45#define MAX_ARGS 32
46
47/*
48 * Internal structure for mount tabel entries.
49 */
50
51struct fs_info {
52 char *device;
53 char *mountpt;
54 char *type;
55 char *opts;
56 int freq;
57 int passno;
58 int flags;
59 struct fs_info *next;
60};
61
62#define FLAG_DONE 1
63#define FLAG_PROGRESS 2
64/*
65 * Structure to allow exit codes to be stored
66 */
67struct fsck_instance {
68 int pid;
69 int flags;
70 int exit_status;
71 time_t start_time;
72 char *prog;
73 char *type;
74 char *device;
75 char *base_device; /* /dev/hda for /dev/hdaN etc */
76 struct fsck_instance *next;
77};
78
79static const char * const ignored_types[] = {
80 "ignore",
81 "iso9660",
82 "nfs",
83 "proc",
84 "sw",
85 "swap",
86 "tmpfs",
87 "devpts",
88 NULL
89};
90
91static const char * const really_wanted[] = {
92 "minix",
93 "ext2",
94 "ext3",
95 "jfs",
96 "reiserfs",
97 "xiafs",
98 "xfs",
99 NULL
100};
101
102#define BASE_MD "/dev/md"
103
104/*
105 * Global variables for options
106 */
107static char **devices;
108static char **args;
109static int num_devices, num_args;
110
111static int verbose;
112static int doall;
113static int noexecute;
114static int serialize;
115static int skip_root;
116static int like_mount;
117static int notitle;
118static int parallel_root;
119static int progress;
120static int progress_fd;
121static int force_all_parallel;
122static int num_running;
123static int max_running;
124static volatile int cancel_requested;
125static int kill_sent;
126static char *fstype;
127static struct fs_info *filesys_info, *filesys_last;
128static struct fsck_instance *instance_list;
129/*static char *fsck_path;*/
130/*static blkid_cache cache;*/
131
132#define FS_TYPE_FLAG_NORMAL 0
133#define FS_TYPE_FLAG_OPT 1
134#define FS_TYPE_FLAG_NEGOPT 2
135static char **fs_type_list;
136static uint8_t *fs_type_flag;
137static int fs_type_negated;
138
139/*
140 * Return the "base device" given a particular device; this is used to
141 * assure that we only fsck one partition on a particular drive at any
142 * one time. Otherwise, the disk heads will be seeking all over the
143 * place. If the base device cannot be determined, return NULL.
144 *
145 * The base_device() function returns an allocated string which must
146 * be freed.
147 */
148#if ENABLE_FEATURE_DEVFS
149/*
150 * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
151 * pathames.
152 */
153static const char *const devfs_hier[] = {
154 "host", "bus", "target", "lun", NULL
155};
156#endif
157
158static char *base_device(const char *device)
159{
160 char *str, *cp;
161#if ENABLE_FEATURE_DEVFS
162 const char *const *hier;
163 const char *disk;
164 int len;
165#endif
166 cp = str = xstrdup(device);
167
168 /* Skip over /dev/; if it's not present, give up. */
169 if (strncmp(cp, "/dev/", 5) != 0)
170 goto errout;
171 cp += 5;
172
173 /*
174 * For md devices, we treat them all as if they were all
175 * on one disk, since we don't know how to parallelize them.
176 */
177 if (cp[0] == 'm' && cp[1] == 'd') {
178 cp[2] = 0;
179 return str;
180 }
181
182 /* Handle DAC 960 devices */
183 if (strncmp(cp, "rd/", 3) == 0) {
184 cp += 3;
185 if (cp[0] != 'c' || !isdigit(cp[1])
186 || cp[2] != 'd' || !isdigit(cp[3]))
187 goto errout;
188 cp[4] = 0;
189 return str;
190 }
191
192 /* Now let's handle /dev/hd* and /dev/sd* devices.... */
193 if ((cp[0] == 'h' || cp[0] == 's') && cp[1] == 'd') {
194 cp += 2;
195 /* If there's a single number after /dev/hd, skip it */
196 if (isdigit(*cp))
197 cp++;
198 /* What follows must be an alpha char, or give up */
199 if (!isalpha(*cp))
200 goto errout;
201 cp[1] = 0;
202 return str;
203 }
204
205#if ENABLE_FEATURE_DEVFS
206 /* Now let's handle devfs (ugh) names */
207 len = 0;
208 if (strncmp(cp, "ide/", 4) == 0)
209 len = 4;
210 if (strncmp(cp, "scsi/", 5) == 0)
211 len = 5;
212 if (len) {
213 cp += len;
214 /*
215 * Now we proceed down the expected devfs hierarchy.
216 * i.e., .../host1/bus2/target3/lun4/...
217 * If we don't find the expected token, followed by
218 * some number of digits at each level, abort.
219 */
220 for (hier = devfs_hier; *hier; hier++) {
221 len = strlen(*hier);
222 if (strncmp(cp, *hier, len) != 0)
223 goto errout;
224 cp += len;
225 while (*cp != '/' && *cp != 0) {
226 if (!isdigit(*cp))
227 goto errout;
228 cp++;
229 }
230 cp++;
231 }
232 cp[-1] = 0;
233 return str;
234 }
235
236 /* Now handle devfs /dev/disc or /dev/disk names */
237 disk = 0;
238 if (strncmp(cp, "discs/", 6) == 0)
239 disk = "disc";
240 else if (strncmp(cp, "disks/", 6) == 0)
241 disk = "disk";
242 if (disk) {
243 cp += 6;
244 if (strncmp(cp, disk, 4) != 0)
245 goto errout;
246 cp += 4;
247 while (*cp != '/' && *cp != 0) {
248 if (!isdigit(*cp))
249 goto errout;
250 cp++;
251 }
252 *cp = 0;
253 return str;
254 }
255#endif
256 errout:
257 free(str);
258 return NULL;
259}
260
261static void free_instance(struct fsck_instance *p)
262{
263 free(p->prog);
264 free(p->device);
265 free(p->base_device);
266 free(p);
267}
268
269static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
270 const char *type, const char *opts,
271 int freq, int passno)
272{
273 struct fs_info *fs;
274
275 fs = xzalloc(sizeof(*fs));
276 fs->device = xstrdup(device);
277 fs->mountpt = xstrdup(mntpnt);
278 fs->type = xstrdup(type);
279 fs->opts = xstrdup(opts ? opts : "");
280 fs->freq = freq;
281 fs->passno = passno;
282 /*fs->flags = 0; */
283 /*fs->next = NULL; */
284
285 if (!filesys_info)
286 filesys_info = fs;
287 else
288 filesys_last->next = fs;
289 filesys_last = fs;
290
291 return fs;
292}
293
294static void strip_line(char *line)
295{
296 char *p = line + strlen(line) - 1;
297
298 while (*line) {
299 if (*p != '\n' && *p != '\r')
300 break;
301 *p-- = '\0';
302 }
303}
304
305static char *parse_word(char **buf)
306{
307 char *word, *next;
308
309 word = *buf;
310 if (*word == '\0')
311 return NULL;
312
313 word = skip_whitespace(word);
314 next = skip_non_whitespace(word);
315 if (*next)
316 *next++ = '\0';
317 *buf = next;
318 return word;
319}
320
321static void parse_escape(char *word)
322{
323 char *q, c;
324 const char *p;
325
326 if (!word)
327 return;
328
329 for (p = q = word; *p; q++) {
330 c = *p++;
331 if (c != '\\') {
332 *q = c;
333 } else {
334 *q = bb_process_escape_sequence(&p);
335 }
336 }
337 *q = '\0';
338}
339
340static int parse_fstab_line(char *line, struct fs_info **ret_fs)
341{
342 /*char *dev;*/
343 char *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
344 struct fs_info *fs;
345
346 *ret_fs = 0;
347 strip_line(line);
348 cp = strchr(line, '#');
349 if (cp)
350 *cp = '\0'; /* Ignore everything after the comment char */
351 cp = line;
352
353 device = parse_word(&cp);
354 if (!device) return 0; /* Allow blank lines */
355 mntpnt = parse_word(&cp);
356 type = parse_word(&cp);
357 opts = parse_word(&cp);
358 freq = parse_word(&cp);
359 passno = parse_word(&cp);
360
361 if (!mntpnt || !type)
362 return -1;
363
364 parse_escape(device);
365 parse_escape(mntpnt);
366 parse_escape(type);
367 parse_escape(opts);
368 parse_escape(freq);
369 parse_escape(passno);
370
371 /*
372 dev = blkid_get_devname(cache, device, NULL);
373 if (dev)
374 device = dev;*/
375
376 if (strchr(type, ','))
377 type = NULL;
378
379 fs = create_fs_device(device, mntpnt, type ? type : "auto", opts,
380 freq ? atoi(freq) : -1,
381 passno ? atoi(passno) : -1);
382 /*if (dev)
383 free(dev);*/
384
385 *ret_fs = fs;
386 return 0;
387}
388
389#if 0
390static void interpret_type(struct fs_info *fs)
391{
392 char *t;
393
394 if (strcmp(fs->type, "auto") != 0)
395 return;
396 t = blkid_get_tag_value(cache, "TYPE", fs->device);
397 if (t) {
398 free(fs->type);
399 fs->type = t;
400 }
401}
402#endif
403#define interpret_type(fs) ((void)0)
404
405/*
406 * Load the filesystem database from /etc/fstab
407 */
408static void load_fs_info(const char *filename)
409{
410 FILE *f;
411 int lineno = 0;
412 int old_fstab = 1;
413 struct fs_info *fs;
414
415 f = fopen_or_warn(filename, "r");
416 if (f == NULL) {
417 /*bb_perror_msg("WARNING: cannot open %s", filename);*/
418 return;
419 }
420 while (1) {
421 int r;
422 char *buf = xmalloc_getline(f);
423 if (!buf) break;
424 r = parse_fstab_line(buf, &fs);
425 free(buf);
426 lineno++;
427 if (r < 0) {
428 bb_error_msg("WARNING: bad format "
429 "on line %d of %s\n", lineno, filename);
430 continue;
431 }
432 if (!fs)
433 continue;
434 if (fs->passno < 0)
435 fs->passno = 0;
436 else
437 old_fstab = 0;
438 }
439 fclose(f);
440
441 if (old_fstab) {
442 fputs("\007\007\007"
443 "WARNING: Your /etc/fstab does not contain the fsck passno\n"
444 " field. I will kludge around things for you, but you\n"
445 " should fix your /etc/fstab file as soon as you can.\n\n", stderr);
446
447 for (fs = filesys_info; fs; fs = fs->next) {
448 fs->passno = 1;
449 }
450 }
451}
452
453/* Lookup filesys in /etc/fstab and return the corresponding entry. */
454static struct fs_info *lookup(char *filesys)
455{
456 struct fs_info *fs;
457
458 /* No filesys name given. */
459 if (filesys == NULL)
460 return NULL;
461
462 for (fs = filesys_info; fs; fs = fs->next) {
463 if (strcmp(filesys, fs->device) == 0
464 || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0)
465 )
466 break;
467 }
468
469 return fs;
470}
471
472#if 0
473/* Find fsck program for a given fs type. */
474static char *find_fsck(char *type)
475{
476 char *s;
477 const char *tpl;
478 char *p = xstrdup(fsck_path);
479 struct stat st;
480
481 /* Are we looking for a program or just a type? */
482 tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s");
483
484 for (s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
485 s = xasprintf(tpl, s, type);
486 if (stat(s, &st) == 0)
487 break;
488 free(s);
489 }
490 free(p);
491 return s;
492}
493#endif
494
495static int progress_active(void)
496{
497 struct fsck_instance *inst;
498
499 for (inst = instance_list; inst; inst = inst->next) {
500 if (inst->flags & FLAG_DONE)
501 continue;
502 if (inst->flags & FLAG_PROGRESS)
503 return 1;
504 }
505 return 0;
506}
507
508/*
509 * Execute a particular fsck program, and link it into the list of
510 * child processes we are waiting for.
511 */
512static int execute(const char *type, const char *device, const char *mntpt,
513 int interactive)
514{
515 char *argv[num_args + 4]; /* see count below: */
516 int argc;
517 int i;
518 struct fsck_instance *inst, *p;
519 pid_t pid;
520
521 inst = xzalloc(sizeof(*inst));
522
523 argv[0] = xasprintf("fsck.%s", type); /* 1 */
524 for (i = 0; i < num_args; i++)
525 argv[i+1] = args[i]; /* num_args */
526 argc = num_args + 1;
527
528 if (progress && !progress_active()) {
529 if (strcmp(type, "ext2") == 0
530 || strcmp(type, "ext3") == 0
531 ) {
532 argv[argc++] = xasprintf("-C%d", progress_fd); /* 1 */
533 inst->flags |= FLAG_PROGRESS;
534 }
535 }
536
537 argv[argc++] = xstrdup(device); /* 1 */
538 argv[argc] = 0; /* 1 */
539
540 if (verbose || noexecute) {
541 printf("[%s (%d) -- %s]", argv[0], num_running,
542 mntpt ? mntpt : device);
543 for (i = 0; i < argc; i++)
544 printf(" %s", argv[i]);
545 puts("");
546 }
547
548 /* Fork and execute the correct program. */
549 if (noexecute)
550 pid = -1;
551 else if ((pid = fork()) < 0) {
552 bb_perror_msg("fork");
553 return errno;
554 }
555 if (pid == 0) {
556 /* Child */
557 if (!interactive)
558 close(0);
559 execvp(argv[0], argv);
560 bb_perror_msg_and_die("%s", argv[0]);
561 }
562
563 for (i = num_args+1; i < argc; i++)
564 free(argv[i]);
565
566 inst->pid = pid;
567 inst->prog = argv[0];
568 inst->type = xstrdup(type);
569 inst->device = xstrdup(device);
570 inst->base_device = base_device(device);
571 inst->start_time = time(0);
572 inst->next = NULL;
573
574 /*
575 * Find the end of the list, so we add the instance on at the end.
576 */
577 if (!instance_list) {
578 instance_list = inst;
579 return 0;
580 }
581 p = instance_list;
582 while (p->next)
583 p = p->next;
584 p->next = inst;
585 return 0;
586}
587
588/*
589 * Send a signal to all outstanding fsck child processes
590 */
591static int kill_all(int signum)
592{
593 struct fsck_instance *inst;
594 int n = 0;
595
596 for (inst = instance_list; inst; inst = inst->next) {
597 if (inst->flags & FLAG_DONE)
598 continue;
599 kill(inst->pid, signum);
600 n++;
601 }
602 return n;
603}
604
605/*
606 * Wait for one child process to exit; when it does, unlink it from
607 * the list of executing child processes, and return it.
608 */
609static struct fsck_instance *wait_one(int flags)
610{
611 int status;
612 int sig;
613 struct fsck_instance *inst, *inst2, *prev;
614 pid_t pid;
615
616 if (!instance_list)
617 return NULL;
618
619 if (noexecute) {
620 inst = instance_list;
621 prev = 0;
622#ifdef RANDOM_DEBUG
623 while (inst->next && (random() & 1)) {
624 prev = inst;
625 inst = inst->next;
626 }
627#endif
628 inst->exit_status = 0;
629 goto ret_inst;
630 }
631
632 /*
633 * gcc -Wall fails saving throw against stupidity
634 * (inst and prev are thought to be uninitialized variables)
635 */
636 inst = prev = NULL;
637
638 do {
639 pid = waitpid(-1, &status, flags);
640 if (cancel_requested && !kill_sent) {
641 kill_all(SIGTERM);
642 kill_sent++;
643 }
644 if ((pid == 0) && (flags & WNOHANG))
645 return NULL;
646 if (pid < 0) {
647 if ((errno == EINTR) || (errno == EAGAIN))
648 continue;
649 if (errno == ECHILD) {
650 bb_error_msg("wait: no more child process?!?");
651 return NULL;
652 }
653 perror("wait");
654 continue;
655 }
656 for (prev = 0, inst = instance_list;
657 inst;
658 prev = inst, inst = inst->next) {
659 if (inst->pid == pid)
660 break;
661 }
662 } while (!inst);
663
664 if (WIFEXITED(status))
665 status = WEXITSTATUS(status);
666 else if (WIFSIGNALED(status)) {
667 sig = WTERMSIG(status);
668 if (sig == SIGINT) {
669 status = EXIT_UNCORRECTED;
670 } else {
671 printf("Warning... %s for device %s exited "
672 "with signal %d.\n",
673 inst->prog, inst->device, sig);
674 status = EXIT_ERROR;
675 }
676 } else {
677 printf("%s %s: status is %x, should never happen.\n",
678 inst->prog, inst->device, status);
679 status = EXIT_ERROR;
680 }
681 inst->exit_status = status;
682 if (progress && (inst->flags & FLAG_PROGRESS) &&
683 !progress_active()) {
684 for (inst2 = instance_list; inst2; inst2 = inst2->next) {
685 if (inst2->flags & FLAG_DONE)
686 continue;
687 if (strcmp(inst2->type, "ext2") &&
688 strcmp(inst2->type, "ext3"))
689 continue;
690 /*
691 * If we've just started the fsck, wait a tiny
692 * bit before sending the kill, to give it
693 * time to set up the signal handler
694 */
695 if (inst2->start_time < time(0)+2) {
696 if (fork() == 0) {
697 sleep(1);
698 kill(inst2->pid, SIGUSR1);
699 exit(0);
700 }
701 } else
702 kill(inst2->pid, SIGUSR1);
703 inst2->flags |= FLAG_PROGRESS;
704 break;
705 }
706 }
707ret_inst:
708 if (prev)
709 prev->next = inst->next;
710 else
711 instance_list = inst->next;
712 if (verbose > 1)
713 printf("Finished with %s (exit status %d)\n",
714 inst->device, inst->exit_status);
715 num_running--;
716 return inst;
717}
718
719#define FLAG_WAIT_ALL 0
720#define FLAG_WAIT_ATLEAST_ONE 1
721/*
722 * Wait until all executing child processes have exited; return the
723 * logical OR of all of their exit code values.
724 */
725static int wait_many(int flags)
726{
727 struct fsck_instance *inst;
728 int global_status = 0;
729 int wait_flags = 0;
730
731 while ((inst = wait_one(wait_flags))) {
732 global_status |= inst->exit_status;
733 free_instance(inst);
734#ifdef RANDOM_DEBUG
735 if (noexecute && (flags & WNOHANG) && !(random() % 3))
736 break;
737#endif
738 if (flags & FLAG_WAIT_ATLEAST_ONE)
739 wait_flags = WNOHANG;
740 }
741 return global_status;
742}
743
744/*
745 * Run the fsck program on a particular device
746 *
747 * If the type is specified using -t, and it isn't prefixed with "no"
748 * (as in "noext2") and only one filesystem type is specified, then
749 * use that type regardless of what is specified in /etc/fstab.
750 *
751 * If the type isn't specified by the user, then use either the type
752 * specified in /etc/fstab, or DEFAULT_FSTYPE.
753 */
754static void fsck_device(struct fs_info *fs, int interactive)
755{
756 const char *type;
757 int retval;
758
759 interpret_type(fs);
760
761 if (strcmp(fs->type, "auto") != 0)
762 type = fs->type;
763 else if (fstype
764 && strncmp(fstype, "no", 2)
765 && strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4)
766 && !strchr(fstype, ',')
767 )
768 type = fstype;
769 else
770 type = DEFAULT_FSTYPE;
771
772 num_running++;
773 retval = execute(type, fs->device, fs->mountpt, interactive);
774 if (retval) {
775 bb_error_msg("error %d while executing fsck.%s for %s",
776 retval, type, fs->device);
777 num_running--;
778 }
779}
780
781/*
782 * Deal with the fsck -t argument.
783 */
784static void compile_fs_type(char *fs_type)
785{
786 char *cp, *list, *s;
787 int num = 2;
788 int negate;
789
790 if (fs_type) {
791 cp = fs_type;
792 while ((cp = strchr(cp, ','))) {
793 num++;
794 cp++;
795 }
796 }
797
798 fs_type_list = xzalloc(num * sizeof(fs_type_list[0]));
799 fs_type_flag = xzalloc(num * sizeof(fs_type_flag[0]));
800 fs_type_negated = -1;
801
802 if (!fs_type)
803 return;
804
805 list = xstrdup(fs_type);
806 num = 0;
807 s = strtok(list, ",");
808 while (s) {
809 negate = 0;
810 if (s[0] == 'n' && s[1] == 'o') { /* "no.." */
811 s += 2;
812 negate = 1;
813 } else if (s[0] == '!') {
814 s++;
815 negate = 1;
816 }
817 if (strcmp(s, "loop") == 0)
818 /* loop is really short-hand for opts=loop */
819 goto loop_special_case;
820 if (strncmp(s, "opts=", 5) == 0) {
821 s += 5;
822 loop_special_case:
823 fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT;
824 } else {
825 if (fs_type_negated == -1)
826 fs_type_negated = negate;
827 if (fs_type_negated != negate)
828 bb_error_msg_and_die(
829"Either all or none of the filesystem types passed to -t must be prefixed\n"
830"with 'no' or '!'.");
831 }
832 fs_type_list[num++] = xstrdup(s);
833 s = strtok(NULL, ",");
834 }
835 free(list);
836}
837
838/*
839 * This function returns true if a particular option appears in a
840 * comma-delimited options list
841 */
842static int opt_in_list(char *opt, char *optlist)
843{
844 char *list, *s;
845
846 if (!optlist)
847 return 0;
848 list = xstrdup(optlist);
849
850 s = strtok(list, ",");
851 while(s) {
852 if (strcmp(s, opt) == 0) {
853 free(list);
854 return 1;
855 }
856 s = strtok(NULL, ",");
857 }
858 free(list);
859 return 0;
860}
861
862/* See if the filesystem matches the criteria given by the -t option */
863static int fs_match(struct fs_info *fs)
864{
865 int n, ret = 0, checked_type = 0;
866 char *cp;
867
868 if (!fs_type_list)
869 return 1;
870
871 for (n = 0; (cp = fs_type_list[n]); n++) {
872 switch (fs_type_flag[n]) {
873 case FS_TYPE_FLAG_NORMAL:
874 checked_type++;
875 if (strcmp(cp, fs->type) == 0)
876 ret = 1;
877 break;
878 case FS_TYPE_FLAG_NEGOPT:
879 if (opt_in_list(cp, fs->opts))
880 return 0;
881 break;
882 case FS_TYPE_FLAG_OPT:
883 if (!opt_in_list(cp, fs->opts))
884 return 0;
885 break;
886 }
887 }
888 if (checked_type == 0)
889 return 1;
890
891 return (fs_type_negated ? !ret : ret);
892}
893
894/* Check if we should ignore this filesystem. */
895static int ignore(struct fs_info *fs)
896{
897 /*
898 * If the pass number is 0, ignore it.
899 */
900 if (fs->passno == 0)
901 return 1;
902
903 interpret_type(fs);
904
905 /*
906 * If a specific fstype is specified, and it doesn't match,
907 * ignore it.
908 */
909 if (!fs_match(fs))
910 return 1;
911
912 /* Are we ignoring this type? */
913 if (index_in_str_array(ignored_types, fs->type) >= 0)
914 return 1;
915#if 0
916 /* Do we really really want to check this fs? */
917 wanted = index_in_str_array(really_wanted, fs->type) >= 0;
918
919 /* See if the <fsck.fs> program is available. */
920 s = find_fsck(fs->type);
921 if (s == NULL) {
922 if (wanted)
923 bb_error_msg("cannot check %s: fsck.%s not found",
924 fs->device, fs->type);
925 return 1;
926 }
927 free(s);
928#endif
929 /* We can and want to check this file system type. */
930 return 0;
931}
932
933/*
934 * Returns TRUE if a partition on the same disk is already being
935 * checked.
936 */
937static int device_already_active(char *device)
938{
939 struct fsck_instance *inst;
940 char *base;
941
942 if (force_all_parallel)
943 return 0;
944
945#ifdef BASE_MD
946 /* Don't check a soft raid disk with any other disk */
947 if (instance_list
948 && (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1)
949 || !strncmp(device, BASE_MD, sizeof(BASE_MD)-1))
950 ) {
951 return 1;
952 }
953#endif
954
955 base = base_device(device);
956 /*
957 * If we don't know the base device, assume that the device is
958 * already active if there are any fsck instances running.
959 */
960 if (!base)
961 return (instance_list != 0);
962
963 for (inst = instance_list; inst; inst = inst->next) {
964 if (!inst->base_device || !strcmp(base, inst->base_device)) {
965 free(base);
966 return 1;
967 }
968 }
969
970 free(base);
971 return 0;
972}
973
974/* Check all file systems, using the /etc/fstab table. */
975static int check_all(void)
976{
977 struct fs_info *fs = NULL;
978 int status = EXIT_OK;
979 int not_done_yet = 1;
980 int passno = 1;
981 int pass_done;
982
983 if (verbose)
984 puts("Checking all filesystems");
985
986 /*
987 * Do an initial scan over the filesystem; mark filesystems
988 * which should be ignored as done, and resolve any "auto"
989 * filesystem types (done as a side-effect of calling ignore()).
990 */
991 for (fs = filesys_info; fs; fs = fs->next) {
992 if (ignore(fs))
993 fs->flags |= FLAG_DONE;
994 }
995
996 /*
997 * Find and check the root filesystem.
998 */
999 if (!parallel_root) {
1000 for (fs = filesys_info; fs; fs = fs->next) {
1001 if (LONE_CHAR(fs->mountpt, '/'))
1002 break;
1003 }
1004 if (fs) {
1005 if (!skip_root && !ignore(fs)) {
1006 fsck_device(fs, 1);
1007 status |= wait_many(FLAG_WAIT_ALL);
1008 if (status > EXIT_NONDESTRUCT)
1009 return status;
1010 }
1011 fs->flags |= FLAG_DONE;
1012 }
1013 }
1014 /*
1015 * This is for the bone-headed user who enters the root
1016 * filesystem twice. Skip root will skep all root entries.
1017 */
1018 if (skip_root)
1019 for (fs = filesys_info; fs; fs = fs->next)
1020 if (LONE_CHAR(fs->mountpt, '/'))
1021 fs->flags |= FLAG_DONE;
1022
1023 while (not_done_yet) {
1024 not_done_yet = 0;
1025 pass_done = 1;
1026
1027 for (fs = filesys_info; fs; fs = fs->next) {
1028 if (cancel_requested)
1029 break;
1030 if (fs->flags & FLAG_DONE)
1031 continue;
1032 /*
1033 * If the filesystem's pass number is higher
1034 * than the current pass number, then we don't
1035 * do it yet.
1036 */
1037 if (fs->passno > passno) {
1038 not_done_yet++;
1039 continue;
1040 }
1041 /*
1042 * If a filesystem on a particular device has
1043 * already been spawned, then we need to defer
1044 * this to another pass.
1045 */
1046 if (device_already_active(fs->device)) {
1047 pass_done = 0;
1048 continue;
1049 }
1050 /*
1051 * Spawn off the fsck process
1052 */
1053 fsck_device(fs, serialize);
1054 fs->flags |= FLAG_DONE;
1055
1056 /*
1057 * Only do one filesystem at a time, or if we
1058 * have a limit on the number of fsck's extant
1059 * at one time, apply that limit.
1060 */
1061 if (serialize
1062 || (max_running && (num_running >= max_running))
1063 ) {
1064 pass_done = 0;
1065 break;
1066 }
1067 }
1068 if (cancel_requested)
1069 break;
1070 if (verbose > 1)
1071 printf("--waiting-- (pass %d)\n", passno);
1072 status |= wait_many(pass_done ? FLAG_WAIT_ALL :
1073 FLAG_WAIT_ATLEAST_ONE);
1074 if (pass_done) {
1075 if (verbose > 1)
1076 puts("----------------------------------");
1077 passno++;
1078 } else
1079 not_done_yet++;
1080 }
1081 if (cancel_requested && !kill_sent) {
1082 kill_all(SIGTERM);
1083 kill_sent++;
1084 }
1085 status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
1086 return status;
1087}
1088
1089static void signal_cancel(int sig ATTRIBUTE_UNUSED)
1090{
1091 cancel_requested++;
1092}
1093
1094static int string_to_int(const char *s)
1095{
1096 int n;
1097
1098 if (!s) bb_show_usage();
1099 n = bb_strtou(s, NULL, 0);
1100 if (errno || n < 0) bb_show_usage();
1101 return n;
1102}
1103
1104static void parse_args(int argc, char *argv[])
1105{
1106 int i, j;
1107 char *arg, *tmp;
1108 char *options = NULL;
1109 int optpos = 0;
1110 int opts_for_fsck = 0;
1111 struct sigaction sa;
1112
1113 /*
1114 * Set up signal action
1115 */
1116 memset(&sa, 0, sizeof(sa));
1117 sa.sa_handler = signal_cancel;
1118 sigaction(SIGINT, &sa, 0);
1119 sigaction(SIGTERM, &sa, 0);
1120
1121 num_devices = 0;
1122 num_args = 0;
1123 instance_list = 0;
1124
1125/* TODO: getopt32 */
1126 for (i = 1; i < argc; i++) {
1127 arg = argv[i];
1128 if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
1129 if (num_devices >= MAX_DEVICES) {
1130 bb_error_msg_and_die("too many devices");
1131 }
1132#if 0
1133 char *dev;
1134 dev = blkid_get_devname(cache, arg, NULL);
1135 if (!dev && strchr(arg, '=')) {
1136 /*
1137 * Check to see if we failed because
1138 * /proc/partitions isn't found.
1139 */
1140 if (access("/proc/partitions", R_OK) < 0) {
1141 bb_perror_msg_and_die("cannot open /proc/partitions "
1142 "(is /proc mounted?)");
1143 }
1144 /*
1145 * Check to see if this is because
1146 * we're not running as root
1147 */
1148 if (geteuid())
1149 bb_error_msg_and_die(
1150 "must be root to scan for matching filesystems: %s\n", arg);
1151 else
1152 bb_error_msg_and_die(
1153 "cannot find matching filesystem: %s", arg);
1154 }
1155 devices = xrealloc(devices, (num_devices+1) * sizeof(devices[0]));
1156 devices[num_devices++] = dev ? dev : xstrdup(arg);
1157#endif
1158 devices = xrealloc(devices, (num_devices+1) * sizeof(devices[0]));
1159 devices[num_devices++] = xstrdup(arg);
1160 continue;
1161 }
1162 if (arg[0] != '-' || opts_for_fsck) {
1163 args = xrealloc(args, (num_args+1) * sizeof(args[0]));
1164 args[num_args++] = xstrdup(arg);
1165 continue;
1166 }
1167 for (j = 1; arg[j]; j++) {
1168 if (opts_for_fsck) {
1169 optpos++;
1170 /* one extra for '\0' */
1171 options = xrealloc(options, optpos + 2);
1172 options[optpos] = arg[j];
1173 continue;
1174 }
1175 switch (arg[j]) {
1176 case 'A':
1177 doall++;
1178 break;
1179 case 'C':
1180 progress++;
1181 if (arg[++j]) { /* -Cn */
1182 progress_fd = string_to_int(&arg[j]);
1183 goto next_arg;
1184 }
1185 /* -C n */
1186 progress_fd = string_to_int(argv[++i]);
1187 goto next_arg;
1188 case 'V':
1189 verbose++;
1190 break;
1191 case 'N':
1192 noexecute++;
1193 break;
1194 case 'R':
1195 skip_root++;
1196 break;
1197 case 'T':
1198 notitle++;
1199 break;
1200 case 'M':
1201 like_mount++;
1202 break;
1203 case 'P':
1204 parallel_root++;
1205 break;
1206 case 's':
1207 serialize++;
1208 break;
1209 case 't':
1210 if (fstype)
1211 bb_show_usage();
1212 if (arg[++j])
1213 tmp = &arg[j];
1214 else if (++i < argc)
1215 tmp = argv[i];
1216 else
1217 bb_show_usage();
1218 fstype = xstrdup(tmp);
1219 compile_fs_type(fstype);
1220 goto next_arg;
1221 case '-':
1222 opts_for_fsck++;
1223 break;
1224 case '?':
1225 bb_show_usage();
1226 break;
1227 default:
1228 optpos++;
1229 /* one extra for '\0' */
1230 options = xrealloc(options, optpos + 2);
1231 options[optpos] = arg[j];
1232 break;
1233 }
1234 }
1235 next_arg:
1236 if (optpos) {
1237 options[0] = '-';
1238 options[optpos + 1] = '\0';
1239 args = xrealloc(args, (num_args+1) * sizeof(args[0]));
1240 args[num_args++] = options;
1241 optpos = 0;
1242 options = NULL;
1243 }
1244 }
1245 if (getenv("FSCK_FORCE_ALL_PARALLEL"))
1246 force_all_parallel++;
1247 tmp = getenv("FSCK_MAX_INST");
1248 if (tmp)
1249 max_running = xatoi(tmp);
1250}
1251
1252int fsck_main(int argc, char *argv[])
1253{
1254 int i, status = 0;
1255 int interactive = 0;
1256 const char *fstab;
1257 struct fs_info *fs;
1258
1259 setbuf(stdout, NULL);
1260 /*setvbuf(stdout, NULL, _IONBF, BUFSIZ);*/
1261 /*setvbuf(stderr, NULL, _IONBF, BUFSIZ);*/
1262
1263 /*blkid_get_cache(&cache, NULL);*/
1264 parse_args(argc, argv);
1265
1266 if (!notitle)
1267 puts("fsck (busybox "BB_VER", "BB_BT")");
1268
1269 fstab = getenv("FSTAB_FILE");
1270 if (!fstab)
1271 fstab = "/etc/fstab";
1272 load_fs_info(fstab);
1273
1274 /*fsck_path = e2fs_set_sbin_path();*/
1275
1276 if (num_devices == 1 || serialize)
1277 interactive = 1;
1278
1279 /* If -A was specified ("check all"), do that! */
1280 if (doall)
1281 return check_all();
1282
1283 if (num_devices == 0) {
1284 serialize++;
1285 interactive++;
1286 return check_all();
1287 }
1288
1289 for (i = 0 ; i < num_devices; i++) {
1290 if (cancel_requested) {
1291 if (!kill_sent) {
1292 kill_all(SIGTERM);
1293 kill_sent++;
1294 }
1295 break;
1296 }
1297 fs = lookup(devices[i]);
1298 if (!fs) {
1299 fs = create_fs_device(devices[i], 0, "auto", 0, -1, -1);
1300 }
1301 fsck_device(fs, interactive);
1302 if (serialize
1303 || (max_running && (num_running >= max_running))
1304 ) {
1305 struct fsck_instance *inst;
1306
1307 inst = wait_one(0);
1308 if (inst) {
1309 status |= inst->exit_status;
1310 free_instance(inst);
1311 }
1312 if (verbose > 1)
1313 puts("----------------------------------");
1314 }
1315 }
1316 status |= wait_many(FLAG_WAIT_ALL);
1317 /*blkid_put_cache(cache);*/
1318 return status;
1319}
diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c
new file mode 100644
index 000000000..f317b047e
--- /dev/null
+++ b/e2fsprogs/lsattr.c
@@ -0,0 +1,114 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * lsattr.c - List file attributes on an ext2 file system
4 *
5 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * This file can be redistributed under the terms of the GNU General
10 * Public License
11 */
12
13/*
14 * History:
15 * 93/10/30 - Creation
16 * 93/11/13 - Replace stat() calls by lstat() to avoid loops
17 * 94/02/27 - Integrated in Ted's distribution
18 * 98/12/29 - Display version info only when -V specified (G M Sipe)
19 */
20
21#include "busybox.h"
22#include "e2fs_lib.h"
23
24enum {
25 OPT_RECUR = 0x1,
26 OPT_ALL = 0x2,
27 OPT_DIRS_OPT = 0x4,
28 OPT_PF_LONG = 0x8,
29 OPT_GENERATION = 0x10,
30};
31
32static void list_attributes(const char *name)
33{
34 unsigned long fsflags;
35 unsigned long generation;
36
37 if (fgetflags(name, &fsflags) == -1)
38 goto read_err;
39
40 if (option_mask32 & OPT_GENERATION) {
41 if (fgetversion(name, &generation) == -1)
42 goto read_err;
43 printf("%5lu ", generation);
44 }
45
46 if (option_mask32 & OPT_PF_LONG) {
47 printf("%-28s ", name);
48 print_flags(stdout, fsflags, PFOPT_LONG);
49 puts("");
50 } else {
51 print_flags(stdout, fsflags, 0);
52 printf(" %s\n", name);
53 }
54
55 return;
56 read_err:
57 bb_perror_msg("reading %s", name);
58}
59
60static int lsattr_dir_proc(const char *dir_name, struct dirent *de,
61 void *private)
62{
63 struct stat st;
64 char *path;
65
66 path = concat_path_file(dir_name, de->d_name);
67
68 if (lstat(path, &st) == -1)
69 bb_perror_msg("stat %s", path);
70
71 else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) {
72 list_attributes(path);
73 if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR)
74 && (de->d_name[0] != '.'
75 || (de->d_name[1] != '\0' && NOT_LONE_CHAR(de->d_name+1, '.')))
76 ) {
77 printf("\n%s:\n", path);
78 iterate_on_dir(path, lsattr_dir_proc, NULL);
79 puts("");
80 }
81 }
82
83 free(path);
84
85 return 0;
86}
87
88static void lsattr_args(const char *name)
89{
90 struct stat st;
91
92 if (lstat(name, &st) == -1) {
93 bb_perror_msg("stat %s", name);
94 } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) {
95 iterate_on_dir(name, lsattr_dir_proc, NULL);
96 } else {
97 list_attributes(name);
98 }
99}
100
101int lsattr_main(int argc, char **argv)
102{
103 getopt32(argc, argv, "Radlv");
104 argv += optind;
105
106 if (!*argv)
107 lsattr_args(".");
108 else {
109 while (*argv)
110 lsattr_args(*argv++);
111 }
112
113 return EXIT_SUCCESS;
114}
diff --git a/e2fsprogs/old_e2fsprogs/Config.in b/e2fsprogs/old_e2fsprogs/Config.in
new file mode 100644
index 000000000..0062b2fe3
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/Config.in
@@ -0,0 +1,67 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6menu "Linux Ext2 FS Progs"
7
8config CHATTR
9 bool "chattr"
10 default n
11 help
12 chattr changes the file attributes on a second extended file system.
13
14config E2FSCK
15 bool "e2fsck"
16 default n
17 help
18 e2fsck is used to check Linux second extended file systems (ext2fs).
19 e2fsck also supports ext2 filesystems countaining a journal (ext3).
20 The normal compat symlinks 'fsck.ext2' and 'fsck.ext3' are also
21 provided.
22
23config FSCK
24 bool "fsck"
25 default n
26 help
27 fsck is used to check and optionally repair one or more filesystems.
28 In actuality, fsck is simply a front-end for the various file system
29 checkers (fsck.fstype) available under Linux.
30
31config LSATTR
32 bool "lsattr"
33 default n
34 help
35 lsattr lists the file attributes on a second extended file system.
36
37config MKE2FS
38 bool "mke2fs"
39 default n
40 help
41 mke2fs is used to create an ext2/ext3 filesystem. The normal compat
42 symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided.
43
44config TUNE2FS
45 bool "tune2fs"
46 default n
47 help
48 tune2fs allows the system administrator to adjust various tunable
49 filesystem parameters on Linux ext2/ext3 filesystems.
50
51config E2LABEL
52 bool "e2label"
53 default n
54 depends on TUNE2FS
55 help
56 e2label will display or change the filesystem label on the ext2
57 filesystem located on device.
58
59config FINDFS
60 bool "findfs"
61 default n
62 depends on TUNE2FS
63 help
64 findfs will search the disks in the system looking for a filesystem
65 which has a label matching label or a UUID equal to uuid.
66
67endmenu
diff --git a/e2fsprogs/old_e2fsprogs/Kbuild b/e2fsprogs/old_e2fsprogs/Kbuild
new file mode 100644
index 000000000..b05bb92e1
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/Kbuild
@@ -0,0 +1,16 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7lib-y:=
8
9lib-$(CONFIG_CHATTR) += chattr.o
10lib-$(CONFIG_E2FSCK) += e2fsck.o util.o
11lib-$(CONFIG_FSCK) += fsck.o util.o
12lib-$(CONFIG_LSATTR) += lsattr.o
13lib-$(CONFIG_MKE2FS) += mke2fs.o util.o
14lib-$(CONFIG_TUNE2FS) += tune2fs.o util.o
15
16CFLAGS += -include $(srctree)/e2fsprogs/e2fsbb.h
diff --git a/e2fsprogs/old_e2fsprogs/README b/e2fsprogs/old_e2fsprogs/README
new file mode 100644
index 000000000..fac090193
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/README
@@ -0,0 +1,3 @@
1This is a pretty straight rip from the e2fsprogs pkg.
2
3See README's in subdirs for specific info.
diff --git a/e2fsprogs/old_e2fsprogs/blkid/Kbuild b/e2fsprogs/old_e2fsprogs/blkid/Kbuild
new file mode 100644
index 000000000..ddcfdfd9a
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/Kbuild
@@ -0,0 +1,23 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7NEEDED-$(CONFIG_E2FSCK) = y
8NEEDED-$(CONFIG_FSCK) = y
9NEEDED-$(CONFIG_MKE2FS) = y
10NEEDED-$(CONFIG_TUNE2FS) = y
11
12lib-y:=
13lib-$(NEEDED-y) += cache.o dev.o devname.o devno.o blkid_getsize.o \
14 probe.o read.o resolve.o save.o tag.o list.o
15
16CFLAGS_dev.o := -include $(srctree)/include/busybox.h
17CFLAGS_devname.o := -include $(srctree)/include/busybox.h
18CFLAGS_devno.o := -include $(srctree)/include/busybox.h
19CFLAGS_blkid_getsize.o := -include $(srctree)/include/busybox.h
20CFLAGS_probe.o := -include $(srctree)/include/busybox.h
21CFLAGS_save.o := -include $(srctree)/include/busybox.h
22CFLAGS_tag.o := -include $(srctree)/include/busybox.h
23CFLAGS_list.o := -include $(srctree)/include/busybox.h
diff --git a/e2fsprogs/old_e2fsprogs/blkid/blkid.h b/e2fsprogs/old_e2fsprogs/blkid/blkid.h
new file mode 100644
index 000000000..4fa9f6fdf
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/blkid.h
@@ -0,0 +1,105 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * blkid.h - Interface for libblkid, a library to identify block devices
4 *
5 * Copyright (C) 2001 Andreas Dilger
6 * Copyright (C) 2003 Theodore Ts'o
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the
10 * GNU Lesser General Public License.
11 * %End-Header%
12 */
13
14#ifndef _BLKID_BLKID_H
15#define _BLKID_BLKID_H
16
17#include <sys/types.h>
18#include <linux/types.h>
19
20#ifdef __cplusplus
21extern "C" {
22#endif
23
24#define BLKID_VERSION "1.0.0"
25#define BLKID_DATE "12-Feb-2003"
26
27typedef struct blkid_struct_dev *blkid_dev;
28typedef struct blkid_struct_cache *blkid_cache;
29typedef __s64 blkid_loff_t;
30
31typedef struct blkid_struct_tag_iterate *blkid_tag_iterate;
32typedef struct blkid_struct_dev_iterate *blkid_dev_iterate;
33
34/*
35 * Flags for blkid_get_dev
36 *
37 * BLKID_DEV_CREATE Create an empty device structure if not found
38 * in the cache.
39 * BLKID_DEV_VERIFY Make sure the device structure corresponds
40 * with reality.
41 * BLKID_DEV_FIND Just look up a device entry, and return NULL
42 * if it is not found.
43 * BLKID_DEV_NORMAL Get a valid device structure, either from the
44 * cache or by probing the device.
45 */
46#define BLKID_DEV_FIND 0x0000
47#define BLKID_DEV_CREATE 0x0001
48#define BLKID_DEV_VERIFY 0x0002
49#define BLKID_DEV_NORMAL (BLKID_DEV_CREATE | BLKID_DEV_VERIFY)
50
51/* cache.c */
52extern void blkid_put_cache(blkid_cache cache);
53extern int blkid_get_cache(blkid_cache *cache, const char *filename);
54
55/* dev.c */
56extern const char *blkid_dev_devname(blkid_dev dev);
57
58extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache);
59extern int blkid_dev_set_search(blkid_dev_iterate iter,
60 char *search_type, char *search_value);
61extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev);
62extern void blkid_dev_iterate_end(blkid_dev_iterate iterate);
63
64/* devno.c */
65extern char *blkid_devno_to_devname(dev_t devno);
66
67/* devname.c */
68extern int blkid_probe_all(blkid_cache cache);
69extern int blkid_probe_all_new(blkid_cache cache);
70extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname,
71 int flags);
72
73/* getsize.c */
74extern blkid_loff_t blkid_get_dev_size(int fd);
75
76/* probe.c */
77int blkid_known_fstype(const char *fstype);
78extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev);
79
80/* read.c */
81
82/* resolve.c */
83extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname,
84 const char *devname);
85extern char *blkid_get_devname(blkid_cache cache, const char *token,
86 const char *value);
87
88/* tag.c */
89extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev);
90extern int blkid_tag_next(blkid_tag_iterate iterate,
91 const char **type, const char **value);
92extern void blkid_tag_iterate_end(blkid_tag_iterate iterate);
93extern int blkid_dev_has_tag(blkid_dev dev, const char *type,
94 const char *value);
95extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
96 const char *type,
97 const char *value);
98extern int blkid_parse_tag_string(const char *token, char **ret_type,
99 char **ret_val);
100
101#ifdef __cplusplus
102}
103#endif
104
105#endif /* _BLKID_BLKID_H */
diff --git a/e2fsprogs/old_e2fsprogs/blkid/blkidP.h b/e2fsprogs/old_e2fsprogs/blkid/blkidP.h
new file mode 100644
index 000000000..c7cb8abe9
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/blkidP.h
@@ -0,0 +1,187 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * blkidP.h - Internal interfaces for libblkid
4 *
5 * Copyright (C) 2001 Andreas Dilger
6 * Copyright (C) 2003 Theodore Ts'o
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the
10 * GNU Lesser General Public License.
11 * %End-Header%
12 */
13
14#ifndef _BLKID_BLKIDP_H
15#define _BLKID_BLKIDP_H
16
17#include <sys/types.h>
18#include <stdio.h>
19
20#include "blkid.h"
21#include "list.h"
22
23#ifdef __GNUC__
24#define __BLKID_ATTR(x) __attribute__(x)
25#else
26#define __BLKID_ATTR(x)
27#endif
28
29
30/*
31 * This describes the attributes of a specific device.
32 * We can traverse all of the tags by bid_tags (linking to the tag bit_names).
33 * The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag
34 * values, if they exist.
35 */
36struct blkid_struct_dev
37{
38 struct list_head bid_devs; /* All devices in the cache */
39 struct list_head bid_tags; /* All tags for this device */
40 blkid_cache bid_cache; /* Dev belongs to this cache */
41 char *bid_name; /* Device inode pathname */
42 char *bid_type; /* Preferred device TYPE */
43 int bid_pri; /* Device priority */
44 dev_t bid_devno; /* Device major/minor number */
45 time_t bid_time; /* Last update time of device */
46 unsigned int bid_flags; /* Device status bitflags */
47 char *bid_label; /* Shortcut to device LABEL */
48 char *bid_uuid; /* Shortcut to binary UUID */
49};
50
51#define BLKID_BID_FL_VERIFIED 0x0001 /* Device data validated from disk */
52#define BLKID_BID_FL_INVALID 0x0004 /* Device is invalid */
53
54/*
55 * Each tag defines a NAME=value pair for a particular device. The tags
56 * are linked via bit_names for a single device, so that traversing the
57 * names list will get you a list of all tags associated with a device.
58 * They are also linked via bit_values for all devices, so one can easily
59 * search all tags with a given NAME for a specific value.
60 */
61struct blkid_struct_tag
62{
63 struct list_head bit_tags; /* All tags for this device */
64 struct list_head bit_names; /* All tags with given NAME */
65 char *bit_name; /* NAME of tag (shared) */
66 char *bit_val; /* value of tag */
67 blkid_dev bit_dev; /* pointer to device */
68};
69typedef struct blkid_struct_tag *blkid_tag;
70
71/*
72 * Minimum number of seconds between device probes, even when reading
73 * from the cache. This is to avoid re-probing all devices which were
74 * just probed by another program that does not share the cache.
75 */
76#define BLKID_PROBE_MIN 2
77
78/*
79 * Time in seconds an entry remains verified in the in-memory cache
80 * before being reverified (in case of long-running processes that
81 * keep a cache in memory and continue to use it for a long time).
82 */
83#define BLKID_PROBE_INTERVAL 200
84
85/* This describes an entire blkid cache file and probed devices.
86 * We can traverse all of the found devices via bic_list.
87 * We can traverse all of the tag types by bic_tags, which hold empty tags
88 * for each tag type. Those tags can be used as list_heads for iterating
89 * through all devices with a specific tag type (e.g. LABEL).
90 */
91struct blkid_struct_cache
92{
93 struct list_head bic_devs; /* List head of all devices */
94 struct list_head bic_tags; /* List head of all tag types */
95 time_t bic_time; /* Last probe time */
96 time_t bic_ftime; /* Mod time of the cachefile */
97 unsigned int bic_flags; /* Status flags of the cache */
98 char *bic_filename; /* filename of cache */
99};
100
101#define BLKID_BIC_FL_PROBED 0x0002 /* We probed /proc/partition devices */
102#define BLKID_BIC_FL_CHANGED 0x0004 /* Cache has changed from disk */
103
104extern char *blkid_strdup(const char *s);
105extern char *blkid_strndup(const char *s, const int length);
106
107#define BLKID_CACHE_FILE "/etc/blkid.tab"
108extern const char *blkid_devdirs[];
109
110#define BLKID_ERR_IO 5
111#define BLKID_ERR_PROC 9
112#define BLKID_ERR_MEM 12
113#define BLKID_ERR_CACHE 14
114#define BLKID_ERR_DEV 19
115#define BLKID_ERR_PARAM 22
116#define BLKID_ERR_BIG 27
117
118/*
119 * Priority settings for different types of devices
120 */
121#define BLKID_PRI_EVMS 30
122#define BLKID_PRI_LVM 20
123#define BLKID_PRI_MD 10
124
125#if defined(TEST_PROGRAM) && !defined(CONFIG_BLKID_DEBUG)
126#define CONFIG_BLKID_DEBUG
127#endif
128
129#define DEBUG_CACHE 0x0001
130#define DEBUG_DUMP 0x0002
131#define DEBUG_DEV 0x0004
132#define DEBUG_DEVNAME 0x0008
133#define DEBUG_DEVNO 0x0010
134#define DEBUG_PROBE 0x0020
135#define DEBUG_READ 0x0040
136#define DEBUG_RESOLVE 0x0080
137#define DEBUG_SAVE 0x0100
138#define DEBUG_TAG 0x0200
139#define DEBUG_INIT 0x8000
140#define DEBUG_ALL 0xFFFF
141
142#ifdef CONFIG_BLKID_DEBUG
143#include <stdio.h>
144extern int blkid_debug_mask;
145#define DBG(m,x) if ((m) & blkid_debug_mask) x;
146#else
147#define DBG(m,x)
148#endif
149
150#ifdef CONFIG_BLKID_DEBUG
151extern void blkid_debug_dump_dev(blkid_dev dev);
152extern void blkid_debug_dump_tag(blkid_tag tag);
153#endif
154
155/* lseek.c */
156/* extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence); */
157#ifdef CONFIG_LFS
158# define blkid_llseek lseek64
159#else
160# define blkid_llseek lseek
161#endif
162
163/* read.c */
164extern void blkid_read_cache(blkid_cache cache);
165
166/* save.c */
167extern int blkid_flush_cache(blkid_cache cache);
168
169/*
170 * Functions to create and find a specific tag type: tag.c
171 */
172extern void blkid_free_tag(blkid_tag tag);
173extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type);
174extern int blkid_set_tag(blkid_dev dev, const char *name,
175 const char *value, const int vlength);
176
177/*
178 * Functions to create and find a specific tag type: dev.c
179 */
180extern blkid_dev blkid_new_dev(void);
181extern void blkid_free_dev(blkid_dev dev);
182
183#ifdef __cplusplus
184}
185#endif
186
187#endif /* _BLKID_BLKIDP_H */
diff --git a/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c b/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c
new file mode 100644
index 000000000..941efa42c
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c
@@ -0,0 +1,179 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * getsize.c --- get the size of a partition.
4 *
5 * Copyright (C) 1995, 1995 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the
9 * GNU Lesser General Public License.
10 * %End-Header%
11 */
12
13/* include this before sys/queues.h! */
14#include "blkidP.h"
15
16#include <stdio.h>
17#include <unistd.h>
18#ifdef HAVE_ERRNO_H
19#include <errno.h>
20#endif
21#include <fcntl.h>
22#ifdef HAVE_SYS_IOCTL_H
23#include <sys/ioctl.h>
24#endif
25#ifdef HAVE_LINUX_FD_H
26#include <linux/fd.h>
27#endif
28#ifdef HAVE_SYS_DISKLABEL_H
29#include <sys/disklabel.h>
30#include <sys/stat.h>
31#endif
32#ifdef HAVE_SYS_DISK_H
33#ifdef HAVE_SYS_QUEUE_H
34#include <sys/queue.h> /* for LIST_HEAD */
35#endif
36#include <sys/disk.h>
37#endif
38#ifdef __linux__
39#include <sys/utsname.h>
40#endif
41
42#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
43#define BLKGETSIZE _IO(0x12,96) /* return device size */
44#endif
45
46#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
47#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
48#endif
49
50#ifdef APPLE_DARWIN
51#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
52#endif /* APPLE_DARWIN */
53
54static int valid_offset(int fd, blkid_loff_t offset)
55{
56 char ch;
57
58 if (blkid_llseek(fd, offset, 0) < 0)
59 return 0;
60 if (read(fd, &ch, 1) < 1)
61 return 0;
62 return 1;
63}
64
65/*
66 * Returns the number of blocks in a partition
67 */
68blkid_loff_t blkid_get_dev_size(int fd)
69{
70 int valid_blkgetsize64 = 1;
71#ifdef __linux__
72 struct utsname ut;
73#endif
74 unsigned long long size64;
75 unsigned long size;
76 blkid_loff_t high, low;
77#ifdef FDGETPRM
78 struct floppy_struct this_floppy;
79#endif
80#ifdef HAVE_SYS_DISKLABEL_H
81 int part = -1;
82 struct disklabel lab;
83 struct partition *pp;
84 char ch;
85 struct stat st;
86#endif /* HAVE_SYS_DISKLABEL_H */
87
88#ifdef DKIOCGETBLOCKCOUNT /* For Apple Darwin */
89 if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
90 if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
91 && (size64 << 9 > 0xFFFFFFFF))
92 return 0; /* EFBIG */
93 return (blkid_loff_t) size64 << 9;
94 }
95#endif
96
97#ifdef BLKGETSIZE64
98#ifdef __linux__
99 if ((uname(&ut) == 0) &&
100 ((ut.release[0] == '2') && (ut.release[1] == '.') &&
101 (ut.release[2] < '6') && (ut.release[3] == '.')))
102 valid_blkgetsize64 = 0;
103#endif
104 if (valid_blkgetsize64 &&
105 ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
106 if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
107 && ((size64) > 0xFFFFFFFF))
108 return 0; /* EFBIG */
109 return size64;
110 }
111#endif
112
113#ifdef BLKGETSIZE
114 if (ioctl(fd, BLKGETSIZE, &size) >= 0)
115 return (blkid_loff_t)size << 9;
116#endif
117
118#ifdef FDGETPRM
119 if (ioctl(fd, FDGETPRM, &this_floppy) >= 0)
120 return (blkid_loff_t)this_floppy.size << 9;
121#endif
122#ifdef HAVE_SYS_DISKLABEL_H
123#if 0
124 /*
125 * This should work in theory but I haven't tested it. Anyone
126 * on a BSD system want to test this for me? In the meantime,
127 * binary search mechanism should work just fine.
128 */
129 if ((fstat(fd, &st) >= 0) && S_ISBLK(st.st_mode))
130 part = st.st_rdev & 7;
131 if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
132 pp = &lab.d_partitions[part];
133 if (pp->p_size)
134 return pp->p_size << 9;
135 }
136#endif
137#endif /* HAVE_SYS_DISKLABEL_H */
138
139 /*
140 * OK, we couldn't figure it out by using a specialized ioctl,
141 * which is generally the best way. So do binary search to
142 * find the size of the partition.
143 */
144 low = 0;
145 for (high = 1024; valid_offset(fd, high); high *= 2)
146 low = high;
147 while (low < high - 1)
148 {
149 const blkid_loff_t mid = (low + high) / 2;
150
151 if (valid_offset(fd, mid))
152 low = mid;
153 else
154 high = mid;
155 }
156 return low + 1;
157}
158
159#ifdef TEST_PROGRAM
160int main(int argc, char **argv)
161{
162 blkid_loff_t bytes;
163 int fd;
164
165 if (argc < 2) {
166 fprintf(stderr, "Usage: %s device\n"
167 "Determine the size of a device\n", argv[0]);
168 return 1;
169 }
170
171 if ((fd = open(argv[1], O_RDONLY)) < 0)
172 perror(argv[0]);
173
174 bytes = blkid_get_dev_size(fd);
175 printf("Device %s has %lld 1k blocks.\n", argv[1], bytes >> 10);
176
177 return 0;
178}
179#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/cache.c b/e2fsprogs/old_e2fsprogs/blkid/cache.c
new file mode 100644
index 000000000..9bae6fb67
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/cache.c
@@ -0,0 +1,126 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * cache.c - allocation/initialization/free routines for cache
4 *
5 * Copyright (C) 2001 Andreas Dilger
6 * Copyright (C) 2003 Theodore Ts'o
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the
10 * GNU Lesser General Public License.
11 * %End-Header%
12 */
13
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include "blkidP.h"
18
19int blkid_debug_mask = 0;
20
21int blkid_get_cache(blkid_cache *ret_cache, const char *filename)
22{
23 blkid_cache cache;
24
25#ifdef CONFIG_BLKID_DEBUG
26 if (!(blkid_debug_mask & DEBUG_INIT)) {
27 char *dstr = getenv("BLKID_DEBUG");
28
29 if (dstr)
30 blkid_debug_mask = strtoul(dstr, 0, 0);
31 blkid_debug_mask |= DEBUG_INIT;
32 }
33#endif
34
35 DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n",
36 filename ? filename : "default cache"));
37
38 if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache))))
39 return -BLKID_ERR_MEM;
40
41 INIT_LIST_HEAD(&cache->bic_devs);
42 INIT_LIST_HEAD(&cache->bic_tags);
43
44 if (filename && !strlen(filename))
45 filename = 0;
46 if (!filename && (getuid() == geteuid()))
47 filename = getenv("BLKID_FILE");
48 if (!filename)
49 filename = BLKID_CACHE_FILE;
50 cache->bic_filename = blkid_strdup(filename);
51
52 blkid_read_cache(cache);
53
54 *ret_cache = cache;
55 return 0;
56}
57
58void blkid_put_cache(blkid_cache cache)
59{
60 if (!cache)
61 return;
62
63 (void) blkid_flush_cache(cache);
64
65 DBG(DEBUG_CACHE, printf("freeing cache struct\n"));
66
67 /* DBG(DEBUG_CACHE, blkid_debug_dump_cache(cache)); */
68
69 while (!list_empty(&cache->bic_devs)) {
70 blkid_dev dev = list_entry(cache->bic_devs.next,
71 struct blkid_struct_dev,
72 bid_devs);
73 blkid_free_dev(dev);
74 }
75
76 while (!list_empty(&cache->bic_tags)) {
77 blkid_tag tag = list_entry(cache->bic_tags.next,
78 struct blkid_struct_tag,
79 bit_tags);
80
81 while (!list_empty(&tag->bit_names)) {
82 blkid_tag bad = list_entry(tag->bit_names.next,
83 struct blkid_struct_tag,
84 bit_names);
85
86 DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n",
87 bad->bit_name, bad->bit_val));
88 blkid_free_tag(bad);
89 }
90 blkid_free_tag(tag);
91 }
92 free(cache->bic_filename);
93
94 free(cache);
95}
96
97#ifdef TEST_PROGRAM
98int main(int argc, char** argv)
99{
100 blkid_cache cache = NULL;
101 int ret;
102
103 blkid_debug_mask = DEBUG_ALL;
104 if ((argc > 2)) {
105 fprintf(stderr, "Usage: %s [filename]\n", argv[0]);
106 exit(1);
107 }
108
109 if ((ret = blkid_get_cache(&cache, argv[1])) < 0) {
110 fprintf(stderr, "error %d parsing cache file %s\n", ret,
111 argv[1] ? argv[1] : BLKID_CACHE_FILE);
112 exit(1);
113 }
114 if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
115 fprintf(stderr, "%s: error creating cache (%d)\n",
116 argv[0], ret);
117 exit(1);
118 }
119 if ((ret = blkid_probe_all(cache) < 0))
120 fprintf(stderr, "error probing devices\n");
121
122 blkid_put_cache(cache);
123
124 return ret;
125}
126#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/dev.c b/e2fsprogs/old_e2fsprogs/blkid/dev.c
new file mode 100644
index 000000000..eddbd02b7
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/dev.c
@@ -0,0 +1,214 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * dev.c - allocation/initialization/free routines for dev
4 *
5 * Copyright (C) 2001 Andreas Dilger
6 * Copyright (C) 2003 Theodore Ts'o
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the
10 * GNU Lesser General Public License.
11 * %End-Header%
12 */
13
14#include <stdlib.h>
15#include <string.h>
16
17#include "blkidP.h"
18
19blkid_dev blkid_new_dev(void)
20{
21 blkid_dev dev;
22
23 if (!(dev = (blkid_dev) calloc(1, sizeof(struct blkid_struct_dev))))
24 return NULL;
25
26 INIT_LIST_HEAD(&dev->bid_devs);
27 INIT_LIST_HEAD(&dev->bid_tags);
28
29 return dev;
30}
31
32void blkid_free_dev(blkid_dev dev)
33{
34 if (!dev)
35 return;
36
37 DBG(DEBUG_DEV,
38 printf(" freeing dev %s (%s)\n", dev->bid_name, dev->bid_type));
39 DBG(DEBUG_DEV, blkid_debug_dump_dev(dev));
40
41 list_del(&dev->bid_devs);
42 while (!list_empty(&dev->bid_tags)) {
43 blkid_tag tag = list_entry(dev->bid_tags.next,
44 struct blkid_struct_tag,
45 bit_tags);
46 blkid_free_tag(tag);
47 }
48 if (dev->bid_name)
49 free(dev->bid_name);
50 free(dev);
51}
52
53/*
54 * Given a blkid device, return its name
55 */
56const char *blkid_dev_devname(blkid_dev dev)
57{
58 return dev->bid_name;
59}
60
61#ifdef CONFIG_BLKID_DEBUG
62void blkid_debug_dump_dev(blkid_dev dev)
63{
64 struct list_head *p;
65
66 if (!dev) {
67 printf(" dev: NULL\n");
68 return;
69 }
70
71 printf(" dev: name = %s\n", dev->bid_name);
72 printf(" dev: DEVNO=\"0x%0llx\"\n", dev->bid_devno);
73 printf(" dev: TIME=\"%lu\"\n", dev->bid_time);
74 printf(" dev: PRI=\"%d\"\n", dev->bid_pri);
75 printf(" dev: flags = 0x%08X\n", dev->bid_flags);
76
77 list_for_each(p, &dev->bid_tags) {
78 blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
79 if (tag)
80 printf(" tag: %s=\"%s\"\n", tag->bit_name,
81 tag->bit_val);
82 else
83 printf(" tag: NULL\n");
84 }
85 puts("");
86}
87#endif
88
89/*
90 * dev iteration routines for the public libblkid interface.
91 *
92 * These routines do not expose the list.h implementation, which are a
93 * contamination of the namespace, and which force us to reveal far, far
94 * too much of our internal implemenation. I'm not convinced I want
95 * to keep list.h in the long term, anyway. It's fine for kernel
96 * programming, but performance is not the #1 priority for this
97 * library, and I really don't like the tradeoff of type-safety for
98 * performance for this application. [tytso:20030125.2007EST]
99 */
100
101/*
102 * This series of functions iterate over all devices in a blkid cache
103 */
104#define DEV_ITERATE_MAGIC 0x01a5284c
105
106struct blkid_struct_dev_iterate {
107 int magic;
108 blkid_cache cache;
109 struct list_head *p;
110};
111
112blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
113{
114 blkid_dev_iterate iter;
115
116 iter = xmalloc(sizeof(struct blkid_struct_dev_iterate));
117 iter->magic = DEV_ITERATE_MAGIC;
118 iter->cache = cache;
119 iter->p = cache->bic_devs.next;
120 return iter;
121}
122
123/*
124 * Return 0 on success, -1 on error
125 */
126extern int blkid_dev_next(blkid_dev_iterate iter,
127 blkid_dev *dev)
128{
129 *dev = 0;
130 if (!iter || iter->magic != DEV_ITERATE_MAGIC ||
131 iter->p == &iter->cache->bic_devs)
132 return -1;
133 *dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs);
134 iter->p = iter->p->next;
135 return 0;
136}
137
138void blkid_dev_iterate_end(blkid_dev_iterate iter)
139{
140 if (!iter || iter->magic != DEV_ITERATE_MAGIC)
141 return;
142 iter->magic = 0;
143 free(iter);
144}
145
146#ifdef TEST_PROGRAM
147#ifdef HAVE_GETOPT_H
148#include <getopt.h>
149#else
150extern char *optarg;
151extern int optind;
152#endif
153
154void usage(char *prog)
155{
156 fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog);
157 fprintf(stderr, "\tList all devices and exit\n", prog);
158 exit(1);
159}
160
161int main(int argc, char **argv)
162{
163 blkid_dev_iterate iter;
164 blkid_cache cache = NULL;
165 blkid_dev dev;
166 int c, ret;
167 char *tmp;
168 char *file = NULL;
169 char *search_type = NULL;
170 char *search_value = NULL;
171
172 while ((c = getopt (argc, argv, "m:f:")) != EOF)
173 switch (c) {
174 case 'f':
175 file = optarg;
176 break;
177 case 'm':
178 blkid_debug_mask = strtoul (optarg, &tmp, 0);
179 if (*tmp) {
180 fprintf(stderr, "Invalid debug mask: %d\n",
181 optarg);
182 exit(1);
183 }
184 break;
185 case '?':
186 usage(argv[0]);
187 }
188 if (argc >= optind+2) {
189 search_type = argv[optind];
190 search_value = argv[optind+1];
191 optind += 2;
192 }
193 if (argc != optind)
194 usage(argv[0]);
195
196 if ((ret = blkid_get_cache(&cache, file)) != 0) {
197 fprintf(stderr, "%s: error creating cache (%d)\n",
198 argv[0], ret);
199 exit(1);
200 }
201
202 iter = blkid_dev_iterate_begin(cache);
203 if (search_type)
204 blkid_dev_set_search(iter, search_type, search_value);
205 while (blkid_dev_next(iter, &dev) == 0) {
206 printf("Device: %s\n", blkid_dev_devname(dev));
207 }
208 blkid_dev_iterate_end(iter);
209
210
211 blkid_put_cache(cache);
212 return 0;
213}
214#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/devname.c b/e2fsprogs/old_e2fsprogs/blkid/devname.c
new file mode 100644
index 000000000..3d11734d5
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/devname.c
@@ -0,0 +1,368 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * devname.c - get a dev by its device inode name
4 *
5 * Copyright (C) Andries Brouwer
6 * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o
7 * Copyright (C) 2001 Andreas Dilger
8 *
9 * %Begin-Header%
10 * This file may be redistributed under the terms of the
11 * GNU Lesser General Public License.
12 * %End-Header%
13 */
14
15#include <stdio.h>
16#include <string.h>
17#ifdef HAVE_UNISTD_H
18#include <unistd.h>
19#endif
20#include <stdlib.h>
21#include <string.h>
22#include <ctype.h>
23#ifdef HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26#include <sys/stat.h>
27#ifdef HAVE_ERRNO_H
28#include <errno.h>
29#endif
30#ifdef HAVE_SYS_MKDEV_H
31#include <sys/mkdev.h>
32#endif
33#include <time.h>
34
35#include "blkidP.h"
36
37/*
38 * Find a dev struct in the cache by device name, if available.
39 *
40 * If there is no entry with the specified device name, and the create
41 * flag is set, then create an empty device entry.
42 */
43blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags)
44{
45 blkid_dev dev = NULL, tmp;
46 struct list_head *p;
47
48 if (!cache || !devname)
49 return NULL;
50
51 list_for_each(p, &cache->bic_devs) {
52 tmp = list_entry(p, struct blkid_struct_dev, bid_devs);
53 if (strcmp(tmp->bid_name, devname))
54 continue;
55
56 DBG(DEBUG_DEVNAME,
57 printf("found devname %s in cache\n", tmp->bid_name));
58 dev = tmp;
59 break;
60 }
61
62 if (!dev && (flags & BLKID_DEV_CREATE)) {
63 dev = blkid_new_dev();
64 if (!dev)
65 return NULL;
66 dev->bid_name = blkid_strdup(devname);
67 dev->bid_cache = cache;
68 list_add_tail(&dev->bid_devs, &cache->bic_devs);
69 cache->bic_flags |= BLKID_BIC_FL_CHANGED;
70 }
71
72 if (flags & BLKID_DEV_VERIFY)
73 dev = blkid_verify(cache, dev);
74 return dev;
75}
76
77/*
78 * Probe a single block device to add to the device cache.
79 */
80static void probe_one(blkid_cache cache, const char *ptname,
81 dev_t devno, int pri)
82{
83 blkid_dev dev = NULL;
84 struct list_head *p;
85 const char **dir;
86 char *devname = NULL;
87
88 /* See if we already have this device number in the cache. */
89 list_for_each(p, &cache->bic_devs) {
90 blkid_dev tmp = list_entry(p, struct blkid_struct_dev,
91 bid_devs);
92 if (tmp->bid_devno == devno) {
93 dev = blkid_verify(cache, tmp);
94 break;
95 }
96 }
97 if (dev && dev->bid_devno == devno)
98 goto set_pri;
99
100 /*
101 * Take a quick look at /dev/ptname for the device number. We check
102 * all of the likely device directories. If we don't find it, or if
103 * the stat information doesn't check out, use blkid_devno_to_devname()
104 * to find it via an exhaustive search for the device major/minor.
105 */
106 for (dir = blkid_devdirs; *dir; dir++) {
107 struct stat st;
108 char device[256];
109
110 sprintf(device, "%s/%s", *dir, ptname);
111 if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) &&
112 dev->bid_devno == devno)
113 goto set_pri;
114
115 if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) &&
116 st.st_rdev == devno) {
117 devname = blkid_strdup(device);
118 break;
119 }
120 }
121 if (!devname) {
122 devname = blkid_devno_to_devname(devno);
123 if (!devname)
124 return;
125 }
126 dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);
127 free(devname);
128
129set_pri:
130 if (!pri && !strncmp(ptname, "md", 2))
131 pri = BLKID_PRI_MD;
132 if (dev)
133 dev->bid_pri = pri;
134 return;
135}
136
137#define PROC_PARTITIONS "/proc/partitions"
138#define VG_DIR "/proc/lvm/VGs"
139
140/*
141 * This function initializes the UUID cache with devices from the LVM
142 * proc hierarchy. We currently depend on the names of the LVM
143 * hierarchy giving us the device structure in /dev. (XXX is this a
144 * safe thing to do?)
145 */
146#ifdef VG_DIR
147#include <dirent.h>
148static dev_t lvm_get_devno(const char *lvm_device)
149{
150 FILE *lvf;
151 char buf[1024];
152 int ma, mi;
153 dev_t ret = 0;
154
155 DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device));
156 if ((lvf = fopen(lvm_device, "r")) == NULL) {
157 DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno,
158 strerror(errno)));
159 return 0;
160 }
161
162 while (fgets(buf, sizeof(buf), lvf)) {
163 if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) {
164 ret = makedev(ma, mi);
165 break;
166 }
167 }
168 fclose(lvf);
169
170 return ret;
171}
172
173static void lvm_probe_all(blkid_cache cache)
174{
175 DIR *vg_list;
176 struct dirent *vg_iter;
177 int vg_len = strlen(VG_DIR);
178 dev_t dev;
179
180 if ((vg_list = opendir(VG_DIR)) == NULL)
181 return;
182
183 DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR));
184
185 while ((vg_iter = readdir(vg_list)) != NULL) {
186 DIR *lv_list;
187 char *vdirname;
188 char *vg_name;
189 struct dirent *lv_iter;
190
191 vg_name = vg_iter->d_name;
192 if (LONE_CHAR(vg_name, '.') || !strcmp(vg_name, ".."))
193 continue;
194 vdirname = xmalloc(vg_len + strlen(vg_name) + 8);
195 sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name);
196
197 lv_list = opendir(vdirname);
198 free(vdirname);
199 if (lv_list == NULL)
200 continue;
201
202 while ((lv_iter = readdir(lv_list)) != NULL) {
203 char *lv_name, *lvm_device;
204
205 lv_name = lv_iter->d_name;
206 if (LONE_CHAR(lv_name, '.') || !strcmp(lv_name, ".."))
207 continue;
208
209 lvm_device = xmalloc(vg_len + strlen(vg_name) +
210 strlen(lv_name) + 8);
211 sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name,
212 lv_name);
213 dev = lvm_get_devno(lvm_device);
214 sprintf(lvm_device, "%s/%s", vg_name, lv_name);
215 DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n",
216 lvm_device,
217 (unsigned int) dev));
218 probe_one(cache, lvm_device, dev, BLKID_PRI_LVM);
219 free(lvm_device);
220 }
221 closedir(lv_list);
222 }
223 closedir(vg_list);
224}
225#endif
226
227#define PROC_EVMS_VOLUMES "/proc/evms/volumes"
228
229static int
230evms_probe_all(blkid_cache cache)
231{
232 char line[100];
233 int ma, mi, sz, num = 0;
234 FILE *procpt;
235 char device[110];
236
237 procpt = fopen(PROC_EVMS_VOLUMES, "r");
238 if (!procpt)
239 return 0;
240 while (fgets(line, sizeof(line), procpt)) {
241 if (sscanf (line, " %d %d %d %*s %*s %[^\n ]",
242 &ma, &mi, &sz, device) != 4)
243 continue;
244
245 DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n",
246 device, ma, mi));
247
248 probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS);
249 num++;
250 }
251 fclose(procpt);
252 return num;
253}
254
255/*
256 * Read the device data for all available block devices in the system.
257 */
258int blkid_probe_all(blkid_cache cache)
259{
260 FILE *proc;
261 char line[1024];
262 char ptname0[128], ptname1[128], *ptname = 0;
263 char *ptnames[2];
264 dev_t devs[2];
265 int ma, mi;
266 unsigned long long sz;
267 int lens[2] = { 0, 0 };
268 int which = 0, last = 0;
269
270 ptnames[0] = ptname0;
271 ptnames[1] = ptname1;
272
273 if (!cache)
274 return -BLKID_ERR_PARAM;
275
276 if (cache->bic_flags & BLKID_BIC_FL_PROBED &&
277 time(0) - cache->bic_time < BLKID_PROBE_INTERVAL)
278 return 0;
279
280 blkid_read_cache(cache);
281 evms_probe_all(cache);
282#ifdef VG_DIR
283 lvm_probe_all(cache);
284#endif
285
286 proc = fopen(PROC_PARTITIONS, "r");
287 if (!proc)
288 return -BLKID_ERR_PROC;
289
290 while (fgets(line, sizeof(line), proc)) {
291 last = which;
292 which ^= 1;
293 ptname = ptnames[which];
294
295 if (sscanf(line, " %d %d %llu %128[^\n ]",
296 &ma, &mi, &sz, ptname) != 4)
297 continue;
298 devs[which] = makedev(ma, mi);
299
300 DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname));
301
302 /* Skip whole disk devs unless they have no partitions
303 * If we don't have a partition on this dev, also
304 * check previous dev to see if it didn't have a partn.
305 * heuristic: partition name ends in a digit.
306 *
307 * Skip extended partitions.
308 * heuristic: size is 1
309 *
310 * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs
311 */
312
313 lens[which] = strlen(ptname);
314 if (isdigit(ptname[lens[which] - 1])) {
315 DBG(DEBUG_DEVNAME,
316 printf("partition dev %s, devno 0x%04X\n",
317 ptname, (unsigned int) devs[which]));
318
319 if (sz > 1)
320 probe_one(cache, ptname, devs[which], 0);
321 lens[which] = 0;
322 lens[last] = 0;
323 } else if (lens[last] && strncmp(ptnames[last], ptname,
324 lens[last])) {
325 DBG(DEBUG_DEVNAME,
326 printf("whole dev %s, devno 0x%04X\n",
327 ptnames[last], (unsigned int) devs[last]));
328 probe_one(cache, ptnames[last], devs[last], 0);
329 lens[last] = 0;
330 }
331 }
332
333 /* Handle the last device if it wasn't partitioned */
334 if (lens[which])
335 probe_one(cache, ptname, devs[which], 0);
336
337 fclose(proc);
338
339 cache->bic_time = time(0);
340 cache->bic_flags |= BLKID_BIC_FL_PROBED;
341 blkid_flush_cache(cache);
342 return 0;
343}
344
345#ifdef TEST_PROGRAM
346int main(int argc, char **argv)
347{
348 blkid_cache cache = NULL;
349 int ret;
350
351 blkid_debug_mask = DEBUG_ALL;
352 if (argc != 1) {
353 fprintf(stderr, "Usage: %s\n"
354 "Probe all devices and exit\n", argv[0]);
355 exit(1);
356 }
357 if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
358 fprintf(stderr, "%s: error creating cache (%d)\n",
359 argv[0], ret);
360 exit(1);
361 }
362 if (blkid_probe_all(cache) < 0)
363 printf("%s: error probing devices\n", argv[0]);
364
365 blkid_put_cache(cache);
366 return 0;
367}
368#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/devno.c b/e2fsprogs/old_e2fsprogs/blkid/devno.c
new file mode 100644
index 000000000..13e7f1a87
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/devno.c
@@ -0,0 +1,223 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * devno.c - find a particular device by its device number (major/minor)
4 *
5 * Copyright (C) 2000, 2001, 2003 Theodore Ts'o
6 * Copyright (C) 2001 Andreas Dilger
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the
10 * GNU Lesser General Public License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#ifdef HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#include <stdlib.h>
20#include <string.h>
21#ifdef HAVE_SYS_TYPES_H
22#include <sys/types.h>
23#endif
24#include <sys/stat.h>
25#include <dirent.h>
26#ifdef HAVE_ERRNO_H
27#include <errno.h>
28#endif
29#ifdef HAVE_SYS_MKDEV_H
30#include <sys/mkdev.h>
31#endif
32
33#include "blkidP.h"
34
35struct dir_list {
36 char *name;
37 struct dir_list *next;
38};
39
40char *blkid_strndup(const char *s, int length)
41{
42 char *ret;
43
44 if (!s)
45 return NULL;
46
47 if (!length)
48 length = strlen(s);
49
50 ret = xmalloc(length + 1);
51 strncpy(ret, s, length);
52 ret[length] = '\0';
53 return ret;
54}
55
56char *blkid_strdup(const char *s)
57{
58 return blkid_strndup(s, 0);
59}
60
61/*
62 * This function adds an entry to the directory list
63 */
64static void add_to_dirlist(const char *name, struct dir_list **list)
65{
66 struct dir_list *dp;
67
68 dp = xmalloc(sizeof(struct dir_list));
69 dp->name = blkid_strdup(name);
70 dp->next = *list;
71 *list = dp;
72}
73
74/*
75 * This function frees a directory list
76 */
77static void free_dirlist(struct dir_list **list)
78{
79 struct dir_list *dp, *next;
80
81 for (dp = *list; dp; dp = next) {
82 next = dp->next;
83 free(dp->name);
84 free(dp);
85 }
86 *list = NULL;
87}
88
89static void scan_dir(char *dir_name, dev_t devno, struct dir_list **list,
90 char **devname)
91{
92 DIR *dir;
93 struct dirent *dp;
94 char path[1024];
95 int dirlen;
96 struct stat st;
97
98 if ((dir = opendir(dir_name)) == NULL)
99 return;
100 dirlen = strlen(dir_name) + 2;
101 while ((dp = readdir(dir)) != 0) {
102 if (dirlen + strlen(dp->d_name) >= sizeof(path))
103 continue;
104
105 if (dp->d_name[0] == '.' &&
106 ((dp->d_name[1] == 0) ||
107 ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
108 continue;
109
110 sprintf(path, "%s/%s", dir_name, dp->d_name);
111 if (stat(path, &st) < 0)
112 continue;
113
114 if (S_ISDIR(st.st_mode))
115 add_to_dirlist(path, list);
116 else if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
117 *devname = blkid_strdup(path);
118 DBG(DEBUG_DEVNO,
119 printf("found 0x%llx at %s (%p)\n", devno,
120 path, *devname));
121 break;
122 }
123 }
124 closedir(dir);
125 return;
126}
127
128/* Directories where we will try to search for device numbers */
129const char *blkid_devdirs[] = { "/devices", "/devfs", "/dev", NULL };
130
131/*
132 * This function finds the pathname to a block device with a given
133 * device number. It returns a pointer to allocated memory to the
134 * pathname on success, and NULL on failure.
135 */
136char *blkid_devno_to_devname(dev_t devno)
137{
138 struct dir_list *list = NULL, *new_list = NULL;
139 char *devname = NULL;
140 const char **dir;
141
142 /*
143 * Add the starting directories to search in reverse order of
144 * importance, since we are using a stack...
145 */
146 for (dir = blkid_devdirs; *dir; dir++)
147 add_to_dirlist(*dir, &list);
148
149 while (list) {
150 struct dir_list *current = list;
151
152 list = list->next;
153 DBG(DEBUG_DEVNO, printf("directory %s\n", current->name));
154 scan_dir(current->name, devno, &new_list, &devname);
155 free(current->name);
156 free(current);
157 if (devname)
158 break;
159 /*
160 * If we're done checking at this level, descend to
161 * the next level of subdirectories. (breadth-first)
162 */
163 if (list == NULL) {
164 list = new_list;
165 new_list = NULL;
166 }
167 }
168 free_dirlist(&list);
169 free_dirlist(&new_list);
170
171 if (!devname) {
172 DBG(DEBUG_DEVNO,
173 printf("blkid: cannot find devno 0x%04lx\n",
174 (unsigned long) devno));
175 } else {
176 DBG(DEBUG_DEVNO,
177 printf("found devno 0x%04llx as %s\n", devno, devname));
178 }
179
180
181 return devname;
182}
183
184#ifdef TEST_PROGRAM
185int main(int argc, char** argv)
186{
187 char *devname, *tmp;
188 int major, minor;
189 dev_t devno;
190 const char *errmsg = "Cannot parse %s: %s\n";
191
192 blkid_debug_mask = DEBUG_ALL;
193 if ((argc != 2) && (argc != 3)) {
194 fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n"
195 "Resolve a device number to a device name\n",
196 argv[0], argv[0]);
197 exit(1);
198 }
199 if (argc == 2) {
200 devno = strtoul(argv[1], &tmp, 0);
201 if (*tmp) {
202 fprintf(stderr, errmsg, "device number", argv[1]);
203 exit(1);
204 }
205 } else {
206 major = strtoul(argv[1], &tmp, 0);
207 if (*tmp) {
208 fprintf(stderr, errmsg, "major number", argv[1]);
209 exit(1);
210 }
211 minor = strtoul(argv[2], &tmp, 0);
212 if (*tmp) {
213 fprintf(stderr, errmsg, "minor number", argv[2]);
214 exit(1);
215 }
216 devno = makedev(major, minor);
217 }
218 printf("Looking for device 0x%04Lx\n", devno);
219 devname = blkid_devno_to_devname(devno);
220 free(devname);
221 return 0;
222}
223#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/list.c b/e2fsprogs/old_e2fsprogs/blkid/list.c
new file mode 100644
index 000000000..04d61a19b
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/list.c
@@ -0,0 +1,110 @@
1/* vi: set sw=4 ts=4: */
2
3#include "list.h"
4
5/*
6 * Insert a new entry between two known consecutive entries.
7 *
8 * This is only for internal list manipulation where we know
9 * the prev/next entries already!
10 */
11void __list_add(struct list_head * add,
12 struct list_head * prev,
13 struct list_head * next)
14{
15 next->prev = add;
16 add->next = next;
17 add->prev = prev;
18 prev->next = add;
19}
20
21/*
22 * list_add - add a new entry
23 * @add: new entry to be added
24 * @head: list head to add it after
25 *
26 * Insert a new entry after the specified head.
27 * This is good for implementing stacks.
28 */
29void list_add(struct list_head *add, struct list_head *head)
30{
31 __list_add(add, head, head->next);
32}
33
34/*
35 * list_add_tail - add a new entry
36 * @add: new entry to be added
37 * @head: list head to add it before
38 *
39 * Insert a new entry before the specified head.
40 * This is useful for implementing queues.
41 */
42void list_add_tail(struct list_head *add, struct list_head *head)
43{
44 __list_add(add, head->prev, head);
45}
46
47/*
48 * Delete a list entry by making the prev/next entries
49 * point to each other.
50 *
51 * This is only for internal list manipulation where we know
52 * the prev/next entries already!
53 */
54void __list_del(struct list_head * prev, struct list_head * next)
55{
56 next->prev = prev;
57 prev->next = next;
58}
59
60/*
61 * list_del - deletes entry from list.
62 * @entry: the element to delete from the list.
63 *
64 * list_empty() on @entry does not return true after this, @entry is
65 * in an undefined state.
66 */
67void list_del(struct list_head *entry)
68{
69 __list_del(entry->prev, entry->next);
70}
71
72/*
73 * list_del_init - deletes entry from list and reinitialize it.
74 * @entry: the element to delete from the list.
75 */
76void list_del_init(struct list_head *entry)
77{
78 __list_del(entry->prev, entry->next);
79 INIT_LIST_HEAD(entry);
80}
81
82/*
83 * list_empty - tests whether a list is empty
84 * @head: the list to test.
85 */
86int list_empty(struct list_head *head)
87{
88 return head->next == head;
89}
90
91/*
92 * list_splice - join two lists
93 * @list: the new list to add.
94 * @head: the place to add it in the first list.
95 */
96void list_splice(struct list_head *list, struct list_head *head)
97{
98 struct list_head *first = list->next;
99
100 if (first != list) {
101 struct list_head *last = list->prev;
102 struct list_head *at = head->next;
103
104 first->prev = head;
105 head->next = first;
106
107 last->next = at;
108 at->prev = last;
109 }
110}
diff --git a/e2fsprogs/old_e2fsprogs/blkid/list.h b/e2fsprogs/old_e2fsprogs/blkid/list.h
new file mode 100644
index 000000000..8b06d853b
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/list.h
@@ -0,0 +1,73 @@
1/* vi: set sw=4 ts=4: */
2#if !defined(_BLKID_LIST_H) && !defined(LIST_HEAD)
3#define _BLKID_LIST_H
4
5#ifdef __cplusplus
6extern "C" {
7#endif
8
9/*
10 * Simple doubly linked list implementation.
11 *
12 * Some of the internal functions ("__xxx") are useful when
13 * manipulating whole lists rather than single entries, as
14 * sometimes we already know the next/prev entries and we can
15 * generate better code by using them directly rather than
16 * using the generic single-entry routines.
17 */
18
19struct list_head {
20 struct list_head *next, *prev;
21};
22
23#define LIST_HEAD_INIT(name) { &(name), &(name) }
24
25#define LIST_HEAD(name) \
26 struct list_head name = LIST_HEAD_INIT(name)
27
28#define INIT_LIST_HEAD(ptr) do { \
29 (ptr)->next = (ptr); (ptr)->prev = (ptr); \
30} while (0)
31
32void __list_add(struct list_head * add, struct list_head * prev, struct list_head * next);
33void list_add(struct list_head *add, struct list_head *head);
34void list_add_tail(struct list_head *add, struct list_head *head);
35void __list_del(struct list_head * prev, struct list_head * next);
36void list_del(struct list_head *entry);
37void list_del_init(struct list_head *entry);
38int list_empty(struct list_head *head);
39void list_splice(struct list_head *list, struct list_head *head);
40
41/**
42 * list_entry - get the struct for this entry
43 * @ptr: the &struct list_head pointer.
44 * @type: the type of the struct this is embedded in.
45 * @member: the name of the list_struct within the struct.
46 */
47#define list_entry(ptr, type, member) \
48 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
49
50/**
51 * list_for_each - iterate over elements in a list
52 * @pos: the &struct list_head to use as a loop counter.
53 * @head: the head for your list.
54 */
55#define list_for_each(pos, head) \
56 for (pos = (head)->next; pos != (head); pos = pos->next)
57
58/**
59 * list_for_each_safe - iterate over elements in a list, but don't dereference
60 * pos after the body is done (in case it is freed)
61 * @pos: the &struct list_head to use as a loop counter.
62 * @pnext: the &struct list_head to use as a pointer to the next item.
63 * @head: the head for your list (not included in iteration).
64 */
65#define list_for_each_safe(pos, pnext, head) \
66 for (pos = (head)->next, pnext = pos->next; pos != (head); \
67 pos = pnext, pnext = pos->next)
68
69#ifdef __cplusplus
70}
71#endif
72
73#endif /* _BLKID_LIST_H */
diff --git a/e2fsprogs/old_e2fsprogs/blkid/probe.c b/e2fsprogs/old_e2fsprogs/blkid/probe.c
new file mode 100644
index 000000000..8c6e2aa33
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/probe.c
@@ -0,0 +1,721 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * probe.c - identify a block device by its contents, and return a dev
4 * struct with the details
5 *
6 * Copyright (C) 1999 by Andries Brouwer
7 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
8 * Copyright (C) 2001 by Andreas Dilger
9 *
10 * %Begin-Header%
11 * This file may be redistributed under the terms of the
12 * GNU Lesser General Public License.
13 * %End-Header%
14 */
15
16#include <stdio.h>
17#include <string.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <fcntl.h>
21#include <sys/types.h>
22#ifdef HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#ifdef HAVE_SYS_MKDEV_H
26#include <sys/mkdev.h>
27#endif
28#ifdef HAVE_ERRNO_H
29#include <errno.h>
30#endif
31#include "blkidP.h"
32#include "../uuid/uuid.h"
33#include "probe.h"
34
35/*
36 * This is a special case code to check for an MDRAID device. We do
37 * this special since it requires checking for a superblock at the end
38 * of the device.
39 */
40static int check_mdraid(int fd, unsigned char *ret_uuid)
41{
42 struct mdp_superblock_s *md;
43 blkid_loff_t offset;
44 char buf[4096];
45
46 if (fd < 0)
47 return -BLKID_ERR_PARAM;
48
49 offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536;
50
51 if (blkid_llseek(fd, offset, 0) < 0 ||
52 read(fd, buf, 4096) != 4096)
53 return -BLKID_ERR_IO;
54
55 /* Check for magic number */
56 if (memcmp("\251+N\374", buf, 4))
57 return -BLKID_ERR_PARAM;
58
59 if (!ret_uuid)
60 return 0;
61 *ret_uuid = 0;
62
63 /* The MD UUID is not contiguous in the superblock, make it so */
64 md = (struct mdp_superblock_s *)buf;
65 if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) {
66 memcpy(ret_uuid, &md->set_uuid0, 4);
67 memcpy(ret_uuid, &md->set_uuid1, 12);
68 }
69 return 0;
70}
71
72static void set_uuid(blkid_dev dev, uuid_t uuid)
73{
74 char str[37];
75
76 if (!uuid_is_null(uuid)) {
77 uuid_unparse(uuid, str);
78 blkid_set_tag(dev, "UUID", str, sizeof(str));
79 }
80}
81
82static void get_ext2_info(blkid_dev dev, unsigned char *buf)
83{
84 struct ext2_super_block *es = (struct ext2_super_block *) buf;
85 const char *label = 0;
86
87 DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n",
88 blkid_le32(es->s_feature_compat),
89 blkid_le32(es->s_feature_incompat),
90 blkid_le32(es->s_feature_ro_compat)));
91
92 if (strlen(es->s_volume_name))
93 label = es->s_volume_name;
94 blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name));
95
96 set_uuid(dev, es->s_uuid);
97}
98
99static int probe_ext3(int fd __BLKID_ATTR((unused)),
100 blkid_cache cache __BLKID_ATTR((unused)),
101 blkid_dev dev,
102 const struct blkid_magic *id __BLKID_ATTR((unused)),
103 unsigned char *buf)
104{
105 struct ext2_super_block *es;
106
107 es = (struct ext2_super_block *)buf;
108
109 /* Distinguish between jbd and ext2/3 fs */
110 if (blkid_le32(es->s_feature_incompat) &
111 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
112 return -BLKID_ERR_PARAM;
113
114 /* Distinguish between ext3 and ext2 */
115 if (!(blkid_le32(es->s_feature_compat) &
116 EXT3_FEATURE_COMPAT_HAS_JOURNAL))
117 return -BLKID_ERR_PARAM;
118
119 get_ext2_info(dev, buf);
120
121 blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2"));
122
123 return 0;
124}
125
126static int probe_ext2(int fd __BLKID_ATTR((unused)),
127 blkid_cache cache __BLKID_ATTR((unused)),
128 blkid_dev dev,
129 const struct blkid_magic *id __BLKID_ATTR((unused)),
130 unsigned char *buf)
131{
132 struct ext2_super_block *es;
133
134 es = (struct ext2_super_block *)buf;
135
136 /* Distinguish between jbd and ext2/3 fs */
137 if (blkid_le32(es->s_feature_incompat) &
138 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
139 return -BLKID_ERR_PARAM;
140
141 get_ext2_info(dev, buf);
142
143 return 0;
144}
145
146static int probe_jbd(int fd __BLKID_ATTR((unused)),
147 blkid_cache cache __BLKID_ATTR((unused)),
148 blkid_dev dev,
149 const struct blkid_magic *id __BLKID_ATTR((unused)),
150 unsigned char *buf)
151{
152 struct ext2_super_block *es = (struct ext2_super_block *) buf;
153
154 if (!(blkid_le32(es->s_feature_incompat) &
155 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
156 return -BLKID_ERR_PARAM;
157
158 get_ext2_info(dev, buf);
159
160 return 0;
161}
162
163static int probe_vfat(int fd __BLKID_ATTR((unused)),
164 blkid_cache cache __BLKID_ATTR((unused)),
165 blkid_dev dev,
166 const struct blkid_magic *id __BLKID_ATTR((unused)),
167 unsigned char *buf)
168{
169 struct vfat_super_block *vs;
170 char serno[10];
171 const char *label = 0;
172 int label_len = 0;
173
174 vs = (struct vfat_super_block *)buf;
175
176 if (strncmp(vs->vs_label, "NO NAME", 7)) {
177 char *end = vs->vs_label + sizeof(vs->vs_label) - 1;
178
179 while (*end == ' ' && end >= vs->vs_label)
180 --end;
181 if (end >= vs->vs_label) {
182 label = vs->vs_label;
183 label_len = end - vs->vs_label + 1;
184 }
185 }
186
187 /* We can't just print them as %04X, because they are unaligned */
188 sprintf(serno, "%02X%02X-%02X%02X", vs->vs_serno[3], vs->vs_serno[2],
189 vs->vs_serno[1], vs->vs_serno[0]);
190 blkid_set_tag(dev, "LABEL", label, label_len);
191 blkid_set_tag(dev, "UUID", serno, sizeof(serno));
192
193 return 0;
194}
195
196static int probe_msdos(int fd __BLKID_ATTR((unused)),
197 blkid_cache cache __BLKID_ATTR((unused)),
198 blkid_dev dev,
199 const struct blkid_magic *id __BLKID_ATTR((unused)),
200 unsigned char *buf)
201{
202 struct msdos_super_block *ms = (struct msdos_super_block *) buf;
203 char serno[10];
204 const char *label = 0;
205 int label_len = 0;
206
207 if (strncmp(ms->ms_label, "NO NAME", 7)) {
208 char *end = ms->ms_label + sizeof(ms->ms_label) - 1;
209
210 while (*end == ' ' && end >= ms->ms_label)
211 --end;
212 if (end >= ms->ms_label) {
213 label = ms->ms_label;
214 label_len = end - ms->ms_label + 1;
215 }
216 }
217
218 /* We can't just print them as %04X, because they are unaligned */
219 sprintf(serno, "%02X%02X-%02X%02X", ms->ms_serno[3], ms->ms_serno[2],
220 ms->ms_serno[1], ms->ms_serno[0]);
221 blkid_set_tag(dev, "UUID", serno, 0);
222 blkid_set_tag(dev, "LABEL", label, label_len);
223 blkid_set_tag(dev, "SEC_TYPE", "msdos", sizeof("msdos"));
224
225 return 0;
226}
227
228static int probe_xfs(int fd __BLKID_ATTR((unused)),
229 blkid_cache cache __BLKID_ATTR((unused)),
230 blkid_dev dev,
231 const struct blkid_magic *id __BLKID_ATTR((unused)),
232 unsigned char *buf)
233{
234 struct xfs_super_block *xs;
235 const char *label = 0;
236
237 xs = (struct xfs_super_block *)buf;
238
239 if (strlen(xs->xs_fname))
240 label = xs->xs_fname;
241 blkid_set_tag(dev, "LABEL", label, sizeof(xs->xs_fname));
242 set_uuid(dev, xs->xs_uuid);
243 return 0;
244}
245
246static int probe_reiserfs(int fd __BLKID_ATTR((unused)),
247 blkid_cache cache __BLKID_ATTR((unused)),
248 blkid_dev dev,
249 const struct blkid_magic *id, unsigned char *buf)
250{
251 struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf;
252 unsigned int blocksize;
253 const char *label = 0;
254
255 blocksize = blkid_le16(rs->rs_blocksize);
256
257 /* If the superblock is inside the journal, we have the wrong one */
258 if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block))
259 return -BLKID_ERR_BIG;
260
261 /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
262 if (!strcmp(id->bim_magic, "ReIsEr2Fs") ||
263 !strcmp(id->bim_magic, "ReIsEr3Fs")) {
264 if (strlen(rs->rs_label))
265 label = rs->rs_label;
266 set_uuid(dev, rs->rs_uuid);
267 }
268 blkid_set_tag(dev, "LABEL", label, sizeof(rs->rs_label));
269
270 return 0;
271}
272
273static int probe_jfs(int fd __BLKID_ATTR((unused)),
274 blkid_cache cache __BLKID_ATTR((unused)),
275 blkid_dev dev,
276 const struct blkid_magic *id __BLKID_ATTR((unused)),
277 unsigned char *buf)
278{
279 struct jfs_super_block *js;
280 const char *label = 0;
281
282 js = (struct jfs_super_block *)buf;
283
284 if (strlen((char *) js->js_label))
285 label = (char *) js->js_label;
286 blkid_set_tag(dev, "LABEL", label, sizeof(js->js_label));
287 set_uuid(dev, js->js_uuid);
288 return 0;
289}
290
291static int probe_romfs(int fd __BLKID_ATTR((unused)),
292 blkid_cache cache __BLKID_ATTR((unused)),
293 blkid_dev dev,
294 const struct blkid_magic *id __BLKID_ATTR((unused)),
295 unsigned char *buf)
296{
297 struct romfs_super_block *ros;
298 const char *label = 0;
299
300 ros = (struct romfs_super_block *)buf;
301
302 if (strlen((char *) ros->ros_volume))
303 label = (char *) ros->ros_volume;
304 blkid_set_tag(dev, "LABEL", label, 0);
305 return 0;
306}
307
308static int probe_cramfs(int fd __BLKID_ATTR((unused)),
309 blkid_cache cache __BLKID_ATTR((unused)),
310 blkid_dev dev,
311 const struct blkid_magic *id __BLKID_ATTR((unused)),
312 unsigned char *buf)
313{
314 struct cramfs_super_block *csb;
315 const char *label = 0;
316
317 csb = (struct cramfs_super_block *)buf;
318
319 if (strlen((char *) csb->name))
320 label = (char *) csb->name;
321 blkid_set_tag(dev, "LABEL", label, 0);
322 return 0;
323}
324
325static int probe_swap0(int fd __BLKID_ATTR((unused)),
326 blkid_cache cache __BLKID_ATTR((unused)),
327 blkid_dev dev,
328 const struct blkid_magic *id __BLKID_ATTR((unused)),
329 unsigned char *buf __BLKID_ATTR((unused)))
330{
331 blkid_set_tag(dev, "UUID", 0, 0);
332 blkid_set_tag(dev, "LABEL", 0, 0);
333 return 0;
334}
335
336static int probe_swap1(int fd,
337 blkid_cache cache __BLKID_ATTR((unused)),
338 blkid_dev dev,
339 const struct blkid_magic *id __BLKID_ATTR((unused)),
340 unsigned char *buf __BLKID_ATTR((unused)))
341{
342 struct swap_id_block *sws;
343
344 probe_swap0(fd, cache, dev, id, buf);
345 /*
346 * Version 1 swap headers are always located at offset of 1024
347 * bytes, although the swap signature itself is located at the
348 * end of the page (which may vary depending on hardware
349 * pagesize).
350 */
351 if (lseek(fd, 1024, SEEK_SET) < 0) return 1;
352 sws = xmalloc(1024);
353 if (read(fd, sws, 1024) != 1024) {
354 free(sws);
355 return 1;
356 }
357
358 /* arbitrary sanity check.. is there any garbage down there? */
359 if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0) {
360 if (sws->sws_volume[0])
361 blkid_set_tag(dev, "LABEL", (const char*)sws->sws_volume,
362 sizeof(sws->sws_volume));
363 if (sws->sws_uuid[0])
364 set_uuid(dev, sws->sws_uuid);
365 }
366 free(sws);
367
368 return 0;
369}
370
371static const char
372* const udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
373 "NSR03", "TEA01", 0 };
374
375static int probe_udf(int fd, blkid_cache cache __BLKID_ATTR((unused)),
376 blkid_dev dev __BLKID_ATTR((unused)),
377 const struct blkid_magic *id __BLKID_ATTR((unused)),
378 unsigned char *buf __BLKID_ATTR((unused)))
379{
380 int j, bs;
381 struct iso_volume_descriptor isosb;
382 const char * const * m;
383
384 /* determine the block size by scanning in 2K increments
385 (block sizes larger than 2K will be null padded) */
386 for (bs = 1; bs < 16; bs++) {
387 lseek(fd, bs*2048+32768, SEEK_SET);
388 if (read(fd, (char *)&isosb, sizeof(isosb)) != sizeof(isosb))
389 return 1;
390 if (isosb.id[0])
391 break;
392 }
393
394 /* Scan up to another 64 blocks looking for additional VSD's */
395 for (j = 1; j < 64; j++) {
396 if (j > 1) {
397 lseek(fd, j*bs*2048+32768, SEEK_SET);
398 if (read(fd, (char *)&isosb, sizeof(isosb))
399 != sizeof(isosb))
400 return 1;
401 }
402 /* If we find NSR0x then call it udf:
403 NSR01 for UDF 1.00
404 NSR02 for UDF 1.50
405 NSR03 for UDF 2.00 */
406 if (!strncmp(isosb.id, "NSR0", 4))
407 return 0;
408 for (m = udf_magic; *m; m++)
409 if (!strncmp(*m, isosb.id, 5))
410 break;
411 if (*m == 0)
412 return 1;
413 }
414 return 1;
415}
416
417static int probe_ocfs(int fd __BLKID_ATTR((unused)),
418 blkid_cache cache __BLKID_ATTR((unused)),
419 blkid_dev dev,
420 const struct blkid_magic *id __BLKID_ATTR((unused)),
421 unsigned char *buf)
422{
423 struct ocfs_volume_header ovh;
424 struct ocfs_volume_label ovl;
425 __u32 major;
426
427 memcpy(&ovh, buf, sizeof(ovh));
428 memcpy(&ovl, buf+512, sizeof(ovl));
429
430 major = ocfsmajor(ovh);
431 if (major == 1)
432 blkid_set_tag(dev,"SEC_TYPE","ocfs1",sizeof("ocfs1"));
433 else if (major >= 9)
434 blkid_set_tag(dev,"SEC_TYPE","ntocfs",sizeof("ntocfs"));
435
436 blkid_set_tag(dev, "LABEL", (const char*)ovl.label, ocfslabellen(ovl));
437 blkid_set_tag(dev, "MOUNT", (const char*)ovh.mount, ocfsmountlen(ovh));
438 set_uuid(dev, ovl.vol_id);
439 return 0;
440}
441
442static int probe_ocfs2(int fd __BLKID_ATTR((unused)),
443 blkid_cache cache __BLKID_ATTR((unused)),
444 blkid_dev dev,
445 const struct blkid_magic *id __BLKID_ATTR((unused)),
446 unsigned char *buf)
447{
448 struct ocfs2_super_block *osb;
449
450 osb = (struct ocfs2_super_block *)buf;
451
452 blkid_set_tag(dev, "LABEL", (const char*)osb->s_label, sizeof(osb->s_label));
453 set_uuid(dev, osb->s_uuid);
454 return 0;
455}
456
457static int probe_oracleasm(int fd __BLKID_ATTR((unused)),
458 blkid_cache cache __BLKID_ATTR((unused)),
459 blkid_dev dev,
460 const struct blkid_magic *id __BLKID_ATTR((unused)),
461 unsigned char *buf)
462{
463 struct oracle_asm_disk_label *dl;
464
465 dl = (struct oracle_asm_disk_label *)buf;
466
467 blkid_set_tag(dev, "LABEL", dl->dl_id, sizeof(dl->dl_id));
468 return 0;
469}
470
471/*
472 * BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined
473 * in the type_array table below + bim_kbalign.
474 *
475 * When probing for a lot of magics, we handle everything in 1kB buffers so
476 * that we don't have to worry about reading each combination of block sizes.
477 */
478#define BLKID_BLK_OFFS 64 /* currently reiserfs */
479
480/*
481 * Various filesystem magics that we can check for. Note that kboff and
482 * sboff are in kilobytes and bytes respectively. All magics are in
483 * byte strings so we don't worry about endian issues.
484 */
485static const struct blkid_magic type_array[] = {
486/* type kboff sboff len magic probe */
487 { "oracleasm", 0, 32, 8, "ORCLDISK", probe_oracleasm },
488 { "ntfs", 0, 3, 8, "NTFS ", 0 },
489 { "jbd", 1, 0x38, 2, "\123\357", probe_jbd },
490 { "ext3", 1, 0x38, 2, "\123\357", probe_ext3 },
491 { "ext2", 1, 0x38, 2, "\123\357", probe_ext2 },
492 { "reiserfs", 8, 0x34, 8, "ReIsErFs", probe_reiserfs },
493 { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", probe_reiserfs },
494 { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", probe_reiserfs },
495 { "reiserfs", 64, 0x34, 8, "ReIsErFs", probe_reiserfs },
496 { "reiserfs", 8, 20, 8, "ReIsErFs", probe_reiserfs },
497 { "vfat", 0, 0x52, 5, "MSWIN", probe_vfat },
498 { "vfat", 0, 0x52, 8, "FAT32 ", probe_vfat },
499 { "vfat", 0, 0x36, 5, "MSDOS", probe_msdos },
500 { "vfat", 0, 0x36, 8, "FAT16 ", probe_msdos },
501 { "vfat", 0, 0x36, 8, "FAT12 ", probe_msdos },
502 { "minix", 1, 0x10, 2, "\177\023", 0 },
503 { "minix", 1, 0x10, 2, "\217\023", 0 },
504 { "minix", 1, 0x10, 2, "\150\044", 0 },
505 { "minix", 1, 0x10, 2, "\170\044", 0 },
506 { "vxfs", 1, 0, 4, "\365\374\001\245", 0 },
507 { "xfs", 0, 0, 4, "XFSB", probe_xfs },
508 { "romfs", 0, 0, 8, "-rom1fs-", probe_romfs },
509 { "bfs", 0, 0, 4, "\316\372\173\033", 0 },
510 { "cramfs", 0, 0, 4, "E=\315\050", probe_cramfs },
511 { "qnx4", 0, 4, 6, "QNX4FS", 0 },
512 { "udf", 32, 1, 5, "BEA01", probe_udf },
513 { "udf", 32, 1, 5, "BOOT2", probe_udf },
514 { "udf", 32, 1, 5, "CD001", probe_udf },
515 { "udf", 32, 1, 5, "CDW02", probe_udf },
516 { "udf", 32, 1, 5, "NSR02", probe_udf },
517 { "udf", 32, 1, 5, "NSR03", probe_udf },
518 { "udf", 32, 1, 5, "TEA01", probe_udf },
519 { "iso9660", 32, 1, 5, "CD001", 0 },
520 { "iso9660", 32, 9, 5, "CDROM", 0 },
521 { "jfs", 32, 0, 4, "JFS1", probe_jfs },
522 { "hfs", 1, 0, 2, "BD", 0 },
523 { "ufs", 8, 0x55c, 4, "T\031\001\000", 0 },
524 { "hpfs", 8, 0, 4, "I\350\225\371", 0 },
525 { "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 },
526 { "swap", 0, 0xff6, 10, "SWAP-SPACE", probe_swap0 },
527 { "swap", 0, 0xff6, 10, "SWAPSPACE2", probe_swap1 },
528 { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", probe_swap0 },
529 { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", probe_swap1 },
530 { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", probe_swap0 },
531 { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", probe_swap1 },
532 { "swap", 0, 0x7ff6, 10, "SWAP-SPACE", probe_swap0 },
533 { "swap", 0, 0x7ff6, 10, "SWAPSPACE2", probe_swap1 },
534 { "swap", 0, 0xfff6, 10, "SWAP-SPACE", probe_swap0 },
535 { "swap", 0, 0xfff6, 10, "SWAPSPACE2", probe_swap1 },
536 { "ocfs", 0, 8, 9, "OracleCFS", probe_ocfs },
537 { "ocfs2", 1, 0, 6, "OCFSV2", probe_ocfs2 },
538 { "ocfs2", 2, 0, 6, "OCFSV2", probe_ocfs2 },
539 { "ocfs2", 4, 0, 6, "OCFSV2", probe_ocfs2 },
540 { "ocfs2", 8, 0, 6, "OCFSV2", probe_ocfs2 },
541 { NULL, 0, 0, 0, NULL, NULL }
542};
543
544/*
545 * Verify that the data in dev is consistent with what is on the actual
546 * block device (using the devname field only). Normally this will be
547 * called when finding items in the cache, but for long running processes
548 * is also desirable to revalidate an item before use.
549 *
550 * If we are unable to revalidate the data, we return the old data and
551 * do not set the BLKID_BID_FL_VERIFIED flag on it.
552 */
553blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
554{
555 const struct blkid_magic *id;
556 unsigned char *bufs[BLKID_BLK_OFFS + 1], *buf;
557 const char *type;
558 struct stat st;
559 time_t diff, now;
560 int fd, idx;
561
562 if (!dev)
563 return NULL;
564
565 now = time(0);
566 diff = now - dev->bid_time;
567
568 if ((now < dev->bid_time) ||
569 (diff < BLKID_PROBE_MIN) ||
570 (dev->bid_flags & BLKID_BID_FL_VERIFIED &&
571 diff < BLKID_PROBE_INTERVAL))
572 return dev;
573
574 DBG(DEBUG_PROBE,
575 printf("need to revalidate %s (time since last check %lu)\n",
576 dev->bid_name, diff));
577
578 if (((fd = open(dev->bid_name, O_RDONLY)) < 0) ||
579 (fstat(fd, &st) < 0)) {
580 if (errno == ENXIO || errno == ENODEV || errno == ENOENT) {
581 blkid_free_dev(dev);
582 return NULL;
583 }
584 /* We don't have read permission, just return cache data. */
585 DBG(DEBUG_PROBE,
586 printf("returning unverified data for %s\n",
587 dev->bid_name));
588 return dev;
589 }
590
591 memset(bufs, 0, sizeof(bufs));
592
593 /*
594 * Iterate over the type array. If we already know the type,
595 * then try that first. If it doesn't work, then blow away
596 * the type information, and try again.
597 *
598 */
599try_again:
600 type = 0;
601 if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) {
602 uuid_t uuid;
603
604 if (check_mdraid(fd, uuid) == 0) {
605 set_uuid(dev, uuid);
606 type = "mdraid";
607 goto found_type;
608 }
609 }
610 for (id = type_array; id->bim_type; id++) {
611 if (dev->bid_type &&
612 strcmp(id->bim_type, dev->bid_type))
613 continue;
614
615 idx = id->bim_kboff + (id->bim_sboff >> 10);
616 if (idx > BLKID_BLK_OFFS || idx < 0)
617 continue;
618 buf = bufs[idx];
619 if (!buf) {
620 if (lseek(fd, idx << 10, SEEK_SET) < 0)
621 continue;
622
623 buf = xmalloc(1024);
624
625 if (read(fd, buf, 1024) != 1024) {
626 free(buf);
627 continue;
628 }
629 bufs[idx] = buf;
630 }
631
632 if (memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ff),
633 id->bim_len))
634 continue;
635
636 if ((id->bim_probe == NULL) ||
637 (id->bim_probe(fd, cache, dev, id, buf) == 0)) {
638 type = id->bim_type;
639 goto found_type;
640 }
641 }
642
643 if (!id->bim_type && dev->bid_type) {
644 /*
645 * Zap the device filesystem type and try again
646 */
647 blkid_set_tag(dev, "TYPE", 0, 0);
648 blkid_set_tag(dev, "SEC_TYPE", 0, 0);
649 blkid_set_tag(dev, "LABEL", 0, 0);
650 blkid_set_tag(dev, "UUID", 0, 0);
651 goto try_again;
652 }
653
654 if (!dev->bid_type) {
655 blkid_free_dev(dev);
656 return NULL;
657 }
658
659found_type:
660 if (dev && type) {
661 dev->bid_devno = st.st_rdev;
662 dev->bid_time = time(0);
663 dev->bid_flags |= BLKID_BID_FL_VERIFIED;
664 cache->bic_flags |= BLKID_BIC_FL_CHANGED;
665
666 blkid_set_tag(dev, "TYPE", type, 0);
667
668 DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n",
669 dev->bid_name, st.st_rdev, type));
670 }
671
672 close(fd);
673
674 return dev;
675}
676
677int blkid_known_fstype(const char *fstype)
678{
679 const struct blkid_magic *id;
680
681 for (id = type_array; id->bim_type; id++) {
682 if (strcmp(fstype, id->bim_type) == 0)
683 return 1;
684 }
685 return 0;
686}
687
688#ifdef TEST_PROGRAM
689int main(int argc, char **argv)
690{
691 blkid_dev dev;
692 blkid_cache cache;
693 int ret;
694
695 blkid_debug_mask = DEBUG_ALL;
696 if (argc != 2) {
697 fprintf(stderr, "Usage: %s device\n"
698 "Probe a single device to determine type\n", argv[0]);
699 exit(1);
700 }
701 if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
702 fprintf(stderr, "%s: error creating cache (%d)\n",
703 argv[0], ret);
704 exit(1);
705 }
706 dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL);
707 if (!dev) {
708 printf("%s: %s has an unsupported type\n", argv[0], argv[1]);
709 return 1;
710 }
711 printf("%s is type %s\n", argv[1], dev->bid_type ?
712 dev->bid_type : "(null)");
713 if (dev->bid_label)
714 printf("\tlabel is '%s'\n", dev->bid_label);
715 if (dev->bid_uuid)
716 printf("\tuuid is %s\n", dev->bid_uuid);
717
718 blkid_free_dev(dev);
719 return 0;
720}
721#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/probe.h b/e2fsprogs/old_e2fsprogs/blkid/probe.h
new file mode 100644
index 000000000..78f796419
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/probe.h
@@ -0,0 +1,375 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * probe.h - constants and on-disk structures for extracting device data
4 *
5 * Copyright (C) 1999 by Andries Brouwer
6 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
7 * Copyright (C) 2001 by Andreas Dilger
8 *
9 * %Begin-Header%
10 * This file may be redistributed under the terms of the
11 * GNU Lesser General Public License.
12 * %End-Header%
13 */
14
15#ifndef _BLKID_PROBE_H
16#define _BLKID_PROBE_H
17
18#include <linux/types.h>
19
20struct blkid_magic;
21
22typedef int (*blkid_probe_t)(int fd, blkid_cache cache, blkid_dev dev,
23 const struct blkid_magic *id, unsigned char *buf);
24
25struct blkid_magic {
26 const char *bim_type; /* type name for this magic */
27 long bim_kboff; /* kilobyte offset of superblock */
28 unsigned bim_sboff; /* byte offset within superblock */
29 unsigned bim_len; /* length of magic */
30 const char *bim_magic; /* magic string */
31 blkid_probe_t bim_probe; /* probe function */
32};
33
34/*
35 * Structures for each of the content types we want to extract information
36 * from. We do not necessarily need the magic field here, because we have
37 * already identified the content type before we get this far. It may still
38 * be useful if there are probe functions which handle multiple content types.
39 */
40struct ext2_super_block {
41 __u32 s_inodes_count;
42 __u32 s_blocks_count;
43 __u32 s_r_blocks_count;
44 __u32 s_free_blocks_count;
45 __u32 s_free_inodes_count;
46 __u32 s_first_data_block;
47 __u32 s_log_block_size;
48 __u32 s_dummy3[7];
49 unsigned char s_magic[2];
50 __u16 s_state;
51 __u32 s_dummy5[8];
52 __u32 s_feature_compat;
53 __u32 s_feature_incompat;
54 __u32 s_feature_ro_compat;
55 unsigned char s_uuid[16];
56 char s_volume_name[16];
57};
58#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004
59#define EXT3_FEATURE_INCOMPAT_RECOVER 0x00000004
60#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008
61
62struct xfs_super_block {
63 unsigned char xs_magic[4];
64 __u32 xs_blocksize;
65 __u64 xs_dblocks;
66 __u64 xs_rblocks;
67 __u32 xs_dummy1[2];
68 unsigned char xs_uuid[16];
69 __u32 xs_dummy2[15];
70 char xs_fname[12];
71 __u32 xs_dummy3[2];
72 __u64 xs_icount;
73 __u64 xs_ifree;
74 __u64 xs_fdblocks;
75};
76
77struct reiserfs_super_block {
78 __u32 rs_blocks_count;
79 __u32 rs_free_blocks;
80 __u32 rs_root_block;
81 __u32 rs_journal_block;
82 __u32 rs_journal_dev;
83 __u32 rs_orig_journal_size;
84 __u32 rs_dummy2[5];
85 __u16 rs_blocksize;
86 __u16 rs_dummy3[3];
87 unsigned char rs_magic[12];
88 __u32 rs_dummy4[5];
89 unsigned char rs_uuid[16];
90 char rs_label[16];
91};
92
93struct jfs_super_block {
94 unsigned char js_magic[4];
95 __u32 js_version;
96 __u64 js_size;
97 __u32 js_bsize;
98 __u32 js_dummy1;
99 __u32 js_pbsize;
100 __u32 js_dummy2[27];
101 unsigned char js_uuid[16];
102 unsigned char js_label[16];
103 unsigned char js_loguuid[16];
104};
105
106struct romfs_super_block {
107 unsigned char ros_magic[8];
108 __u32 ros_dummy1[2];
109 unsigned char ros_volume[16];
110};
111
112struct cramfs_super_block {
113 __u8 magic[4];
114 __u32 size;
115 __u32 flags;
116 __u32 future;
117 __u8 signature[16];
118 struct cramfs_info {
119 __u32 crc;
120 __u32 edition;
121 __u32 blocks;
122 __u32 files;
123 } info;
124 __u8 name[16];
125};
126
127struct swap_id_block {
128/* unsigned char sws_boot[1024]; */
129 __u32 sws_version;
130 __u32 sws_lastpage;
131 __u32 sws_nrbad;
132 unsigned char sws_uuid[16];
133 char sws_volume[16];
134 unsigned char sws_pad[117];
135 __u32 sws_badpg;
136};
137
138/* Yucky misaligned values */
139struct vfat_super_block {
140/* 00*/ unsigned char vs_ignored[3];
141/* 03*/ unsigned char vs_sysid[8];
142/* 0b*/ unsigned char vs_sector_size[2];
143/* 0d*/ __u8 vs_cluster_size;
144/* 0e*/ __u16 vs_reserved;
145/* 10*/ __u8 vs_fats;
146/* 11*/ unsigned char vs_dir_entries[2];
147/* 13*/ unsigned char vs_sectors[2];
148/* 15*/ unsigned char vs_media;
149/* 16*/ __u16 vs_fat_length;
150/* 18*/ __u16 vs_secs_track;
151/* 1a*/ __u16 vs_heads;
152/* 1c*/ __u32 vs_hidden;
153/* 20*/ __u32 vs_total_sect;
154/* 24*/ __u32 vs_fat32_length;
155/* 28*/ __u16 vs_flags;
156/* 2a*/ __u8 vs_version[2];
157/* 2c*/ __u32 vs_root_cluster;
158/* 30*/ __u16 vs_insfo_sector;
159/* 32*/ __u16 vs_backup_boot;
160/* 34*/ __u16 vs_reserved2[6];
161/* 40*/ unsigned char vs_unknown[3];
162/* 43*/ unsigned char vs_serno[4];
163/* 47*/ char vs_label[11];
164/* 52*/ unsigned char vs_magic[8];
165/* 5a*/ unsigned char vs_dummy2[164];
166/*1fe*/ unsigned char vs_pmagic[2];
167};
168
169/* Yucky misaligned values */
170struct msdos_super_block {
171/* 00*/ unsigned char ms_ignored[3];
172/* 03*/ unsigned char ms_sysid[8];
173/* 0b*/ unsigned char ms_sector_size[2];
174/* 0d*/ __u8 ms_cluster_size;
175/* 0e*/ __u16 ms_reserved;
176/* 10*/ __u8 ms_fats;
177/* 11*/ unsigned char ms_dir_entries[2];
178/* 13*/ unsigned char ms_sectors[2];
179/* 15*/ unsigned char ms_media;
180/* 16*/ __u16 ms_fat_length;
181/* 18*/ __u16 ms_secs_track;
182/* 1a*/ __u16 ms_heads;
183/* 1c*/ __u32 ms_hidden;
184/* 20*/ __u32 ms_total_sect;
185/* 24*/ unsigned char ms_unknown[3];
186/* 27*/ unsigned char ms_serno[4];
187/* 2b*/ char ms_label[11];
188/* 36*/ unsigned char ms_magic[8];
189/* 3d*/ unsigned char ms_dummy2[192];
190/*1fe*/ unsigned char ms_pmagic[2];
191};
192
193struct minix_super_block {
194 __u16 ms_ninodes;
195 __u16 ms_nzones;
196 __u16 ms_imap_blocks;
197 __u16 ms_zmap_blocks;
198 __u16 ms_firstdatazone;
199 __u16 ms_log_zone_size;
200 __u32 ms_max_size;
201 unsigned char ms_magic[2];
202 __u16 ms_state;
203 __u32 ms_zones;
204};
205
206struct mdp_superblock_s {
207 __u32 md_magic;
208 __u32 major_version;
209 __u32 minor_version;
210 __u32 patch_version;
211 __u32 gvalid_words;
212 __u32 set_uuid0;
213 __u32 ctime;
214 __u32 level;
215 __u32 size;
216 __u32 nr_disks;
217 __u32 raid_disks;
218 __u32 md_minor;
219 __u32 not_persistent;
220 __u32 set_uuid1;
221 __u32 set_uuid2;
222 __u32 set_uuid3;
223};
224
225struct hfs_super_block {
226 char h_magic[2];
227 char h_dummy[18];
228 __u32 h_blksize;
229};
230
231struct ocfs_volume_header {
232 unsigned char minor_version[4];
233 unsigned char major_version[4];
234 unsigned char signature[128];
235 char mount[128];
236 unsigned char mount_len[2];
237};
238
239struct ocfs_volume_label {
240 unsigned char disk_lock[48];
241 char label[64];
242 unsigned char label_len[2];
243 unsigned char vol_id[16];
244 unsigned char vol_id_len[2];
245};
246
247#define ocfsmajor(o) ((__u32)o.major_version[0] \
248 + (((__u32) o.major_version[1]) << 8) \
249 + (((__u32) o.major_version[2]) << 16) \
250 + (((__u32) o.major_version[3]) << 24))
251#define ocfslabellen(o) ((__u32)o.label_len[0] + (((__u32) o.label_len[1]) << 8))
252#define ocfsmountlen(o) ((__u32)o.mount_len[0] + (((__u32) o.mount_len[1])<<8))
253
254#define OCFS_MAGIC "OracleCFS"
255
256struct ocfs2_super_block {
257 unsigned char signature[8];
258 unsigned char s_dummy1[184];
259 unsigned char s_dummy2[80];
260 char s_label[64];
261 unsigned char s_uuid[16];
262};
263
264#define OCFS2_MIN_BLOCKSIZE 512
265#define OCFS2_MAX_BLOCKSIZE 4096
266
267#define OCFS2_SUPER_BLOCK_BLKNO 2
268
269#define OCFS2_SUPER_BLOCK_SIGNATURE "OCFSV2"
270
271struct oracle_asm_disk_label {
272 char dummy[32];
273 char dl_tag[8];
274 char dl_id[24];
275};
276
277#define ORACLE_ASM_DISK_LABEL_MARKED "ORCLDISK"
278#define ORACLE_ASM_DISK_LABEL_OFFSET 32
279
280#define ISODCL(from, to) (to - from + 1)
281struct iso_volume_descriptor {
282 char type[ISODCL(1,1)]; /* 711 */
283 char id[ISODCL(2,6)];
284 char version[ISODCL(7,7)];
285 char data[ISODCL(8,2048)];
286};
287
288/*
289 * Byte swap functions
290 */
291#ifdef __GNUC__
292#define _INLINE_ static __inline__
293#else /* For Watcom C */
294#define _INLINE_ static inline
295#endif
296
297static __u16 blkid_swab16(__u16 val);
298static __u32 blkid_swab32(__u32 val);
299static __u64 blkid_swab64(__u64 val);
300
301#if ((defined __GNUC__) && \
302 (defined(__i386__) || defined(__i486__) || defined(__i586__)))
303
304#define _BLKID_HAVE_ASM_BITOPS_
305
306_INLINE_ __u32 blkid_swab32(__u32 val)
307{
308#ifdef EXT2FS_REQUIRE_486
309 __asm__("bswap %0" : "=r" (val) : "0" (val));
310#else
311 __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */
312 "rorl $16,%0\n\t" /* swap words */
313 "xchgb %b0,%h0" /* swap higher bytes */
314 :"=q" (val)
315 : "0" (val));
316#endif
317 return val;
318}
319
320_INLINE_ __u16 blkid_swab16(__u16 val)
321{
322 __asm__("xchgb %b0,%h0" /* swap bytes */ \
323 : "=q" (val) \
324 : "0" (val)); \
325 return val;
326}
327
328_INLINE_ __u64 blkid_swab64(__u64 val)
329{
330 return blkid_swab32(val >> 32) |
331 ( ((__u64)blkid_swab32((__u32)val)) << 32 );
332}
333#endif
334
335#if !defined(_BLKID_HAVE_ASM_BITOPS_)
336
337_INLINE_ __u16 blkid_swab16(__u16 val)
338{
339 return (val >> 8) | (val << 8);
340}
341
342_INLINE_ __u32 blkid_swab32(__u32 val)
343{
344 return (val>>24) | ((val>>8) & 0xFF00) |
345 ((val<<8) & 0xFF0000) | (val<<24);
346}
347
348_INLINE_ __u64 blkid_swab64(__u64 val)
349{
350 return blkid_swab32(val >> 32) |
351 ( ((__u64)blkid_swab32((__u32)val)) << 32 );
352}
353#endif
354
355
356
357#if __BYTE_ORDER == __BIG_ENDIAN
358#define blkid_le16(x) blkid_swab16(x)
359#define blkid_le32(x) blkid_swab32(x)
360#define blkid_le64(x) blkid_swab64(x)
361#define blkid_be16(x) (x)
362#define blkid_be32(x) (x)
363#define blkid_be64(x) (x)
364#else
365#define blkid_le16(x) (x)
366#define blkid_le32(x) (x)
367#define blkid_le64(x) (x)
368#define blkid_be16(x) blkid_swab16(x)
369#define blkid_be32(x) blkid_swab32(x)
370#define blkid_be64(x) blkid_swab64(x)
371#endif
372
373#undef _INLINE_
374
375#endif /* _BLKID_PROBE_H */
diff --git a/e2fsprogs/old_e2fsprogs/blkid/read.c b/e2fsprogs/old_e2fsprogs/blkid/read.c
new file mode 100644
index 000000000..bb02a2e21
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/read.c
@@ -0,0 +1,462 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * read.c - read the blkid cache from disk, to avoid scanning all devices
4 *
5 * Copyright (C) 2001, 2003 Theodore Y. Ts'o
6 * Copyright (C) 2001 Andreas Dilger
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the
10 * GNU Lesser General Public License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <ctype.h>
16#include <string.h>
17#include <time.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <unistd.h>
22#include <errno.h>
23
24#include "blkidP.h"
25#include "../uuid/uuid.h"
26
27#ifdef HAVE_STRTOULL
28#define __USE_ISOC9X
29#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */
30#else
31/* FIXME: need to support real strtoull here */
32#define STRTOULL strtoul
33#endif
34
35#include <stdlib.h>
36
37#ifdef TEST_PROGRAM
38#define blkid_debug_dump_dev(dev) (debug_dump_dev(dev))
39static void debug_dump_dev(blkid_dev dev);
40#endif
41
42/*
43 * File format:
44 *
45 * <device [<NAME="value"> ...]>device_name</device>
46 *
47 * The following tags are required for each entry:
48 * <ID="id"> unique (within this file) ID number of this device
49 * <TIME="time"> (ascii time_t) time this entry was last read from disk
50 * <TYPE="type"> (detected) type of filesystem/data for this partition
51 *
52 * The following tags may be present, depending on the device contents
53 * <LABEL="label"> (user supplied) label (volume name, etc)
54 * <UUID="uuid"> (generated) universally unique identifier (serial no)
55 */
56
57static char *skip_over_blank(char *cp)
58{
59 while (*cp && isspace(*cp))
60 cp++;
61 return cp;
62}
63
64static char *skip_over_word(char *cp)
65{
66 char ch;
67
68 while ((ch = *cp)) {
69 /* If we see a backslash, skip the next character */
70 if (ch == '\\') {
71 cp++;
72 if (*cp == '\0')
73 break;
74 cp++;
75 continue;
76 }
77 if (isspace(ch) || ch == '<' || ch == '>')
78 break;
79 cp++;
80 }
81 return cp;
82}
83
84static char *strip_line(char *line)
85{
86 char *p;
87
88 line = skip_over_blank(line);
89
90 p = line + strlen(line) - 1;
91
92 while (*line) {
93 if (isspace(*p))
94 *p-- = '\0';
95 else
96 break;
97 }
98
99 return line;
100}
101
102/*
103 * Start parsing a new line from the cache.
104 *
105 * line starts with "<device" return 1 -> continue parsing line
106 * line starts with "<foo", empty, or # return 0 -> skip line
107 * line starts with other, return -BLKID_ERR_CACHE -> error
108 */
109static int parse_start(char **cp)
110{
111 char *p;
112
113 p = strip_line(*cp);
114
115 /* Skip comment or blank lines. We can't just NUL the first '#' char,
116 * in case it is inside quotes, or escaped.
117 */
118 if (*p == '\0' || *p == '#')
119 return 0;
120
121 if (!strncmp(p, "<device", 7)) {
122 DBG(DEBUG_READ, printf("found device header: %8s\n", p));
123 p += 7;
124
125 *cp = p;
126 return 1;
127 }
128
129 if (*p == '<')
130 return 0;
131
132 return -BLKID_ERR_CACHE;
133}
134
135/* Consume the remaining XML on the line (cosmetic only) */
136static int parse_end(char **cp)
137{
138 *cp = skip_over_blank(*cp);
139
140 if (!strncmp(*cp, "</device>", 9)) {
141 DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp));
142 *cp += 9;
143 return 0;
144 }
145
146 return -BLKID_ERR_CACHE;
147}
148
149/*
150 * Allocate a new device struct with device name filled in. Will handle
151 * finding the device on lines of the form:
152 * <device foo=bar>devname</device>
153 * <device>devname<foo>bar</foo></device>
154 */
155static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
156{
157 char *start, *tmp, *end, *name;
158 int ret;
159
160 if ((ret = parse_start(cp)) <= 0)
161 return ret;
162
163 start = tmp = strchr(*cp, '>');
164 if (!start) {
165 DBG(DEBUG_READ,
166 printf("blkid: short line parsing dev: %s\n", *cp));
167 return -BLKID_ERR_CACHE;
168 }
169 start = skip_over_blank(start + 1);
170 end = skip_over_word(start);
171
172 DBG(DEBUG_READ, printf("device should be %*s\n", end - start, start));
173
174 if (**cp == '>')
175 *cp = end;
176 else
177 (*cp)++;
178
179 *tmp = '\0';
180
181 if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
182 DBG(DEBUG_READ,
183 printf("blkid: missing </device> ending: %s\n", end));
184 } else if (tmp)
185 *tmp = '\0';
186
187 if (end - start <= 1) {
188 DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp));
189 return -BLKID_ERR_CACHE;
190 }
191
192 name = blkid_strndup(start, end-start);
193 if (name == NULL)
194 return -BLKID_ERR_MEM;
195
196 DBG(DEBUG_READ, printf("found dev %s\n", name));
197
198 if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE)))
199 return -BLKID_ERR_MEM;
200
201 free(name);
202 return 1;
203}
204
205/*
206 * Extract a tag of the form NAME="value" from the line.
207 */
208static int parse_token(char **name, char **value, char **cp)
209{
210 char *end;
211
212 if (!name || !value || !cp)
213 return -BLKID_ERR_PARAM;
214
215 if (!(*value = strchr(*cp, '=')))
216 return 0;
217
218 **value = '\0';
219 *name = strip_line(*cp);
220 *value = skip_over_blank(*value + 1);
221
222 if (**value == '"') {
223 end = strchr(*value + 1, '"');
224 if (!end) {
225 DBG(DEBUG_READ,
226 printf("unbalanced quotes at: %s\n", *value));
227 *cp = *value;
228 return -BLKID_ERR_CACHE;
229 }
230 (*value)++;
231 *end = '\0';
232 end++;
233 } else {
234 end = skip_over_word(*value);
235 if (*end) {
236 *end = '\0';
237 end++;
238 }
239 }
240 *cp = end;
241
242 return 1;
243}
244
245/*
246 * Extract a tag of the form <NAME>value</NAME> from the line.
247 */
248/*
249static int parse_xml(char **name, char **value, char **cp)
250{
251 char *end;
252
253 if (!name || !value || !cp)
254 return -BLKID_ERR_PARAM;
255
256 *name = strip_line(*cp);
257
258 if ((*name)[0] != '<' || (*name)[1] == '/')
259 return 0;
260
261 FIXME: finish this.
262}
263*/
264
265/*
266 * Extract a tag from the line.
267 *
268 * Return 1 if a valid tag was found.
269 * Return 0 if no tag found.
270 * Return -ve error code.
271 */
272static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp)
273{
274 char *name;
275 char *value;
276 int ret;
277
278 if (!cache || !dev)
279 return -BLKID_ERR_PARAM;
280
281 if ((ret = parse_token(&name, &value, cp)) <= 0 /* &&
282 (ret = parse_xml(&name, &value, cp)) <= 0 */)
283 return ret;
284
285 /* Some tags are stored directly in the device struct */
286 if (!strcmp(name, "DEVNO"))
287 dev->bid_devno = STRTOULL(value, 0, 0);
288 else if (!strcmp(name, "PRI"))
289 dev->bid_pri = strtol(value, 0, 0);
290 else if (!strcmp(name, "TIME"))
291 /* FIXME: need to parse a long long eventually */
292 dev->bid_time = strtol(value, 0, 0);
293 else
294 ret = blkid_set_tag(dev, name, value, strlen(value));
295
296 DBG(DEBUG_READ, printf(" tag: %s=\"%s\"\n", name, value));
297
298 return ret < 0 ? ret : 1;
299}
300
301/*
302 * Parse a single line of data, and return a newly allocated dev struct.
303 * Add the new device to the cache struct, if one was read.
304 *
305 * Lines are of the form <device [TAG="value" ...]>/dev/foo</device>
306 *
307 * Returns -ve value on error.
308 * Returns 0 otherwise.
309 * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL
310 * (e.g. comment lines, unknown XML content, etc).
311 */
312static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
313{
314 blkid_dev dev;
315 int ret;
316
317 if (!cache || !dev_p)
318 return -BLKID_ERR_PARAM;
319
320 *dev_p = NULL;
321
322 DBG(DEBUG_READ, printf("line: %s\n", cp));
323
324 if ((ret = parse_dev(cache, dev_p, &cp)) <= 0)
325 return ret;
326
327 dev = *dev_p;
328
329 while ((ret = parse_tag(cache, dev, &cp)) > 0) {
330 ;
331 }
332
333 if (dev->bid_type == NULL) {
334 DBG(DEBUG_READ,
335 printf("blkid: device %s has no TYPE\n",dev->bid_name));
336 blkid_free_dev(dev);
337 }
338
339 DBG(DEBUG_READ, blkid_debug_dump_dev(dev));
340
341 return ret;
342}
343
344/*
345 * Parse the specified filename, and return the data in the supplied or
346 * a newly allocated cache struct. If the file doesn't exist, return a
347 * new empty cache struct.
348 */
349void blkid_read_cache(blkid_cache cache)
350{
351 FILE *file;
352 char buf[4096];
353 int fd, lineno = 0;
354 struct stat st;
355
356 if (!cache)
357 return;
358
359 /*
360 * If the file doesn't exist, then we just return an empty
361 * struct so that the cache can be populated.
362 */
363 if ((fd = open(cache->bic_filename, O_RDONLY)) < 0)
364 return;
365 if (fstat(fd, &st) < 0)
366 goto errout;
367 if ((st.st_mtime == cache->bic_ftime) ||
368 (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
369 DBG(DEBUG_CACHE, printf("skipping re-read of %s\n",
370 cache->bic_filename));
371 goto errout;
372 }
373
374 DBG(DEBUG_CACHE, printf("reading cache file %s\n",
375 cache->bic_filename));
376
377 file = fdopen(fd, "r");
378 if (!file)
379 goto errout;
380
381 while (fgets(buf, sizeof(buf), file)) {
382 blkid_dev dev;
383 unsigned int end;
384
385 lineno++;
386 if (buf[0] == 0)
387 continue;
388 end = strlen(buf) - 1;
389 /* Continue reading next line if it ends with a backslash */
390 while (buf[end] == '\\' && end < sizeof(buf) - 2 &&
391 fgets(buf + end, sizeof(buf) - end, file)) {
392 end = strlen(buf) - 1;
393 lineno++;
394 }
395
396 if (blkid_parse_line(cache, &dev, buf) < 0) {
397 DBG(DEBUG_READ,
398 printf("blkid: bad format on line %d\n", lineno));
399 continue;
400 }
401 }
402 fclose(file);
403
404 /*
405 * Initially we do not need to write out the cache file.
406 */
407 cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
408 cache->bic_ftime = st.st_mtime;
409
410 return;
411errout:
412 close(fd);
413 return;
414}
415
416#ifdef TEST_PROGRAM
417static void debug_dump_dev(blkid_dev dev)
418{
419 struct list_head *p;
420
421 if (!dev) {
422 printf(" dev: NULL\n");
423 return;
424 }
425
426 printf(" dev: name = %s\n", dev->bid_name);
427 printf(" dev: DEVNO=\"0x%0llx\"\n", dev->bid_devno);
428 printf(" dev: TIME=\"%lu\"\n", dev->bid_time);
429 printf(" dev: PRI=\"%d\"\n", dev->bid_pri);
430 printf(" dev: flags = 0x%08X\n", dev->bid_flags);
431
432 list_for_each(p, &dev->bid_tags) {
433 blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
434 if (tag)
435 printf(" tag: %s=\"%s\"\n", tag->bit_name,
436 tag->bit_val);
437 else
438 printf(" tag: NULL\n");
439 }
440 puts("");
441}
442
443int main(int argc, char**argv)
444{
445 blkid_cache cache = NULL;
446 int ret;
447
448 blkid_debug_mask = DEBUG_ALL;
449 if (argc > 2) {
450 fprintf(stderr, "Usage: %s [filename]\n"
451 "Test parsing of the cache (filename)\n", argv[0]);
452 exit(1);
453 }
454 if ((ret = blkid_get_cache(&cache, argv[1])) < 0)
455 fprintf(stderr, "error %d reading cache file %s\n", ret,
456 argv[1] ? argv[1] : BLKID_CACHE_FILE);
457
458 blkid_put_cache(cache);
459
460 return ret;
461}
462#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/resolve.c b/e2fsprogs/old_e2fsprogs/blkid/resolve.c
new file mode 100644
index 000000000..7942de2cd
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/resolve.c
@@ -0,0 +1,139 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * resolve.c - resolve names and tags into specific devices
4 *
5 * Copyright (C) 2001, 2003 Theodore Ts'o.
6 * Copyright (C) 2001 Andreas Dilger
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the
10 * GNU Lesser General Public License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#ifdef HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <stdlib.h>
19#include <fcntl.h>
20#include <string.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include "blkidP.h"
24#include "probe.h"
25
26/*
27 * Find a tagname (e.g. LABEL or UUID) on a specific device.
28 */
29char *blkid_get_tag_value(blkid_cache cache, const char *tagname,
30 const char *devname)
31{
32 blkid_tag found;
33 blkid_dev dev;
34 blkid_cache c = cache;
35 char *ret = NULL;
36
37 DBG(DEBUG_RESOLVE, printf("looking for %s on %s\n", tagname, devname));
38
39 if (!devname)
40 return NULL;
41
42 if (!cache) {
43 if (blkid_get_cache(&c, NULL) < 0)
44 return NULL;
45 }
46
47 if ((dev = blkid_get_dev(c, devname, BLKID_DEV_NORMAL)) &&
48 (found = blkid_find_tag_dev(dev, tagname)))
49 ret = blkid_strdup(found->bit_val);
50
51 if (!cache)
52 blkid_put_cache(c);
53
54 return ret;
55}
56
57/*
58 * Locate a device name from a token (NAME=value string), or (name, value)
59 * pair. In the case of a token, value is ignored. If the "token" is not
60 * of the form "NAME=value" and there is no value given, then it is assumed
61 * to be the actual devname and a copy is returned.
62 */
63char *blkid_get_devname(blkid_cache cache, const char *token,
64 const char *value)
65{
66 blkid_dev dev;
67 blkid_cache c = cache;
68 char *t = 0, *v = 0;
69 char *ret = NULL;
70
71 if (!token)
72 return NULL;
73
74 if (!cache) {
75 if (blkid_get_cache(&c, NULL) < 0)
76 return NULL;
77 }
78
79 DBG(DEBUG_RESOLVE,
80 printf("looking for %s%s%s %s\n", token, value ? "=" : "",
81 value ? value : "", cache ? "in cache" : "from disk"));
82
83 if (!value) {
84 if (!strchr(token, '='))
85 return blkid_strdup(token);
86 blkid_parse_tag_string(token, &t, &v);
87 if (!t || !v)
88 goto errout;
89 token = t;
90 value = v;
91 }
92
93 dev = blkid_find_dev_with_tag(c, token, value);
94 if (!dev)
95 goto errout;
96
97 ret = blkid_strdup(blkid_dev_devname(dev));
98
99errout:
100 free(t);
101 free(v);
102 if (!cache) {
103 blkid_put_cache(c);
104 }
105 return ret;
106}
107
108#ifdef TEST_PROGRAM
109int main(int argc, char **argv)
110{
111 char *value;
112 blkid_cache cache;
113
114 blkid_debug_mask = DEBUG_ALL;
115 if (argc != 2 && argc != 3) {
116 fprintf(stderr, "Usage:\t%s tagname=value\n"
117 "\t%s tagname devname\n"
118 "Find which device holds a given token or\n"
119 "Find what the value of a tag is in a device\n",
120 argv[0], argv[0]);
121 exit(1);
122 }
123 if (blkid_get_cache(&cache, bb_dev_null) < 0) {
124 fprintf(stderr, "cannot get blkid cache\n");
125 exit(1);
126 }
127
128 if (argv[2]) {
129 value = blkid_get_tag_value(cache, argv[1], argv[2]);
130 printf("%s has tag %s=%s\n", argv[2], argv[1],
131 value ? value : "<missing>");
132 } else {
133 value = blkid_get_devname(cache, argv[1], NULL);
134 printf("%s has tag %s\n", value ? value : "<none>", argv[1]);
135 }
136 blkid_put_cache(cache);
137 return value ? 0 : 1;
138}
139#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/save.c b/e2fsprogs/old_e2fsprogs/blkid/save.c
new file mode 100644
index 000000000..cdbaabcb1
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/save.c
@@ -0,0 +1,189 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * save.c - write the cache struct to disk
4 *
5 * Copyright (C) 2001 by Andreas Dilger
6 * Copyright (C) 2003 Theodore Ts'o
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the
10 * GNU Lesser General Public License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#include <stdlib.h>
17#include <unistd.h>
18#include <sys/types.h>
19#ifdef HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#ifdef HAVE_SYS_MKDEV_H
23#include <sys/mkdev.h>
24#endif
25#ifdef HAVE_ERRNO_H
26#include <errno.h>
27#endif
28#include "blkidP.h"
29
30static int save_dev(blkid_dev dev, FILE *file)
31{
32 struct list_head *p;
33
34 if (!dev || dev->bid_name[0] != '/')
35 return 0;
36
37 DBG(DEBUG_SAVE,
38 printf("device %s, type %s\n", dev->bid_name, dev->bid_type));
39
40 fprintf(file,
41 "<device DEVNO=\"0x%04lx\" TIME=\"%lu\"",
42 (unsigned long) dev->bid_devno, dev->bid_time);
43 if (dev->bid_pri)
44 fprintf(file, " PRI=\"%d\"", dev->bid_pri);
45 list_for_each(p, &dev->bid_tags) {
46 blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
47 fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val);
48 }
49 fprintf(file, ">%s</device>\n", dev->bid_name);
50
51 return 0;
52}
53
54/*
55 * Write out the cache struct to the cache file on disk.
56 */
57int blkid_flush_cache(blkid_cache cache)
58{
59 struct list_head *p;
60 char *tmp = NULL;
61 const char *opened = NULL;
62 const char *filename;
63 FILE *file = NULL;
64 int fd, ret = 0;
65 struct stat st;
66
67 if (!cache)
68 return -BLKID_ERR_PARAM;
69
70 if (list_empty(&cache->bic_devs) ||
71 !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
72 DBG(DEBUG_SAVE, printf("skipping cache file write\n"));
73 return 0;
74 }
75
76 filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE;
77
78 /* If we can't write to the cache file, then don't even try */
79 if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) ||
80 (ret == 0 && access(filename, W_OK) < 0)) {
81 DBG(DEBUG_SAVE,
82 printf("can't write to cache file %s\n", filename));
83 return 0;
84 }
85
86 /*
87 * Try and create a temporary file in the same directory so
88 * that in case of error we don't overwrite the cache file.
89 * If the cache file doesn't yet exist, it isn't a regular
90 * file (e.g. /dev/null or a socket), or we couldn't create
91 * a temporary file then we open it directly.
92 */
93 if (ret == 0 && S_ISREG(st.st_mode)) {
94 tmp = xmalloc(strlen(filename) + 8);
95 sprintf(tmp, "%s-XXXXXX", filename);
96 fd = mkstemp(tmp);
97 if (fd >= 0) {
98 file = fdopen(fd, "w");
99 opened = tmp;
100 }
101 fchmod(fd, 0644);
102 }
103
104 if (!file) {
105 file = fopen(filename, "w");
106 opened = filename;
107 }
108
109 DBG(DEBUG_SAVE,
110 printf("writing cache file %s (really %s)\n",
111 filename, opened));
112
113 if (!file) {
114 ret = errno;
115 goto errout;
116 }
117
118 list_for_each(p, &cache->bic_devs) {
119 blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
120 if (!dev->bid_type)
121 continue;
122 if ((ret = save_dev(dev, file)) < 0)
123 break;
124 }
125
126 if (ret >= 0) {
127 cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
128 ret = 1;
129 }
130
131 fclose(file);
132 if (opened != filename) {
133 if (ret < 0) {
134 unlink(opened);
135 DBG(DEBUG_SAVE,
136 printf("unlinked temp cache %s\n", opened));
137 } else {
138 char *backup;
139
140 backup = xmalloc(strlen(filename) + 5);
141 sprintf(backup, "%s.old", filename);
142 unlink(backup);
143 link(filename, backup);
144 free(backup);
145 rename(opened, filename);
146 DBG(DEBUG_SAVE,
147 printf("moved temp cache %s\n", opened));
148 }
149 }
150
151errout:
152 free(tmp);
153 return ret;
154}
155
156#ifdef TEST_PROGRAM
157int main(int argc, char **argv)
158{
159 blkid_cache cache = NULL;
160 int ret;
161
162 blkid_debug_mask = DEBUG_ALL;
163 if (argc > 2) {
164 fprintf(stderr, "Usage: %s [filename]\n"
165 "Test loading/saving a cache (filename)\n", argv[0]);
166 exit(1);
167 }
168
169 if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
170 fprintf(stderr, "%s: error creating cache (%d)\n",
171 argv[0], ret);
172 exit(1);
173 }
174 if ((ret = blkid_probe_all(cache)) < 0) {
175 fprintf(stderr, "error (%d) probing devices\n", ret);
176 exit(1);
177 }
178 cache->bic_filename = blkid_strdup(argv[1]);
179
180 if ((ret = blkid_flush_cache(cache)) < 0) {
181 fprintf(stderr, "error (%d) saving cache\n", ret);
182 exit(1);
183 }
184
185 blkid_put_cache(cache);
186
187 return ret;
188}
189#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/tag.c b/e2fsprogs/old_e2fsprogs/blkid/tag.c
new file mode 100644
index 000000000..9e862a50a
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/blkid/tag.c
@@ -0,0 +1,432 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * tag.c - allocation/initialization/free routines for tag structs
4 *
5 * Copyright (C) 2001 Andreas Dilger
6 * Copyright (C) 2003 Theodore Ts'o
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the
10 * GNU Lesser General Public License.
11 * %End-Header%
12 */
13
14#include <stdlib.h>
15#include <string.h>
16#include <stdio.h>
17
18#include "blkidP.h"
19
20static blkid_tag blkid_new_tag(void)
21{
22 blkid_tag tag;
23
24 if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag))))
25 return NULL;
26
27 INIT_LIST_HEAD(&tag->bit_tags);
28 INIT_LIST_HEAD(&tag->bit_names);
29
30 return tag;
31}
32
33#ifdef CONFIG_BLKID_DEBUG
34void blkid_debug_dump_tag(blkid_tag tag)
35{
36 if (!tag) {
37 printf(" tag: NULL\n");
38 return;
39 }
40
41 printf(" tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
42}
43#endif
44
45void blkid_free_tag(blkid_tag tag)
46{
47 if (!tag)
48 return;
49
50 DBG(DEBUG_TAG, printf(" freeing tag %s=%s\n", tag->bit_name,
51 tag->bit_val ? tag->bit_val : "(NULL)"));
52 DBG(DEBUG_TAG, blkid_debug_dump_tag(tag));
53
54 list_del(&tag->bit_tags); /* list of tags for this device */
55 list_del(&tag->bit_names); /* list of tags with this type */
56
57 free(tag->bit_name);
58 free(tag->bit_val);
59 free(tag);
60}
61
62/*
63 * Find the desired tag on a device. If value is NULL, then the
64 * first such tag is returned, otherwise return only exact tag if found.
65 */
66blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
67{
68 struct list_head *p;
69
70 if (!dev || !type)
71 return NULL;
72
73 list_for_each(p, &dev->bid_tags) {
74 blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
75 bit_tags);
76
77 if (!strcmp(tmp->bit_name, type))
78 return tmp;
79 }
80 return NULL;
81}
82
83/*
84 * Find the desired tag type in the cache.
85 * We return the head tag for this tag type.
86 */
87static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
88{
89 blkid_tag head = NULL, tmp;
90 struct list_head *p;
91
92 if (!cache || !type)
93 return NULL;
94
95 list_for_each(p, &cache->bic_tags) {
96 tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
97 if (!strcmp(tmp->bit_name, type)) {
98 DBG(DEBUG_TAG,
99 printf(" found cache tag head %s\n", type));
100 head = tmp;
101 break;
102 }
103 }
104 return head;
105}
106
107/*
108 * Set a tag on an existing device.
109 *
110 * If value is NULL, then delete the tagsfrom the device.
111 */
112int blkid_set_tag(blkid_dev dev, const char *name,
113 const char *value, const int vlength)
114{
115 blkid_tag t = 0, head = 0;
116 char *val = 0;
117
118 if (!dev || !name)
119 return -BLKID_ERR_PARAM;
120
121 if (!(val = blkid_strndup(value, vlength)) && value)
122 return -BLKID_ERR_MEM;
123 t = blkid_find_tag_dev(dev, name);
124 if (!value) {
125 blkid_free_tag(t);
126 } else if (t) {
127 if (!strcmp(t->bit_val, val)) {
128 /* Same thing, exit */
129 free(val);
130 return 0;
131 }
132 free(t->bit_val);
133 t->bit_val = val;
134 } else {
135 /* Existing tag not present, add to device */
136 if (!(t = blkid_new_tag()))
137 goto errout;
138 t->bit_name = blkid_strdup(name);
139 t->bit_val = val;
140 t->bit_dev = dev;
141
142 list_add_tail(&t->bit_tags, &dev->bid_tags);
143
144 if (dev->bid_cache) {
145 head = blkid_find_head_cache(dev->bid_cache,
146 t->bit_name);
147 if (!head) {
148 head = blkid_new_tag();
149 if (!head)
150 goto errout;
151
152 DBG(DEBUG_TAG,
153 printf(" creating new cache tag head %s\n", name));
154 head->bit_name = blkid_strdup(name);
155 if (!head->bit_name)
156 goto errout;
157 list_add_tail(&head->bit_tags,
158 &dev->bid_cache->bic_tags);
159 }
160 list_add_tail(&t->bit_names, &head->bit_names);
161 }
162 }
163
164 /* Link common tags directly to the device struct */
165 if (!strcmp(name, "TYPE"))
166 dev->bid_type = val;
167 else if (!strcmp(name, "LABEL"))
168 dev->bid_label = val;
169 else if (!strcmp(name, "UUID"))
170 dev->bid_uuid = val;
171
172 if (dev->bid_cache)
173 dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
174 return 0;
175
176errout:
177 blkid_free_tag(t);
178 if (!t)
179 free(val);
180 blkid_free_tag(head);
181 return -BLKID_ERR_MEM;
182}
183
184
185/*
186 * Parse a "NAME=value" string. This is slightly different than
187 * parse_token, because that will end an unquoted value at a space, while
188 * this will assume that an unquoted value is the rest of the token (e.g.
189 * if we are passed an already quoted string from the command-line we don't
190 * have to both quote and escape quote so that the quotes make it to
191 * us).
192 *
193 * Returns 0 on success, and -1 on failure.
194 */
195int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
196{
197 char *name, *value, *cp;
198
199 DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token));
200
201 if (!token || !(cp = strchr(token, '=')))
202 return -1;
203
204 name = blkid_strdup(token);
205 if (!name)
206 return -1;
207 value = name + (cp - token);
208 *value++ = '\0';
209 if (*value == '"' || *value == '\'') {
210 char c = *value++;
211 if (!(cp = strrchr(value, c)))
212 goto errout; /* missing closing quote */
213 *cp = '\0';
214 }
215 value = blkid_strdup(value);
216 if (!value)
217 goto errout;
218
219 *ret_type = name;
220 *ret_val = value;
221
222 return 0;
223
224errout:
225 free(name);
226 return -1;
227}
228
229/*
230 * Tag iteration routines for the public libblkid interface.
231 *
232 * These routines do not expose the list.h implementation, which are a
233 * contamination of the namespace, and which force us to reveal far, far
234 * too much of our internal implemenation. I'm not convinced I want
235 * to keep list.h in the long term, anyway. It's fine for kernel
236 * programming, but performance is not the #1 priority for this
237 * library, and I really don't like the tradeoff of type-safety for
238 * performance for this application. [tytso:20030125.2007EST]
239 */
240
241/*
242 * This series of functions iterate over all tags in a device
243 */
244#define TAG_ITERATE_MAGIC 0x01a5284c
245
246struct blkid_struct_tag_iterate {
247 int magic;
248 blkid_dev dev;
249 struct list_head *p;
250};
251
252blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
253{
254 blkid_tag_iterate iter;
255
256 iter = xmalloc(sizeof(struct blkid_struct_tag_iterate));
257 iter->magic = TAG_ITERATE_MAGIC;
258 iter->dev = dev;
259 iter->p = dev->bid_tags.next;
260 return iter;
261}
262
263/*
264 * Return 0 on success, -1 on error
265 */
266extern int blkid_tag_next(blkid_tag_iterate iter,
267 const char **type, const char **value)
268{
269 blkid_tag tag;
270
271 *type = 0;
272 *value = 0;
273 if (!iter || iter->magic != TAG_ITERATE_MAGIC ||
274 iter->p == &iter->dev->bid_tags)
275 return -1;
276 tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
277 *type = tag->bit_name;
278 *value = tag->bit_val;
279 iter->p = iter->p->next;
280 return 0;
281}
282
283void blkid_tag_iterate_end(blkid_tag_iterate iter)
284{
285 if (!iter || iter->magic != TAG_ITERATE_MAGIC)
286 return;
287 iter->magic = 0;
288 free(iter);
289}
290
291/*
292 * This function returns a device which matches a particular
293 * type/value pair. If there is more than one device that matches the
294 * search specification, it returns the one with the highest priority
295 * value. This allows us to give preference to EVMS or LVM devices.
296 *
297 * XXX there should also be an interface which uses an iterator so we
298 * can get all of the devices which match a type/value search parameter.
299 */
300extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
301 const char *type,
302 const char *value)
303{
304 blkid_tag head;
305 blkid_dev dev;
306 int pri;
307 struct list_head *p;
308
309 if (!cache || !type || !value)
310 return NULL;
311
312 blkid_read_cache(cache);
313
314 DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value));
315
316try_again:
317 pri = -1;
318 dev = 0;
319 head = blkid_find_head_cache(cache, type);
320
321 if (head) {
322 list_for_each(p, &head->bit_names) {
323 blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
324 bit_names);
325
326 if (!strcmp(tmp->bit_val, value) &&
327 tmp->bit_dev->bid_pri > pri) {
328 dev = tmp->bit_dev;
329 pri = dev->bid_pri;
330 }
331 }
332 }
333 if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
334 dev = blkid_verify(cache, dev);
335 if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))
336 goto try_again;
337 }
338
339 if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
340 if (blkid_probe_all(cache) < 0)
341 return NULL;
342 goto try_again;
343 }
344 return dev;
345}
346
347#ifdef TEST_PROGRAM
348#ifdef HAVE_GETOPT_H
349#include <getopt.h>
350#else
351extern char *optarg;
352extern int optind;
353#endif
354
355void usage(char *prog)
356{
357 fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
358 "[type value]\n",
359 prog);
360 fprintf(stderr, "\tList all tags for a device and exit\n", prog);
361 exit(1);
362}
363
364int main(int argc, char **argv)
365{
366 blkid_tag_iterate iter;
367 blkid_cache cache = NULL;
368 blkid_dev dev;
369 int c, ret, found;
370 int flags = BLKID_DEV_FIND;
371 char *tmp;
372 char *file = NULL;
373 char *devname = NULL;
374 char *search_type = NULL;
375 char *search_value = NULL;
376 const char *type, *value;
377
378 while ((c = getopt (argc, argv, "m:f:")) != EOF)
379 switch (c) {
380 case 'f':
381 file = optarg;
382 break;
383 case 'm':
384 blkid_debug_mask = strtoul (optarg, &tmp, 0);
385 if (*tmp) {
386 fprintf(stderr, "Invalid debug mask: %d\n",
387 optarg);
388 exit(1);
389 }
390 break;
391 case '?':
392 usage(argv[0]);
393 }
394 if (argc > optind)
395 devname = argv[optind++];
396 if (argc > optind)
397 search_type = argv[optind++];
398 if (argc > optind)
399 search_value = argv[optind++];
400 if (!devname || (argc != optind))
401 usage(argv[0]);
402
403 if ((ret = blkid_get_cache(&cache, file)) != 0) {
404 fprintf(stderr, "%s: error creating cache (%d)\n",
405 argv[0], ret);
406 exit(1);
407 }
408
409 dev = blkid_get_dev(cache, devname, flags);
410 if (!dev) {
411 fprintf(stderr, "%s: cannot find device in blkid cache\n");
412 exit(1);
413 }
414 if (search_type) {
415 found = blkid_dev_has_tag(dev, search_type, search_value);
416 printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev),
417 search_type, search_value ? search_value : "NULL",
418 found ? "FOUND" : "NOT FOUND");
419 return !found;
420 }
421 printf("Device %s...\n", blkid_dev_devname(dev));
422
423 iter = blkid_tag_iterate_begin(dev);
424 while (blkid_tag_next(iter, &type, &value) == 0) {
425 printf("\tTag %s has value %s\n", type, value);
426 }
427 blkid_tag_iterate_end(iter);
428
429 blkid_put_cache(cache);
430 return 0;
431}
432#endif
diff --git a/e2fsprogs/old_e2fsprogs/chattr.c b/e2fsprogs/old_e2fsprogs/chattr.c
new file mode 100644
index 000000000..4848e1e1a
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/chattr.c
@@ -0,0 +1,219 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * chattr.c - Change file attributes on an ext2 file system
4 *
5 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * This file can be redistributed under the terms of the GNU General
10 * Public License
11 */
12
13/*
14 * History:
15 * 93/10/30 - Creation
16 * 93/11/13 - Replace stat() calls by lstat() to avoid loops
17 * 94/02/27 - Integrated in Ted's distribution
18 * 98/12/29 - Ignore symlinks when working recursively (G M Sipe)
19 * 98/12/29 - Display version info only when -V specified (G M Sipe)
20 */
21
22#include <sys/types.h>
23#include <dirent.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <string.h>
29#include <errno.h>
30#include <sys/param.h>
31#include <sys/stat.h>
32#include "ext2fs/ext2_fs.h"
33
34#ifdef __GNUC__
35# define EXT2FS_ATTR(x) __attribute__(x)
36#else
37# define EXT2FS_ATTR(x)
38#endif
39
40#include "e2fsbb.h"
41#include "e2p/e2p.h"
42
43#define OPT_ADD 1
44#define OPT_REM 2
45#define OPT_SET 4
46#define OPT_SET_VER 8
47static int flags;
48static int recursive;
49
50static unsigned long version;
51
52static unsigned long af;
53static unsigned long rf;
54static unsigned long sf;
55
56struct flags_char {
57 unsigned long flag;
58 char optchar;
59};
60
61static const struct flags_char flags_array[] = {
62 { EXT2_NOATIME_FL, 'A' },
63 { EXT2_SYNC_FL, 'S' },
64 { EXT2_DIRSYNC_FL, 'D' },
65 { EXT2_APPEND_FL, 'a' },
66 { EXT2_COMPR_FL, 'c' },
67 { EXT2_NODUMP_FL, 'd' },
68 { EXT2_IMMUTABLE_FL, 'i' },
69 { EXT3_JOURNAL_DATA_FL, 'j' },
70 { EXT2_SECRM_FL, 's' },
71 { EXT2_UNRM_FL, 'u' },
72 { EXT2_NOTAIL_FL, 't' },
73 { EXT2_TOPDIR_FL, 'T' },
74 { 0, 0 }
75};
76
77static unsigned long get_flag(char c)
78{
79 const struct flags_char *fp;
80 for (fp = flags_array; fp->flag; fp++)
81 if (fp->optchar == c)
82 return fp->flag;
83 bb_show_usage();
84 return 0;
85}
86
87static int decode_arg(char *arg)
88{
89 unsigned long *fl;
90 char opt = *arg++;
91
92 if (opt == '-') {
93 flags |= OPT_REM;
94 fl = &rf;
95 } else if (opt == '+') {
96 flags |= OPT_ADD;
97 fl = &af;
98 } else if (opt == '=') {
99 flags |= OPT_SET;
100 fl = &sf;
101 } else
102 return EOF;
103
104 for (; *arg ; ++arg)
105 (*fl) |= get_flag(*arg);
106
107 return 1;
108}
109
110static int chattr_dir_proc(const char *, struct dirent *, void *);
111
112static void change_attributes(const char * name)
113{
114 unsigned long fsflags;
115 struct stat st;
116
117 if (lstat(name, &st) == -1) {
118 bb_error_msg("stat %s failed", name);
119 return;
120 }
121 if (S_ISLNK(st.st_mode) && recursive)
122 return;
123
124 /* Don't try to open device files, fifos etc. We probably
125 * ought to display an error if the file was explicitly given
126 * on the command line (whether or not recursive was
127 * requested). */
128 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
129 return;
130
131 if (flags & OPT_SET_VER)
132 if (fsetversion(name, version) == -1)
133 bb_error_msg("setting version on %s", name);
134
135 if (flags & OPT_SET) {
136 fsflags = sf;
137 } else {
138 if (fgetflags(name, &fsflags) == -1) {
139 bb_error_msg("reading flags on %s", name);
140 goto skip_setflags;
141 }
142 if (flags & OPT_REM)
143 fsflags &= ~rf;
144 if (flags & OPT_ADD)
145 fsflags |= af;
146 if (!S_ISDIR(st.st_mode))
147 fsflags &= ~EXT2_DIRSYNC_FL;
148 }
149 if (fsetflags(name, fsflags) == -1)
150 bb_error_msg("setting flags on %s", name);
151
152skip_setflags:
153 if (S_ISDIR(st.st_mode) && recursive)
154 iterate_on_dir(name, chattr_dir_proc, NULL);
155}
156
157static int chattr_dir_proc(const char *dir_name, struct dirent *de,
158 void *private EXT2FS_ATTR((unused)))
159{
160 /*if (strcmp(de->d_name, ".") || strcmp(de->d_name, "..")) {*/
161 if (de->d_name[0] == '.'
162 && (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2]))
163 ) {
164 char *path = concat_subpath_file(dir_name, de->d_name);
165 if (path) {
166 change_attributes(path);
167 free(path);
168 }
169 }
170 return 0;
171}
172
173int chattr_main(int argc, char **argv)
174{
175 int i;
176 char *arg;
177
178 /* parse the args */
179 for (i = 1; i < argc; ++i) {
180 arg = argv[i];
181
182 /* take care of -R and -v <version> */
183 if (arg[0] == '-') {
184 if (arg[1] == 'R' && arg[2] == '\0') {
185 recursive = 1;
186 continue;
187 } else if (arg[1] == 'v' && arg[2] == '\0') {
188 char *tmp;
189 ++i;
190 if (i >= argc)
191 bb_show_usage();
192 version = strtol(argv[i], &tmp, 0);
193 if (*tmp)
194 bb_error_msg_and_die("bad version '%s'", arg);
195 flags |= OPT_SET_VER;
196 continue;
197 }
198 }
199
200 if (decode_arg(arg) == EOF)
201 break;
202 }
203
204 /* run sanity checks on all the arguments given us */
205 if (i >= argc)
206 bb_show_usage();
207 if ((flags & OPT_SET) && ((flags & OPT_ADD) || (flags & OPT_REM)))
208 bb_error_msg_and_die("= is incompatible with - and +");
209 if ((rf & af) != 0)
210 bb_error_msg_and_die("Can't set and unset a flag");
211 if (!flags)
212 bb_error_msg_and_die("Must use '-v', =, - or +");
213
214 /* now run chattr on all the files passed to us */
215 while (i < argc)
216 change_attributes(argv[i++]);
217
218 return EXIT_SUCCESS;
219}
diff --git a/e2fsprogs/old_e2fsprogs/e2fsbb.h b/e2fsprogs/old_e2fsprogs/e2fsbb.h
new file mode 100644
index 000000000..78e7cbd04
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2fsbb.h
@@ -0,0 +1,43 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * File: e2fsbb.h
4 *
5 * Redefine a bunch of e2fsprogs stuff to use busybox routines
6 * instead. This makes upgrade between e2fsprogs versions easy.
7 */
8
9#ifndef __E2FSBB_H__
10#define __E2FSBB_H__ 1
11
12#include "libbb.h"
13
14/* version we've last synced against */
15#define E2FSPROGS_VERSION "1.38"
16#define E2FSPROGS_DATE "30-Jun-2005"
17
18typedef long errcode_t;
19#define ERRCODE_RANGE 8
20#define error_message(code) strerror((int) (code & ((1<<ERRCODE_RANGE)-1)))
21
22/* header defines */
23#define ENABLE_HTREE 1
24#define HAVE_ERRNO_H 1
25#define HAVE_EXT2_IOCTLS 1
26#define HAVE_LINUX_FD_H 1
27#define HAVE_MNTENT_H 1
28#define HAVE_NETINET_IN_H 1
29#define HAVE_NET_IF_H 1
30#define HAVE_SYS_IOCTL_H 1
31#define HAVE_SYS_MOUNT_H 1
32#define HAVE_SYS_QUEUE_H 1
33#define HAVE_SYS_STAT_H 1
34#define HAVE_SYS_TYPES_H 1
35#define HAVE_UNISTD_H 1
36
37/* Endianness */
38#if BB_BIG_ENDIAN
39#define ENABLE_SWAPFS 1
40#define WORDS_BIGENDIAN 1
41#endif
42
43#endif /* __E2FSBB_H__ */
diff --git a/e2fsprogs/old_e2fsprogs/e2fsck.c b/e2fsprogs/old_e2fsprogs/e2fsck.c
new file mode 100644
index 000000000..408b2758d
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2fsck.c
@@ -0,0 +1,13552 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * e2fsck
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
6 * Copyright (C) 2006 Garrett Kajmowicz
7 *
8 * Dictionary Abstract Data Type
9 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
10 * Free Software License:
11 * All rights are reserved by the author, with the following exceptions:
12 * Permission is granted to freely reproduce and distribute this software,
13 * possibly in exchange for a fee, provided that this copyright notice appears
14 * intact. Permission is also granted to adapt this software to produce
15 * derivative works, as long as the modified versions carry this copyright
16 * notice and additional notices stating that the work has been modified.
17 * This source code may be translated into executable form and incorporated
18 * into proprietary software; there is no requirement for such software to
19 * contain a copyright notice related to this source.
20 *
21 * linux/fs/recovery and linux/fs/revoke
22 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
23 *
24 * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
25 *
26 * Journal recovery routines for the generic filesystem journaling code;
27 * part of the ext2fs journaling system.
28 *
29 * Licensed under GPLv2 or later, see file License in this tarball for details.
30 */
31
32#ifndef _GNU_SOURCE
33#define _GNU_SOURCE 1 /* get strnlen() */
34#endif
35
36#include "e2fsck.h" /*Put all of our defines here to clean things up*/
37
38#define _(x) x
39#define N_(x) x
40
41/*
42 * Procedure declarations
43 */
44
45static void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf);
46
47/* pass1.c */
48static void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
49
50/* pass2.c */
51static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
52 ext2_ino_t ino, char *buf);
53
54/* pass3.c */
55static int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
56static errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
57 int num, int gauranteed_size);
58static ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix);
59static errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino,
60 int adj);
61
62/* rehash.c */
63static void e2fsck_rehash_directories(e2fsck_t ctx);
64
65/* util.c */
66static void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
67 const char *description);
68static int ask(e2fsck_t ctx, const char * string, int def);
69static void e2fsck_read_bitmaps(e2fsck_t ctx);
70static void preenhalt(e2fsck_t ctx);
71static void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
72 struct ext2_inode * inode, const char * proc);
73static void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
74 struct ext2_inode * inode, const char * proc);
75static blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs,
76 const char *name, io_manager manager);
77
78/* unix.c */
79static void e2fsck_clear_progbar(e2fsck_t ctx);
80static int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
81 float percent, unsigned int dpynum);
82
83
84/*
85 * problem.h --- e2fsck problem error codes
86 */
87
88typedef __u32 problem_t;
89
90struct problem_context {
91 errcode_t errcode;
92 ext2_ino_t ino, ino2, dir;
93 struct ext2_inode *inode;
94 struct ext2_dir_entry *dirent;
95 blk_t blk, blk2;
96 e2_blkcnt_t blkcount;
97 int group;
98 __u64 num;
99 const char *str;
100};
101
102
103/*
104 * Function declarations
105 */
106static int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx);
107static int end_problem_latch(e2fsck_t ctx, int mask);
108static int set_latch_flags(int mask, int setflags, int clearflags);
109static void clear_problem_context(struct problem_context *ctx);
110
111/*
112 * Dictionary Abstract Data Type
113 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
114 *
115 * dict.h v 1.22.2.6 2000/11/13 01:36:44 kaz
116 * kazlib_1_20
117 */
118
119#ifndef DICT_H
120#define DICT_H
121
122/*
123 * Blurb for inclusion into C++ translation units
124 */
125
126typedef unsigned long dictcount_t;
127#define DICTCOUNT_T_MAX ULONG_MAX
128
129/*
130 * The dictionary is implemented as a red-black tree
131 */
132
133typedef enum { dnode_red, dnode_black } dnode_color_t;
134
135typedef struct dnode_t {
136 struct dnode_t *dict_left;
137 struct dnode_t *dict_right;
138 struct dnode_t *dict_parent;
139 dnode_color_t dict_color;
140 const void *dict_key;
141 void *dict_data;
142} dnode_t;
143
144typedef int (*dict_comp_t)(const void *, const void *);
145typedef void (*dnode_free_t)(dnode_t *);
146
147typedef struct dict_t {
148 dnode_t dict_nilnode;
149 dictcount_t dict_nodecount;
150 dictcount_t dict_maxcount;
151 dict_comp_t dict_compare;
152 dnode_free_t dict_freenode;
153 int dict_dupes;
154} dict_t;
155
156typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
157
158typedef struct dict_load_t {
159 dict_t *dict_dictptr;
160 dnode_t dict_nilnode;
161} dict_load_t;
162
163#define dict_count(D) ((D)->dict_nodecount)
164#define dnode_get(N) ((N)->dict_data)
165#define dnode_getkey(N) ((N)->dict_key)
166
167#endif
168
169/*
170 * Compatibility header file for e2fsck which should be included
171 * instead of linux/jfs.h
172 *
173 * Copyright (C) 2000 Stephen C. Tweedie
174 */
175
176/*
177 * Pull in the definition of the e2fsck context structure
178 */
179
180struct buffer_head {
181 char b_data[8192];
182 e2fsck_t b_ctx;
183 io_channel b_io;
184 int b_size;
185 blk_t b_blocknr;
186 int b_dirty;
187 int b_uptodate;
188 int b_err;
189};
190
191
192#define K_DEV_FS 1
193#define K_DEV_JOURNAL 2
194
195#define lock_buffer(bh) do {} while(0)
196#define unlock_buffer(bh) do {} while(0)
197#define buffer_req(bh) 1
198#define do_readahead(journal, start) do {} while(0)
199
200static e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
201
202typedef struct {
203 int object_length;
204} kmem_cache_t;
205
206#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length)
207
208/*
209 * We use the standard libext2fs portability tricks for inline
210 * functions.
211 */
212
213static kmem_cache_t * do_cache_create(int len)
214{
215 kmem_cache_t *new_cache;
216
217 new_cache = malloc(sizeof(*new_cache));
218 if (new_cache)
219 new_cache->object_length = len;
220 return new_cache;
221}
222
223static void do_cache_destroy(kmem_cache_t *cache)
224{
225 free(cache);
226}
227
228
229/*
230 * Dictionary Abstract Data Type
231 */
232
233
234/*
235 * These macros provide short convenient names for structure members,
236 * which are embellished with dict_ prefixes so that they are
237 * properly confined to the documented namespace. It's legal for a
238 * program which uses dict to define, for instance, a macro called ``parent''.
239 * Such a macro would interfere with the dnode_t struct definition.
240 * In general, highly portable and reusable C modules which expose their
241 * structures need to confine structure member names to well-defined spaces.
242 * The resulting identifiers aren't necessarily convenient to use, nor
243 * readable, in the implementation, however!
244 */
245
246#define left dict_left
247#define right dict_right
248#define parent dict_parent
249#define color dict_color
250#define key dict_key
251#define data dict_data
252
253#define nilnode dict_nilnode
254#define maxcount dict_maxcount
255#define compare dict_compare
256#define dupes dict_dupes
257
258#define dict_root(D) ((D)->nilnode.left)
259#define dict_nil(D) (&(D)->nilnode)
260
261static void dnode_free(dnode_t *node);
262
263/*
264 * Perform a ``left rotation'' adjustment on the tree. The given node P and
265 * its right child C are rearranged so that the P instead becomes the left
266 * child of C. The left subtree of C is inherited as the new right subtree
267 * for P. The ordering of the keys within the tree is thus preserved.
268 */
269
270static void rotate_left(dnode_t *upper)
271{
272 dnode_t *lower, *lowleft, *upparent;
273
274 lower = upper->right;
275 upper->right = lowleft = lower->left;
276 lowleft->parent = upper;
277
278 lower->parent = upparent = upper->parent;
279
280 /* don't need to check for root node here because root->parent is
281 the sentinel nil node, and root->parent->left points back to root */
282
283 if (upper == upparent->left) {
284 upparent->left = lower;
285 } else {
286 assert (upper == upparent->right);
287 upparent->right = lower;
288 }
289
290 lower->left = upper;
291 upper->parent = lower;
292}
293
294/*
295 * This operation is the ``mirror'' image of rotate_left. It is
296 * the same procedure, but with left and right interchanged.
297 */
298
299static void rotate_right(dnode_t *upper)
300{
301 dnode_t *lower, *lowright, *upparent;
302
303 lower = upper->left;
304 upper->left = lowright = lower->right;
305 lowright->parent = upper;
306
307 lower->parent = upparent = upper->parent;
308
309 if (upper == upparent->right) {
310 upparent->right = lower;
311 } else {
312 assert (upper == upparent->left);
313 upparent->left = lower;
314 }
315
316 lower->right = upper;
317 upper->parent = lower;
318}
319
320/*
321 * Do a postorder traversal of the tree rooted at the specified
322 * node and free everything under it. Used by dict_free().
323 */
324
325static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
326{
327 if (node == nil)
328 return;
329 free_nodes(dict, node->left, nil);
330 free_nodes(dict, node->right, nil);
331 dict->dict_freenode(node);
332}
333
334/*
335 * Verify that the tree contains the given node. This is done by
336 * traversing all of the nodes and comparing their pointers to the
337 * given pointer. Returns 1 if the node is found, otherwise
338 * returns zero. It is intended for debugging purposes.
339 */
340
341static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
342{
343 if (root != nil) {
344 return root == node
345 || verify_dict_has_node(nil, root->left, node)
346 || verify_dict_has_node(nil, root->right, node);
347 }
348 return 0;
349}
350
351
352/*
353 * Select a different set of node allocator routines.
354 */
355
356static void dict_set_allocator(dict_t *dict, dnode_free_t fr)
357{
358 assert (dict_count(dict) == 0);
359 dict->dict_freenode = fr;
360}
361
362/*
363 * Free all the nodes in the dictionary by using the dictionary's
364 * installed free routine. The dictionary is emptied.
365 */
366
367static void dict_free_nodes(dict_t *dict)
368{
369 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
370 free_nodes(dict, root, nil);
371 dict->dict_nodecount = 0;
372 dict->nilnode.left = &dict->nilnode;
373 dict->nilnode.right = &dict->nilnode;
374}
375
376/*
377 * Initialize a user-supplied dictionary object.
378 */
379
380static dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
381{
382 dict->compare = comp;
383 dict->dict_freenode = dnode_free;
384 dict->dict_nodecount = 0;
385 dict->maxcount = maxcount;
386 dict->nilnode.left = &dict->nilnode;
387 dict->nilnode.right = &dict->nilnode;
388 dict->nilnode.parent = &dict->nilnode;
389 dict->nilnode.color = dnode_black;
390 dict->dupes = 0;
391 return dict;
392}
393
394/*
395 * Locate a node in the dictionary having the given key.
396 * If the node is not found, a null a pointer is returned (rather than
397 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
398 * located node is returned.
399 */
400
401static dnode_t *dict_lookup(dict_t *dict, const void *key)
402{
403 dnode_t *root = dict_root(dict);
404 dnode_t *nil = dict_nil(dict);
405 dnode_t *saved;
406 int result;
407
408 /* simple binary search adapted for trees that contain duplicate keys */
409
410 while (root != nil) {
411 result = dict->compare(key, root->key);
412 if (result < 0)
413 root = root->left;
414 else if (result > 0)
415 root = root->right;
416 else {
417 if (!dict->dupes) { /* no duplicates, return match */
418 return root;
419 } else { /* could be dupes, find leftmost one */
420 do {
421 saved = root;
422 root = root->left;
423 while (root != nil && dict->compare(key, root->key))
424 root = root->right;
425 } while (root != nil);
426 return saved;
427 }
428 }
429 }
430
431 return NULL;
432}
433
434/*
435 * Insert a node into the dictionary. The node should have been
436 * initialized with a data field. All other fields are ignored.
437 * The behavior is undefined if the user attempts to insert into
438 * a dictionary that is already full (for which the dict_isfull()
439 * function returns true).
440 */
441
442static void dict_insert(dict_t *dict, dnode_t *node, const void *key)
443{
444 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
445 dnode_t *parent = nil, *uncle, *grandpa;
446 int result = -1;
447
448 node->key = key;
449
450 /* basic binary tree insert */
451
452 while (where != nil) {
453 parent = where;
454 result = dict->compare(key, where->key);
455 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
456 assert (dict->dupes || result != 0);
457 if (result < 0)
458 where = where->left;
459 else
460 where = where->right;
461 }
462
463 assert (where == nil);
464
465 if (result < 0)
466 parent->left = node;
467 else
468 parent->right = node;
469
470 node->parent = parent;
471 node->left = nil;
472 node->right = nil;
473
474 dict->dict_nodecount++;
475
476 /* red black adjustments */
477
478 node->color = dnode_red;
479
480 while (parent->color == dnode_red) {
481 grandpa = parent->parent;
482 if (parent == grandpa->left) {
483 uncle = grandpa->right;
484 if (uncle->color == dnode_red) { /* red parent, red uncle */
485 parent->color = dnode_black;
486 uncle->color = dnode_black;
487 grandpa->color = dnode_red;
488 node = grandpa;
489 parent = grandpa->parent;
490 } else { /* red parent, black uncle */
491 if (node == parent->right) {
492 rotate_left(parent);
493 parent = node;
494 assert (grandpa == parent->parent);
495 /* rotation between parent and child preserves grandpa */
496 }
497 parent->color = dnode_black;
498 grandpa->color = dnode_red;
499 rotate_right(grandpa);
500 break;
501 }
502 } else { /* symmetric cases: parent == parent->parent->right */
503 uncle = grandpa->left;
504 if (uncle->color == dnode_red) {
505 parent->color = dnode_black;
506 uncle->color = dnode_black;
507 grandpa->color = dnode_red;
508 node = grandpa;
509 parent = grandpa->parent;
510 } else {
511 if (node == parent->left) {
512 rotate_right(parent);
513 parent = node;
514 assert (grandpa == parent->parent);
515 }
516 parent->color = dnode_black;
517 grandpa->color = dnode_red;
518 rotate_left(grandpa);
519 break;
520 }
521 }
522 }
523
524 dict_root(dict)->color = dnode_black;
525
526}
527
528/*
529 * Allocate a node using the dictionary's allocator routine, give it
530 * the data item.
531 */
532
533static dnode_t *dnode_init(dnode_t *dnode, void *data)
534{
535 dnode->data = data;
536 dnode->parent = NULL;
537 dnode->left = NULL;
538 dnode->right = NULL;
539 return dnode;
540}
541
542static int dict_alloc_insert(dict_t *dict, const void *key, void *data)
543{
544 dnode_t *node = malloc(sizeof(dnode_t));
545
546 if (node) {
547 dnode_init(node, data);
548 dict_insert(dict, node, key);
549 return 1;
550 }
551 return 0;
552}
553
554/*
555 * Return the node with the lowest (leftmost) key. If the dictionary is empty
556 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
557 */
558
559static dnode_t *dict_first(dict_t *dict)
560{
561 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
562
563 if (root != nil)
564 while ((left = root->left) != nil)
565 root = left;
566
567 return (root == nil) ? NULL : root;
568}
569
570/*
571 * Return the given node's successor node---the node which has the
572 * next key in the the left to right ordering. If the node has
573 * no successor, a null pointer is returned rather than a pointer to
574 * the nil node.
575 */
576
577static dnode_t *dict_next(dict_t *dict, dnode_t *curr)
578{
579 dnode_t *nil = dict_nil(dict), *parent, *left;
580
581 if (curr->right != nil) {
582 curr = curr->right;
583 while ((left = curr->left) != nil)
584 curr = left;
585 return curr;
586 }
587
588 parent = curr->parent;
589
590 while (parent != nil && curr == parent->right) {
591 curr = parent;
592 parent = curr->parent;
593 }
594
595 return (parent == nil) ? NULL : parent;
596}
597
598
599static void dnode_free(dnode_t *node)
600{
601 free(node);
602}
603
604
605#undef left
606#undef right
607#undef parent
608#undef color
609#undef key
610#undef data
611
612#undef nilnode
613#undef maxcount
614#undef compare
615#undef dupes
616
617
618/*
619 * dirinfo.c --- maintains the directory information table for e2fsck.
620 */
621
622/*
623 * This subroutine is called during pass1 to create a directory info
624 * entry. During pass1, the passed-in parent is 0; it will get filled
625 * in during pass2.
626 */
627static void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
628{
629 struct dir_info *dir;
630 int i, j;
631 ext2_ino_t num_dirs;
632 errcode_t retval;
633 unsigned long old_size;
634
635 if (!ctx->dir_info) {
636 ctx->dir_info_count = 0;
637 retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
638 if (retval)
639 num_dirs = 1024; /* Guess */
640 ctx->dir_info_size = num_dirs + 10;
641 ctx->dir_info = (struct dir_info *)
642 e2fsck_allocate_memory(ctx, ctx->dir_info_size
643 * sizeof (struct dir_info),
644 "directory map");
645 }
646
647 if (ctx->dir_info_count >= ctx->dir_info_size) {
648 old_size = ctx->dir_info_size * sizeof(struct dir_info);
649 ctx->dir_info_size += 10;
650 retval = ext2fs_resize_mem(old_size, ctx->dir_info_size *
651 sizeof(struct dir_info),
652 &ctx->dir_info);
653 if (retval) {
654 ctx->dir_info_size -= 10;
655 return;
656 }
657 }
658
659 /*
660 * Normally, add_dir_info is called with each inode in
661 * sequential order; but once in a while (like when pass 3
662 * needs to recreate the root directory or lost+found
663 * directory) it is called out of order. In those cases, we
664 * need to move the dir_info entries down to make room, since
665 * the dir_info array needs to be sorted by inode number for
666 * get_dir_info()'s sake.
667 */
668 if (ctx->dir_info_count &&
669 ctx->dir_info[ctx->dir_info_count-1].ino >= ino) {
670 for (i = ctx->dir_info_count-1; i > 0; i--)
671 if (ctx->dir_info[i-1].ino < ino)
672 break;
673 dir = &ctx->dir_info[i];
674 if (dir->ino != ino)
675 for (j = ctx->dir_info_count++; j > i; j--)
676 ctx->dir_info[j] = ctx->dir_info[j-1];
677 } else
678 dir = &ctx->dir_info[ctx->dir_info_count++];
679
680 dir->ino = ino;
681 dir->dotdot = parent;
682 dir->parent = parent;
683}
684
685/*
686 * get_dir_info() --- given an inode number, try to find the directory
687 * information entry for it.
688 */
689static struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)
690{
691 int low, high, mid;
692
693 low = 0;
694 high = ctx->dir_info_count-1;
695 if (!ctx->dir_info)
696 return 0;
697 if (ino == ctx->dir_info[low].ino)
698 return &ctx->dir_info[low];
699 if (ino == ctx->dir_info[high].ino)
700 return &ctx->dir_info[high];
701
702 while (low < high) {
703 mid = (low+high)/2;
704 if (mid == low || mid == high)
705 break;
706 if (ino == ctx->dir_info[mid].ino)
707 return &ctx->dir_info[mid];
708 if (ino < ctx->dir_info[mid].ino)
709 high = mid;
710 else
711 low = mid;
712 }
713 return 0;
714}
715
716/*
717 * Free the dir_info structure when it isn't needed any more.
718 */
719static void e2fsck_free_dir_info(e2fsck_t ctx)
720{
721 ext2fs_free_mem(&ctx->dir_info);
722 ctx->dir_info_size = 0;
723 ctx->dir_info_count = 0;
724}
725
726/*
727 * Return the count of number of directories in the dir_info structure
728 */
729static int e2fsck_get_num_dirinfo(e2fsck_t ctx)
730{
731 return ctx->dir_info_count;
732}
733
734/*
735 * A simple interator function
736 */
737static struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
738{
739 if (*control >= ctx->dir_info_count)
740 return 0;
741
742 return ctx->dir_info + (*control)++;
743}
744
745/*
746 * dirinfo.c --- maintains the directory information table for e2fsck.
747 *
748 */
749
750#ifdef ENABLE_HTREE
751
752/*
753 * This subroutine is called during pass1 to create a directory info
754 * entry. During pass1, the passed-in parent is 0; it will get filled
755 * in during pass2.
756 */
757static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
758{
759 struct dx_dir_info *dir;
760 int i, j;
761 errcode_t retval;
762 unsigned long old_size;
763
764 if (!ctx->dx_dir_info) {
765 ctx->dx_dir_info_count = 0;
766 ctx->dx_dir_info_size = 100; /* Guess */
767 ctx->dx_dir_info = (struct dx_dir_info *)
768 e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
769 * sizeof (struct dx_dir_info),
770 "directory map");
771 }
772
773 if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
774 old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
775 ctx->dx_dir_info_size += 10;
776 retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
777 sizeof(struct dx_dir_info),
778 &ctx->dx_dir_info);
779 if (retval) {
780 ctx->dx_dir_info_size -= 10;
781 return;
782 }
783 }
784
785 /*
786 * Normally, add_dx_dir_info is called with each inode in
787 * sequential order; but once in a while (like when pass 3
788 * needs to recreate the root directory or lost+found
789 * directory) it is called out of order. In those cases, we
790 * need to move the dx_dir_info entries down to make room, since
791 * the dx_dir_info array needs to be sorted by inode number for
792 * get_dx_dir_info()'s sake.
793 */
794 if (ctx->dx_dir_info_count &&
795 ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
796 for (i = ctx->dx_dir_info_count-1; i > 0; i--)
797 if (ctx->dx_dir_info[i-1].ino < ino)
798 break;
799 dir = &ctx->dx_dir_info[i];
800 if (dir->ino != ino)
801 for (j = ctx->dx_dir_info_count++; j > i; j--)
802 ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
803 } else
804 dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
805
806 dir->ino = ino;
807 dir->numblocks = num_blocks;
808 dir->hashversion = 0;
809 dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
810 * sizeof (struct dx_dirblock_info),
811 "dx_block info array");
812
813}
814
815/*
816 * get_dx_dir_info() --- given an inode number, try to find the directory
817 * information entry for it.
818 */
819static struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino)
820{
821 int low, high, mid;
822
823 low = 0;
824 high = ctx->dx_dir_info_count-1;
825 if (!ctx->dx_dir_info)
826 return 0;
827 if (ino == ctx->dx_dir_info[low].ino)
828 return &ctx->dx_dir_info[low];
829 if (ino == ctx->dx_dir_info[high].ino)
830 return &ctx->dx_dir_info[high];
831
832 while (low < high) {
833 mid = (low+high)/2;
834 if (mid == low || mid == high)
835 break;
836 if (ino == ctx->dx_dir_info[mid].ino)
837 return &ctx->dx_dir_info[mid];
838 if (ino < ctx->dx_dir_info[mid].ino)
839 high = mid;
840 else
841 low = mid;
842 }
843 return 0;
844}
845
846/*
847 * Free the dx_dir_info structure when it isn't needed any more.
848 */
849static void e2fsck_free_dx_dir_info(e2fsck_t ctx)
850{
851 int i;
852 struct dx_dir_info *dir;
853
854 if (ctx->dx_dir_info) {
855 dir = ctx->dx_dir_info;
856 for (i=0; i < ctx->dx_dir_info_count; i++) {
857 ext2fs_free_mem(&dir->dx_block);
858 }
859 ext2fs_free_mem(&ctx->dx_dir_info);
860 }
861 ctx->dx_dir_info_size = 0;
862 ctx->dx_dir_info_count = 0;
863}
864
865/*
866 * A simple interator function
867 */
868static struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
869{
870 if (*control >= ctx->dx_dir_info_count)
871 return 0;
872
873 return ctx->dx_dir_info + (*control)++;
874}
875
876#endif /* ENABLE_HTREE */
877/*
878 * e2fsck.c - a consistency checker for the new extended file system.
879 *
880 */
881
882/*
883 * This function allocates an e2fsck context
884 */
885static errcode_t e2fsck_allocate_context(e2fsck_t *ret)
886{
887 e2fsck_t context;
888 errcode_t retval;
889
890 retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
891 if (retval)
892 return retval;
893
894 memset(context, 0, sizeof(struct e2fsck_struct));
895
896 context->process_inode_size = 256;
897 context->ext_attr_ver = 2;
898
899 *ret = context;
900 return 0;
901}
902
903struct ea_refcount_el {
904 blk_t ea_blk;
905 int ea_count;
906};
907
908struct ea_refcount {
909 blk_t count;
910 blk_t size;
911 blk_t cursor;
912 struct ea_refcount_el *list;
913};
914
915static void ea_refcount_free(ext2_refcount_t refcount)
916{
917 if (!refcount)
918 return;
919
920 ext2fs_free_mem(&refcount->list);
921 ext2fs_free_mem(&refcount);
922}
923
924/*
925 * This function resets an e2fsck context; it is called when e2fsck
926 * needs to be restarted.
927 */
928static errcode_t e2fsck_reset_context(e2fsck_t ctx)
929{
930 ctx->flags = 0;
931 ctx->lost_and_found = 0;
932 ctx->bad_lost_and_found = 0;
933 ext2fs_free_inode_bitmap(ctx->inode_used_map);
934 ctx->inode_used_map = 0;
935 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
936 ctx->inode_dir_map = 0;
937 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
938 ctx->inode_reg_map = 0;
939 ext2fs_free_block_bitmap(ctx->block_found_map);
940 ctx->block_found_map = 0;
941 ext2fs_free_icount(ctx->inode_link_info);
942 ctx->inode_link_info = 0;
943 if (ctx->journal_io) {
944 if (ctx->fs && ctx->fs->io != ctx->journal_io)
945 io_channel_close(ctx->journal_io);
946 ctx->journal_io = 0;
947 }
948 if (ctx->fs) {
949 ext2fs_free_dblist(ctx->fs->dblist);
950 ctx->fs->dblist = 0;
951 }
952 e2fsck_free_dir_info(ctx);
953#ifdef ENABLE_HTREE
954 e2fsck_free_dx_dir_info(ctx);
955#endif
956 ea_refcount_free(ctx->refcount);
957 ctx->refcount = 0;
958 ea_refcount_free(ctx->refcount_extra);
959 ctx->refcount_extra = 0;
960 ext2fs_free_block_bitmap(ctx->block_dup_map);
961 ctx->block_dup_map = 0;
962 ext2fs_free_block_bitmap(ctx->block_ea_map);
963 ctx->block_ea_map = 0;
964 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
965 ctx->inode_bad_map = 0;
966 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
967 ctx->inode_imagic_map = 0;
968 ext2fs_u32_list_free(ctx->dirs_to_hash);
969 ctx->dirs_to_hash = 0;
970
971 /*
972 * Clear the array of invalid meta-data flags
973 */
974 ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
975 ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
976 ext2fs_free_mem(&ctx->invalid_inode_table_flag);
977
978 /* Clear statistic counters */
979 ctx->fs_directory_count = 0;
980 ctx->fs_regular_count = 0;
981 ctx->fs_blockdev_count = 0;
982 ctx->fs_chardev_count = 0;
983 ctx->fs_links_count = 0;
984 ctx->fs_symlinks_count = 0;
985 ctx->fs_fast_symlinks_count = 0;
986 ctx->fs_fifo_count = 0;
987 ctx->fs_total_count = 0;
988 ctx->fs_sockets_count = 0;
989 ctx->fs_ind_count = 0;
990 ctx->fs_dind_count = 0;
991 ctx->fs_tind_count = 0;
992 ctx->fs_fragmented = 0;
993 ctx->large_files = 0;
994
995 /* Reset the superblock to the user's requested value */
996 ctx->superblock = ctx->use_superblock;
997
998 return 0;
999}
1000
1001static void e2fsck_free_context(e2fsck_t ctx)
1002{
1003 if (!ctx)
1004 return;
1005
1006 e2fsck_reset_context(ctx);
1007 if (ctx->blkid)
1008 blkid_put_cache(ctx->blkid);
1009
1010 ext2fs_free_mem(&ctx);
1011}
1012
1013/*
1014 * ea_refcount.c
1015 */
1016
1017/*
1018 * The strategy we use for keeping track of EA refcounts is as
1019 * follows. We keep a sorted array of first EA blocks and its
1020 * reference counts. Once the refcount has dropped to zero, it is
1021 * removed from the array to save memory space. Once the EA block is
1022 * checked, its bit is set in the block_ea_map bitmap.
1023 */
1024
1025
1026static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
1027{
1028 ext2_refcount_t refcount;
1029 errcode_t retval;
1030 size_t bytes;
1031
1032 retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount);
1033 if (retval)
1034 return retval;
1035 memset(refcount, 0, sizeof(struct ea_refcount));
1036
1037 if (!size)
1038 size = 500;
1039 refcount->size = size;
1040 bytes = (size_t) (size * sizeof(struct ea_refcount_el));
1041#ifdef DEBUG
1042 printf("Refcount allocated %d entries, %d bytes.\n",
1043 refcount->size, bytes);
1044#endif
1045 retval = ext2fs_get_mem(bytes, &refcount->list);
1046 if (retval)
1047 goto errout;
1048 memset(refcount->list, 0, bytes);
1049
1050 refcount->count = 0;
1051 refcount->cursor = 0;
1052
1053 *ret = refcount;
1054 return 0;
1055
1056errout:
1057 ea_refcount_free(refcount);
1058 return retval;
1059}
1060
1061/*
1062 * collapse_refcount() --- go through the refcount array, and get rid
1063 * of any count == zero entries
1064 */
1065static void refcount_collapse(ext2_refcount_t refcount)
1066{
1067 unsigned int i, j;
1068 struct ea_refcount_el *list;
1069
1070 list = refcount->list;
1071 for (i = 0, j = 0; i < refcount->count; i++) {
1072 if (list[i].ea_count) {
1073 if (i != j)
1074 list[j] = list[i];
1075 j++;
1076 }
1077 }
1078#if defined(DEBUG) || defined(TEST_PROGRAM)
1079 printf("Refcount_collapse: size was %d, now %d\n",
1080 refcount->count, j);
1081#endif
1082 refcount->count = j;
1083}
1084
1085
1086/*
1087 * insert_refcount_el() --- Insert a new entry into the sorted list at a
1088 * specified position.
1089 */
1090static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
1091 blk_t blk, int pos)
1092{
1093 struct ea_refcount_el *el;
1094 errcode_t retval;
1095 blk_t new_size = 0;
1096 int num;
1097
1098 if (refcount->count >= refcount->size) {
1099 new_size = refcount->size + 100;
1100#ifdef DEBUG
1101 printf("Reallocating refcount %d entries...\n", new_size);
1102#endif
1103 retval = ext2fs_resize_mem((size_t) refcount->size *
1104 sizeof(struct ea_refcount_el),
1105 (size_t) new_size *
1106 sizeof(struct ea_refcount_el),
1107 &refcount->list);
1108 if (retval)
1109 return 0;
1110 refcount->size = new_size;
1111 }
1112 num = (int) refcount->count - pos;
1113 if (num < 0)
1114 return 0; /* should never happen */
1115 if (num) {
1116 memmove(&refcount->list[pos+1], &refcount->list[pos],
1117 sizeof(struct ea_refcount_el) * num);
1118 }
1119 refcount->count++;
1120 el = &refcount->list[pos];
1121 el->ea_count = 0;
1122 el->ea_blk = blk;
1123 return el;
1124}
1125
1126
1127/*
1128 * get_refcount_el() --- given an block number, try to find refcount
1129 * information in the sorted list. If the create flag is set,
1130 * and we can't find an entry, create one in the sorted list.
1131 */
1132static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
1133 blk_t blk, int create)
1134{
1135 float range;
1136 int low, high, mid;
1137 blk_t lowval, highval;
1138
1139 if (!refcount || !refcount->list)
1140 return 0;
1141retry:
1142 low = 0;
1143 high = (int) refcount->count-1;
1144 if (create && ((refcount->count == 0) ||
1145 (blk > refcount->list[high].ea_blk))) {
1146 if (refcount->count >= refcount->size)
1147 refcount_collapse(refcount);
1148
1149 return insert_refcount_el(refcount, blk,
1150 (unsigned) refcount->count);
1151 }
1152 if (refcount->count == 0)
1153 return 0;
1154
1155 if (refcount->cursor >= refcount->count)
1156 refcount->cursor = 0;
1157 if (blk == refcount->list[refcount->cursor].ea_blk)
1158 return &refcount->list[refcount->cursor++];
1159#ifdef DEBUG
1160 printf("Non-cursor get_refcount_el: %u\n", blk);
1161#endif
1162 while (low <= high) {
1163 if (low == high)
1164 mid = low;
1165 else {
1166 /* Interpolate for efficiency */
1167 lowval = refcount->list[low].ea_blk;
1168 highval = refcount->list[high].ea_blk;
1169
1170 if (blk < lowval)
1171 range = 0;
1172 else if (blk > highval)
1173 range = 1;
1174 else
1175 range = ((float) (blk - lowval)) /
1176 (highval - lowval);
1177 mid = low + ((int) (range * (high-low)));
1178 }
1179
1180 if (blk == refcount->list[mid].ea_blk) {
1181 refcount->cursor = mid+1;
1182 return &refcount->list[mid];
1183 }
1184 if (blk < refcount->list[mid].ea_blk)
1185 high = mid-1;
1186 else
1187 low = mid+1;
1188 }
1189 /*
1190 * If we need to create a new entry, it should be right at
1191 * low (where high will be left at low-1).
1192 */
1193 if (create) {
1194 if (refcount->count >= refcount->size) {
1195 refcount_collapse(refcount);
1196 if (refcount->count < refcount->size)
1197 goto retry;
1198 }
1199 return insert_refcount_el(refcount, blk, low);
1200 }
1201 return 0;
1202}
1203
1204static errcode_t
1205ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret)
1206{
1207 struct ea_refcount_el *el;
1208
1209 el = get_refcount_el(refcount, blk, 1);
1210 if (!el)
1211 return EXT2_ET_NO_MEMORY;
1212 el->ea_count++;
1213
1214 if (ret)
1215 *ret = el->ea_count;
1216 return 0;
1217}
1218
1219static errcode_t
1220ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret)
1221{
1222 struct ea_refcount_el *el;
1223
1224 el = get_refcount_el(refcount, blk, 0);
1225 if (!el || el->ea_count == 0)
1226 return EXT2_ET_INVALID_ARGUMENT;
1227
1228 el->ea_count--;
1229
1230 if (ret)
1231 *ret = el->ea_count;
1232 return 0;
1233}
1234
1235static errcode_t
1236ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count)
1237{
1238 struct ea_refcount_el *el;
1239
1240 /*
1241 * Get the refcount element
1242 */
1243 el = get_refcount_el(refcount, blk, count ? 1 : 0);
1244 if (!el)
1245 return count ? EXT2_ET_NO_MEMORY : 0;
1246 el->ea_count = count;
1247 return 0;
1248}
1249
1250static inline void ea_refcount_intr_begin(ext2_refcount_t refcount)
1251{
1252 refcount->cursor = 0;
1253}
1254
1255
1256static blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret)
1257{
1258 struct ea_refcount_el *list;
1259
1260 while (1) {
1261 if (refcount->cursor >= refcount->count)
1262 return 0;
1263 list = refcount->list;
1264 if (list[refcount->cursor].ea_count) {
1265 if (ret)
1266 *ret = list[refcount->cursor].ea_count;
1267 return list[refcount->cursor++].ea_blk;
1268 }
1269 refcount->cursor++;
1270 }
1271}
1272
1273
1274/*
1275 * ehandler.c --- handle bad block errors which come up during the
1276 * course of an e2fsck session.
1277 */
1278
1279
1280static const char *operation;
1281
1282static errcode_t
1283e2fsck_handle_read_error(io_channel channel, unsigned long block, int count,
1284 void *data, size_t size FSCK_ATTR((unused)),
1285 int actual FSCK_ATTR((unused)), errcode_t error)
1286{
1287 int i;
1288 char *p;
1289 ext2_filsys fs = (ext2_filsys) channel->app_data;
1290 e2fsck_t ctx;
1291
1292 ctx = (e2fsck_t) fs->priv_data;
1293
1294 /*
1295 * If more than one block was read, try reading each block
1296 * separately. We could use the actual bytes read to figure
1297 * out where to start, but we don't bother.
1298 */
1299 if (count > 1) {
1300 p = (char *) data;
1301 for (i=0; i < count; i++, p += channel->block_size, block++) {
1302 error = io_channel_read_blk(channel, block,
1303 1, p);
1304 if (error)
1305 return error;
1306 }
1307 return 0;
1308 }
1309 if (operation)
1310 printf(_("Error reading block %lu (%s) while %s. "), block,
1311 error_message(error), operation);
1312 else
1313 printf(_("Error reading block %lu (%s). "), block,
1314 error_message(error));
1315 preenhalt(ctx);
1316 if (ask(ctx, _("Ignore error"), 1)) {
1317 if (ask(ctx, _("Force rewrite"), 1))
1318 io_channel_write_blk(channel, block, 1, data);
1319 return 0;
1320 }
1321
1322 return error;
1323}
1324
1325static errcode_t
1326e2fsck_handle_write_error(io_channel channel, unsigned long block, int count,
1327 const void *data, size_t size FSCK_ATTR((unused)),
1328 int actual FSCK_ATTR((unused)), errcode_t error)
1329{
1330 int i;
1331 const char *p;
1332 ext2_filsys fs = (ext2_filsys) channel->app_data;
1333 e2fsck_t ctx;
1334
1335 ctx = (e2fsck_t) fs->priv_data;
1336
1337 /*
1338 * If more than one block was written, try writing each block
1339 * separately. We could use the actual bytes read to figure
1340 * out where to start, but we don't bother.
1341 */
1342 if (count > 1) {
1343 p = (const char *) data;
1344 for (i=0; i < count; i++, p += channel->block_size, block++) {
1345 error = io_channel_write_blk(channel, block,
1346 1, p);
1347 if (error)
1348 return error;
1349 }
1350 return 0;
1351 }
1352
1353 if (operation)
1354 printf(_("Error writing block %lu (%s) while %s. "), block,
1355 error_message(error), operation);
1356 else
1357 printf(_("Error writing block %lu (%s). "), block,
1358 error_message(error));
1359 preenhalt(ctx);
1360 if (ask(ctx, _("Ignore error"), 1))
1361 return 0;
1362
1363 return error;
1364}
1365
1366static const char *ehandler_operation(const char *op)
1367{
1368 const char *ret = operation;
1369
1370 operation = op;
1371 return ret;
1372}
1373
1374static void ehandler_init(io_channel channel)
1375{
1376 channel->read_error = e2fsck_handle_read_error;
1377 channel->write_error = e2fsck_handle_write_error;
1378}
1379
1380/*
1381 * journal.c --- code for handling the "ext3" journal
1382 *
1383 * Copyright (C) 2000 Andreas Dilger
1384 * Copyright (C) 2000 Theodore Ts'o
1385 *
1386 * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie
1387 * Copyright (C) 1999 Red Hat Software
1388 *
1389 * This file may be redistributed under the terms of the
1390 * GNU General Public License version 2 or at your discretion
1391 * any later version.
1392 */
1393
1394/*
1395 * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
1396 * This creates a larger static binary, and a smaller binary using
1397 * shared libraries. It's also probably slightly less CPU-efficient,
1398 * which is why it's not on by default. But, it's a good way of
1399 * testing the functions in inode_io.c and fileio.c.
1400 */
1401#undef USE_INODE_IO
1402
1403/* Kernel compatibility functions for handling the journal. These allow us
1404 * to use the recovery.c file virtually unchanged from the kernel, so we
1405 * don't have to do much to keep kernel and user recovery in sync.
1406 */
1407static int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys)
1408{
1409#ifdef USE_INODE_IO
1410 *phys = block;
1411 return 0;
1412#else
1413 struct inode *inode = journal->j_inode;
1414 errcode_t retval;
1415 blk_t pblk;
1416
1417 if (!inode) {
1418 *phys = block;
1419 return 0;
1420 }
1421
1422 retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino,
1423 &inode->i_ext2, NULL, 0, block, &pblk);
1424 *phys = pblk;
1425 return retval;
1426#endif
1427}
1428
1429static struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize)
1430{
1431 struct buffer_head *bh;
1432
1433 bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer");
1434 if (!bh)
1435 return NULL;
1436
1437 bh->b_ctx = kdev->k_ctx;
1438 if (kdev->k_dev == K_DEV_FS)
1439 bh->b_io = kdev->k_ctx->fs->io;
1440 else
1441 bh->b_io = kdev->k_ctx->journal_io;
1442 bh->b_size = blocksize;
1443 bh->b_blocknr = blocknr;
1444
1445 return bh;
1446}
1447
1448static void sync_blockdev(kdev_t kdev)
1449{
1450 io_channel io;
1451
1452 if (kdev->k_dev == K_DEV_FS)
1453 io = kdev->k_ctx->fs->io;
1454 else
1455 io = kdev->k_ctx->journal_io;
1456
1457 io_channel_flush(io);
1458}
1459
1460static void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
1461{
1462 int retval;
1463 struct buffer_head *bh;
1464
1465 for (; nr > 0; --nr) {
1466 bh = *bhp++;
1467 if (rw == READ && !bh->b_uptodate) {
1468 retval = io_channel_read_blk(bh->b_io,
1469 bh->b_blocknr,
1470 1, bh->b_data);
1471 if (retval) {
1472 bb_error_msg("while reading block %lu",
1473 (unsigned long) bh->b_blocknr);
1474 bh->b_err = retval;
1475 continue;
1476 }
1477 bh->b_uptodate = 1;
1478 } else if (rw == WRITE && bh->b_dirty) {
1479 retval = io_channel_write_blk(bh->b_io,
1480 bh->b_blocknr,
1481 1, bh->b_data);
1482 if (retval) {
1483 bb_error_msg("while writing block %lu",
1484 (unsigned long) bh->b_blocknr);
1485 bh->b_err = retval;
1486 continue;
1487 }
1488 bh->b_dirty = 0;
1489 bh->b_uptodate = 1;
1490 }
1491 }
1492}
1493
1494static void mark_buffer_dirty(struct buffer_head *bh)
1495{
1496 bh->b_dirty = 1;
1497}
1498
1499static inline void mark_buffer_clean(struct buffer_head * bh)
1500{
1501 bh->b_dirty = 0;
1502}
1503
1504static void brelse(struct buffer_head *bh)
1505{
1506 if (bh->b_dirty)
1507 ll_rw_block(WRITE, 1, &bh);
1508 ext2fs_free_mem(&bh);
1509}
1510
1511static int buffer_uptodate(struct buffer_head *bh)
1512{
1513 return bh->b_uptodate;
1514}
1515
1516static inline void mark_buffer_uptodate(struct buffer_head *bh, int val)
1517{
1518 bh->b_uptodate = val;
1519}
1520
1521static void wait_on_buffer(struct buffer_head *bh)
1522{
1523 if (!bh->b_uptodate)
1524 ll_rw_block(READ, 1, &bh);
1525}
1526
1527
1528static void e2fsck_clear_recover(e2fsck_t ctx, int error)
1529{
1530 ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
1531
1532 /* if we had an error doing journal recovery, we need a full fsck */
1533 if (error)
1534 ctx->fs->super->s_state &= ~EXT2_VALID_FS;
1535 ext2fs_mark_super_dirty(ctx->fs);
1536}
1537
1538static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
1539{
1540 struct ext2_super_block *sb = ctx->fs->super;
1541 struct ext2_super_block jsuper;
1542 struct problem_context pctx;
1543 struct buffer_head *bh;
1544 struct inode *j_inode = NULL;
1545 struct kdev_s *dev_fs = NULL, *dev_journal;
1546 const char *journal_name = 0;
1547 journal_t *journal = NULL;
1548 errcode_t retval = 0;
1549 io_manager io_ptr = 0;
1550 unsigned long start = 0;
1551 blk_t blk;
1552 int ext_journal = 0;
1553 int tried_backup_jnl = 0;
1554 int i;
1555
1556 clear_problem_context(&pctx);
1557
1558 journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
1559 if (!journal) {
1560 return EXT2_ET_NO_MEMORY;
1561 }
1562
1563 dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
1564 if (!dev_fs) {
1565 retval = EXT2_ET_NO_MEMORY;
1566 goto errout;
1567 }
1568 dev_journal = dev_fs+1;
1569
1570 dev_fs->k_ctx = dev_journal->k_ctx = ctx;
1571 dev_fs->k_dev = K_DEV_FS;
1572 dev_journal->k_dev = K_DEV_JOURNAL;
1573
1574 journal->j_dev = dev_journal;
1575 journal->j_fs_dev = dev_fs;
1576 journal->j_inode = NULL;
1577 journal->j_blocksize = ctx->fs->blocksize;
1578
1579 if (uuid_is_null(sb->s_journal_uuid)) {
1580 if (!sb->s_journal_inum)
1581 return EXT2_ET_BAD_INODE_NUM;
1582 j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
1583 "journal inode");
1584 if (!j_inode) {
1585 retval = EXT2_ET_NO_MEMORY;
1586 goto errout;
1587 }
1588
1589 j_inode->i_ctx = ctx;
1590 j_inode->i_ino = sb->s_journal_inum;
1591
1592 if ((retval = ext2fs_read_inode(ctx->fs,
1593 sb->s_journal_inum,
1594 &j_inode->i_ext2))) {
1595 try_backup_journal:
1596 if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
1597 tried_backup_jnl)
1598 goto errout;
1599 memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
1600 memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
1601 EXT2_N_BLOCKS*4);
1602 j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
1603 j_inode->i_ext2.i_links_count = 1;
1604 j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
1605 tried_backup_jnl++;
1606 }
1607 if (!j_inode->i_ext2.i_links_count ||
1608 !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
1609 retval = EXT2_ET_NO_JOURNAL;
1610 goto try_backup_journal;
1611 }
1612 if (j_inode->i_ext2.i_size / journal->j_blocksize <
1613 JFS_MIN_JOURNAL_BLOCKS) {
1614 retval = EXT2_ET_JOURNAL_TOO_SMALL;
1615 goto try_backup_journal;
1616 }
1617 for (i=0; i < EXT2_N_BLOCKS; i++) {
1618 blk = j_inode->i_ext2.i_block[i];
1619 if (!blk) {
1620 if (i < EXT2_NDIR_BLOCKS) {
1621 retval = EXT2_ET_JOURNAL_TOO_SMALL;
1622 goto try_backup_journal;
1623 }
1624 continue;
1625 }
1626 if (blk < sb->s_first_data_block ||
1627 blk >= sb->s_blocks_count) {
1628 retval = EXT2_ET_BAD_BLOCK_NUM;
1629 goto try_backup_journal;
1630 }
1631 }
1632 journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;
1633
1634#ifdef USE_INODE_IO
1635 retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
1636 &j_inode->i_ext2,
1637 &journal_name);
1638 if (retval)
1639 goto errout;
1640
1641 io_ptr = inode_io_manager;
1642#else
1643 journal->j_inode = j_inode;
1644 ctx->journal_io = ctx->fs->io;
1645 if ((retval = journal_bmap(journal, 0, &start)) != 0)
1646 goto errout;
1647#endif
1648 } else {
1649 ext_journal = 1;
1650 if (!ctx->journal_name) {
1651 char uuid[37];
1652
1653 uuid_unparse(sb->s_journal_uuid, uuid);
1654 ctx->journal_name = blkid_get_devname(ctx->blkid,
1655 "UUID", uuid);
1656 if (!ctx->journal_name)
1657 ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
1658 }
1659 journal_name = ctx->journal_name;
1660
1661 if (!journal_name) {
1662 fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
1663 return EXT2_ET_LOAD_EXT_JOURNAL;
1664 }
1665
1666 io_ptr = unix_io_manager;
1667 }
1668
1669#ifndef USE_INODE_IO
1670 if (ext_journal)
1671#endif
1672 retval = io_ptr->open(journal_name, IO_FLAG_RW,
1673 &ctx->journal_io);
1674 if (retval)
1675 goto errout;
1676
1677 io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
1678
1679 if (ext_journal) {
1680 if (ctx->fs->blocksize == 1024)
1681 start = 1;
1682 bh = getblk(dev_journal, start, ctx->fs->blocksize);
1683 if (!bh) {
1684 retval = EXT2_ET_NO_MEMORY;
1685 goto errout;
1686 }
1687 ll_rw_block(READ, 1, &bh);
1688 if ((retval = bh->b_err) != 0)
1689 goto errout;
1690 memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
1691 sizeof(jsuper));
1692 brelse(bh);
1693#if BB_BIG_ENDIAN
1694 if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
1695 ext2fs_swap_super(&jsuper);
1696#endif
1697 if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
1698 !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
1699 fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
1700 retval = EXT2_ET_LOAD_EXT_JOURNAL;
1701 goto errout;
1702 }
1703 /* Make sure the journal UUID is correct */
1704 if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
1705 sizeof(jsuper.s_uuid))) {
1706 fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
1707 retval = EXT2_ET_LOAD_EXT_JOURNAL;
1708 goto errout;
1709 }
1710
1711 journal->j_maxlen = jsuper.s_blocks_count;
1712 start++;
1713 }
1714
1715 if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
1716 retval = EXT2_ET_NO_MEMORY;
1717 goto errout;
1718 }
1719
1720 journal->j_sb_buffer = bh;
1721 journal->j_superblock = (journal_superblock_t *)bh->b_data;
1722
1723#ifdef USE_INODE_IO
1724 ext2fs_free_mem(&j_inode);
1725#endif
1726
1727 *ret_journal = journal;
1728 return 0;
1729
1730errout:
1731 ext2fs_free_mem(&dev_fs);
1732 ext2fs_free_mem(&j_inode);
1733 ext2fs_free_mem(&journal);
1734 return retval;
1735
1736}
1737
1738static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
1739 struct problem_context *pctx)
1740{
1741 struct ext2_super_block *sb = ctx->fs->super;
1742 int recover = ctx->fs->super->s_feature_incompat &
1743 EXT3_FEATURE_INCOMPAT_RECOVER;
1744 int has_journal = ctx->fs->super->s_feature_compat &
1745 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
1746
1747 if (has_journal || sb->s_journal_inum) {
1748 /* The journal inode is bogus, remove and force full fsck */
1749 pctx->ino = sb->s_journal_inum;
1750 if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
1751 if (has_journal && sb->s_journal_inum)
1752 printf("*** ext3 journal has been deleted - "
1753 "filesystem is now ext2 only ***\n\n");
1754 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
1755 sb->s_journal_inum = 0;
1756 ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */
1757 e2fsck_clear_recover(ctx, 1);
1758 return 0;
1759 }
1760 return EXT2_ET_BAD_INODE_NUM;
1761 } else if (recover) {
1762 if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
1763 e2fsck_clear_recover(ctx, 1);
1764 return 0;
1765 }
1766 return EXT2_ET_UNSUPP_FEATURE;
1767 }
1768 return 0;
1769}
1770
1771#define V1_SB_SIZE 0x0024
1772static void clear_v2_journal_fields(journal_t *journal)
1773{
1774 e2fsck_t ctx = journal->j_dev->k_ctx;
1775 struct problem_context pctx;
1776
1777 clear_problem_context(&pctx);
1778
1779 if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
1780 return;
1781
1782 memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
1783 ctx->fs->blocksize-V1_SB_SIZE);
1784 mark_buffer_dirty(journal->j_sb_buffer);
1785}
1786
1787
1788static errcode_t e2fsck_journal_load(journal_t *journal)
1789{
1790 e2fsck_t ctx = journal->j_dev->k_ctx;
1791 journal_superblock_t *jsb;
1792 struct buffer_head *jbh = journal->j_sb_buffer;
1793 struct problem_context pctx;
1794
1795 clear_problem_context(&pctx);
1796
1797 ll_rw_block(READ, 1, &jbh);
1798 if (jbh->b_err) {
1799 bb_error_msg(_("reading journal superblock"));
1800 return jbh->b_err;
1801 }
1802
1803 jsb = journal->j_superblock;
1804 /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
1805 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
1806 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
1807
1808 switch (ntohl(jsb->s_header.h_blocktype)) {
1809 case JFS_SUPERBLOCK_V1:
1810 journal->j_format_version = 1;
1811 if (jsb->s_feature_compat ||
1812 jsb->s_feature_incompat ||
1813 jsb->s_feature_ro_compat ||
1814 jsb->s_nr_users)
1815 clear_v2_journal_fields(journal);
1816 break;
1817
1818 case JFS_SUPERBLOCK_V2:
1819 journal->j_format_version = 2;
1820 if (ntohl(jsb->s_nr_users) > 1 &&
1821 uuid_is_null(ctx->fs->super->s_journal_uuid))
1822 clear_v2_journal_fields(journal);
1823 if (ntohl(jsb->s_nr_users) > 1) {
1824 fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
1825 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
1826 }
1827 break;
1828
1829 /*
1830 * These should never appear in a journal super block, so if
1831 * they do, the journal is badly corrupted.
1832 */
1833 case JFS_DESCRIPTOR_BLOCK:
1834 case JFS_COMMIT_BLOCK:
1835 case JFS_REVOKE_BLOCK:
1836 return EXT2_ET_CORRUPT_SUPERBLOCK;
1837
1838 /* If we don't understand the superblock major type, but there
1839 * is a magic number, then it is likely to be a new format we
1840 * just don't understand, so leave it alone. */
1841 default:
1842 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
1843 }
1844
1845 if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
1846 return EXT2_ET_UNSUPP_FEATURE;
1847
1848 if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
1849 return EXT2_ET_RO_UNSUPP_FEATURE;
1850
1851 /* We have now checked whether we know enough about the journal
1852 * format to be able to proceed safely, so any other checks that
1853 * fail we should attempt to recover from. */
1854 if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
1855 bb_error_msg(_("%s: no valid journal superblock found"),
1856 ctx->device_name);
1857 return EXT2_ET_CORRUPT_SUPERBLOCK;
1858 }
1859
1860 if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
1861 journal->j_maxlen = ntohl(jsb->s_maxlen);
1862 else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
1863 bb_error_msg(_("%s: journal too short"),
1864 ctx->device_name);
1865 return EXT2_ET_CORRUPT_SUPERBLOCK;
1866 }
1867
1868 journal->j_tail_sequence = ntohl(jsb->s_sequence);
1869 journal->j_transaction_sequence = journal->j_tail_sequence;
1870 journal->j_tail = ntohl(jsb->s_start);
1871 journal->j_first = ntohl(jsb->s_first);
1872 journal->j_last = ntohl(jsb->s_maxlen);
1873
1874 return 0;
1875}
1876
1877static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
1878 journal_t *journal)
1879{
1880 char *p;
1881 union {
1882 uuid_t uuid;
1883 __u32 val[4];
1884 } u;
1885 __u32 new_seq = 0;
1886 int i;
1887
1888 /* Leave a valid existing V1 superblock signature alone.
1889 * Anything unrecognisable we overwrite with a new V2
1890 * signature. */
1891
1892 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
1893 jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
1894 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
1895 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
1896 }
1897
1898 /* Zero out everything else beyond the superblock header */
1899
1900 p = ((char *) jsb) + sizeof(journal_header_t);
1901 memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
1902
1903 jsb->s_blocksize = htonl(ctx->fs->blocksize);
1904 jsb->s_maxlen = htonl(journal->j_maxlen);
1905 jsb->s_first = htonl(1);
1906
1907 /* Initialize the journal sequence number so that there is "no"
1908 * chance we will find old "valid" transactions in the journal.
1909 * This avoids the need to zero the whole journal (slow to do,
1910 * and risky when we are just recovering the filesystem).
1911 */
1912 uuid_generate(u.uuid);
1913 for (i = 0; i < 4; i ++)
1914 new_seq ^= u.val[i];
1915 jsb->s_sequence = htonl(new_seq);
1916
1917 mark_buffer_dirty(journal->j_sb_buffer);
1918 ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
1919}
1920
1921static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
1922 journal_t *journal,
1923 struct problem_context *pctx)
1924{
1925 struct ext2_super_block *sb = ctx->fs->super;
1926 int recover = ctx->fs->super->s_feature_incompat &
1927 EXT3_FEATURE_INCOMPAT_RECOVER;
1928
1929 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
1930 if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
1931 e2fsck_journal_reset_super(ctx, journal->j_superblock,
1932 journal);
1933 journal->j_transaction_sequence = 1;
1934 e2fsck_clear_recover(ctx, recover);
1935 return 0;
1936 }
1937 return EXT2_ET_CORRUPT_SUPERBLOCK;
1938 } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
1939 return EXT2_ET_CORRUPT_SUPERBLOCK;
1940
1941 return 0;
1942}
1943
1944static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
1945 int reset, int drop)
1946{
1947 journal_superblock_t *jsb;
1948
1949 if (drop)
1950 mark_buffer_clean(journal->j_sb_buffer);
1951 else if (!(ctx->options & E2F_OPT_READONLY)) {
1952 jsb = journal->j_superblock;
1953 jsb->s_sequence = htonl(journal->j_transaction_sequence);
1954 if (reset)
1955 jsb->s_start = 0; /* this marks the journal as empty */
1956 mark_buffer_dirty(journal->j_sb_buffer);
1957 }
1958 brelse(journal->j_sb_buffer);
1959
1960 if (ctx->journal_io) {
1961 if (ctx->fs && ctx->fs->io != ctx->journal_io)
1962 io_channel_close(ctx->journal_io);
1963 ctx->journal_io = 0;
1964 }
1965
1966#ifndef USE_INODE_IO
1967 ext2fs_free_mem(&journal->j_inode);
1968#endif
1969 ext2fs_free_mem(&journal->j_fs_dev);
1970 ext2fs_free_mem(&journal);
1971}
1972
1973/*
1974 * This function makes sure that the superblock fields regarding the
1975 * journal are consistent.
1976 */
1977static int e2fsck_check_ext3_journal(e2fsck_t ctx)
1978{
1979 struct ext2_super_block *sb = ctx->fs->super;
1980 journal_t *journal;
1981 int recover = ctx->fs->super->s_feature_incompat &
1982 EXT3_FEATURE_INCOMPAT_RECOVER;
1983 struct problem_context pctx;
1984 problem_t problem;
1985 int reset = 0, force_fsck = 0;
1986 int retval;
1987
1988 /* If we don't have any journal features, don't do anything more */
1989 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
1990 !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
1991 uuid_is_null(sb->s_journal_uuid))
1992 return 0;
1993
1994 clear_problem_context(&pctx);
1995 pctx.num = sb->s_journal_inum;
1996
1997 retval = e2fsck_get_journal(ctx, &journal);
1998 if (retval) {
1999 if ((retval == EXT2_ET_BAD_INODE_NUM) ||
2000 (retval == EXT2_ET_BAD_BLOCK_NUM) ||
2001 (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
2002 (retval == EXT2_ET_NO_JOURNAL))
2003 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
2004 return retval;
2005 }
2006
2007 retval = e2fsck_journal_load(journal);
2008 if (retval) {
2009 if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
2010 ((retval == EXT2_ET_UNSUPP_FEATURE) &&
2011 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
2012 &pctx))) ||
2013 ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
2014 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
2015 &pctx))) ||
2016 ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
2017 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
2018 retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
2019 &pctx);
2020 e2fsck_journal_release(ctx, journal, 0, 1);
2021 return retval;
2022 }
2023
2024 /*
2025 * We want to make the flags consistent here. We will not leave with
2026 * needs_recovery set but has_journal clear. We can't get in a loop
2027 * with -y, -n, or -p, only if a user isn't making up their mind.
2028 */
2029no_has_journal:
2030 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
2031 recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
2032 pctx.str = "inode";
2033 if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
2034 if (recover &&
2035 !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
2036 goto no_has_journal;
2037 /*
2038 * Need a full fsck if we are releasing a
2039 * journal stored on a reserved inode.
2040 */
2041 force_fsck = recover ||
2042 (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
2043 /* Clear all of the journal fields */
2044 sb->s_journal_inum = 0;
2045 sb->s_journal_dev = 0;
2046 memset(sb->s_journal_uuid, 0,
2047 sizeof(sb->s_journal_uuid));
2048 e2fsck_clear_recover(ctx, force_fsck);
2049 } else if (!(ctx->options & E2F_OPT_READONLY)) {
2050 sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
2051 ext2fs_mark_super_dirty(ctx->fs);
2052 }
2053 }
2054
2055 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
2056 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
2057 journal->j_superblock->s_start != 0) {
2058 /* Print status information */
2059 fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
2060 if (ctx->superblock)
2061 problem = PR_0_JOURNAL_RUN_DEFAULT;
2062 else
2063 problem = PR_0_JOURNAL_RUN;
2064 if (fix_problem(ctx, problem, &pctx)) {
2065 ctx->options |= E2F_OPT_FORCE;
2066 sb->s_feature_incompat |=
2067 EXT3_FEATURE_INCOMPAT_RECOVER;
2068 ext2fs_mark_super_dirty(ctx->fs);
2069 } else if (fix_problem(ctx,
2070 PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
2071 reset = 1;
2072 sb->s_state &= ~EXT2_VALID_FS;
2073 ext2fs_mark_super_dirty(ctx->fs);
2074 }
2075 /*
2076 * If the user answers no to the above question, we
2077 * ignore the fact that journal apparently has data;
2078 * accidentally replaying over valid data would be far
2079 * worse than skipping a questionable recovery.
2080 *
2081 * XXX should we abort with a fatal error here? What
2082 * will the ext3 kernel code do if a filesystem with
2083 * !NEEDS_RECOVERY but with a non-zero
2084 * journal->j_superblock->s_start is mounted?
2085 */
2086 }
2087
2088 e2fsck_journal_release(ctx, journal, reset, 0);
2089 return retval;
2090}
2091
2092static errcode_t recover_ext3_journal(e2fsck_t ctx)
2093{
2094 journal_t *journal;
2095 int retval;
2096
2097 journal_init_revoke_caches();
2098 retval = e2fsck_get_journal(ctx, &journal);
2099 if (retval)
2100 return retval;
2101
2102 retval = e2fsck_journal_load(journal);
2103 if (retval)
2104 goto errout;
2105
2106 retval = journal_init_revoke(journal, 1024);
2107 if (retval)
2108 goto errout;
2109
2110 retval = -journal_recover(journal);
2111 if (retval)
2112 goto errout;
2113
2114 if (journal->j_superblock->s_errno) {
2115 ctx->fs->super->s_state |= EXT2_ERROR_FS;
2116 ext2fs_mark_super_dirty(ctx->fs);
2117 journal->j_superblock->s_errno = 0;
2118 mark_buffer_dirty(journal->j_sb_buffer);
2119 }
2120
2121errout:
2122 journal_destroy_revoke(journal);
2123 journal_destroy_revoke_caches();
2124 e2fsck_journal_release(ctx, journal, 1, 0);
2125 return retval;
2126}
2127
2128static int e2fsck_run_ext3_journal(e2fsck_t ctx)
2129{
2130 io_manager io_ptr = ctx->fs->io->manager;
2131 int blocksize = ctx->fs->blocksize;
2132 errcode_t retval, recover_retval;
2133
2134 printf(_("%s: recovering journal\n"), ctx->device_name);
2135 if (ctx->options & E2F_OPT_READONLY) {
2136 printf(_("%s: won't do journal recovery while read-only\n"),
2137 ctx->device_name);
2138 return EXT2_ET_FILE_RO;
2139 }
2140
2141 if (ctx->fs->flags & EXT2_FLAG_DIRTY)
2142 ext2fs_flush(ctx->fs); /* Force out any modifications */
2143
2144 recover_retval = recover_ext3_journal(ctx);
2145
2146 /*
2147 * Reload the filesystem context to get up-to-date data from disk
2148 * because journal recovery will change the filesystem under us.
2149 */
2150 ext2fs_close(ctx->fs);
2151 retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
2152 ctx->superblock, blocksize, io_ptr,
2153 &ctx->fs);
2154
2155 if (retval) {
2156 bb_error_msg(_("while trying to re-open %s"),
2157 ctx->device_name);
2158 bb_error_msg_and_die(0);
2159 }
2160 ctx->fs->priv_data = ctx;
2161
2162 /* Set the superblock flags */
2163 e2fsck_clear_recover(ctx, recover_retval);
2164 return recover_retval;
2165}
2166
2167/*
2168 * This function will move the journal inode from a visible file in
2169 * the filesystem directory hierarchy to the reserved inode if necessary.
2170 */
2171static const char * const journal_names[] = {
2172 ".journal", "journal", ".journal.dat", "journal.dat", 0 };
2173
2174static void e2fsck_move_ext3_journal(e2fsck_t ctx)
2175{
2176 struct ext2_super_block *sb = ctx->fs->super;
2177 struct problem_context pctx;
2178 struct ext2_inode inode;
2179 ext2_filsys fs = ctx->fs;
2180 ext2_ino_t ino;
2181 errcode_t retval;
2182 const char * const * cpp;
2183 int group, mount_flags;
2184
2185 clear_problem_context(&pctx);
2186
2187 /*
2188 * If the filesystem is opened read-only, or there is no
2189 * journal, then do nothing.
2190 */
2191 if ((ctx->options & E2F_OPT_READONLY) ||
2192 (sb->s_journal_inum == 0) ||
2193 !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
2194 return;
2195
2196 /*
2197 * Read in the journal inode
2198 */
2199 if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
2200 return;
2201
2202 /*
2203 * If it's necessary to backup the journal inode, do so.
2204 */
2205 if ((sb->s_jnl_backup_type == 0) ||
2206 ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
2207 memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
2208 if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
2209 memcpy(sb->s_jnl_blocks, inode.i_block,
2210 EXT2_N_BLOCKS*4);
2211 sb->s_jnl_blocks[16] = inode.i_size;
2212 sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
2213 ext2fs_mark_super_dirty(fs);
2214 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
2215 }
2216 }
2217
2218 /*
2219 * If the journal is already the hidden inode, then do nothing
2220 */
2221 if (sb->s_journal_inum == EXT2_JOURNAL_INO)
2222 return;
2223
2224 /*
2225 * The journal inode had better have only one link and not be readable.
2226 */
2227 if (inode.i_links_count != 1)
2228 return;
2229
2230 /*
2231 * If the filesystem is mounted, or we can't tell whether
2232 * or not it's mounted, do nothing.
2233 */
2234 retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
2235 if (retval || (mount_flags & EXT2_MF_MOUNTED))
2236 return;
2237
2238 /*
2239 * If we can't find the name of the journal inode, then do
2240 * nothing.
2241 */
2242 for (cpp = journal_names; *cpp; cpp++) {
2243 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
2244 strlen(*cpp), 0, &ino);
2245 if ((retval == 0) && (ino == sb->s_journal_inum))
2246 break;
2247 }
2248 if (*cpp == 0)
2249 return;
2250
2251 /* We need the inode bitmap to be loaded */
2252 retval = ext2fs_read_bitmaps(fs);
2253 if (retval)
2254 return;
2255
2256 pctx.str = *cpp;
2257 if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
2258 return;
2259
2260 /*
2261 * OK, we've done all the checks, let's actually move the
2262 * journal inode. Errors at this point mean we need to force
2263 * an ext2 filesystem check.
2264 */
2265 if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
2266 goto err_out;
2267 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
2268 goto err_out;
2269 sb->s_journal_inum = EXT2_JOURNAL_INO;
2270 ext2fs_mark_super_dirty(fs);
2271 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
2272 inode.i_links_count = 0;
2273 inode.i_dtime = time(0);
2274 if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
2275 goto err_out;
2276
2277 group = ext2fs_group_of_ino(fs, ino);
2278 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
2279 ext2fs_mark_ib_dirty(fs);
2280 fs->group_desc[group].bg_free_inodes_count++;
2281 fs->super->s_free_inodes_count++;
2282 return;
2283
2284err_out:
2285 pctx.errcode = retval;
2286 fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
2287 fs->super->s_state &= ~EXT2_VALID_FS;
2288 ext2fs_mark_super_dirty(fs);
2289 return;
2290}
2291
2292/*
2293 * message.c --- print e2fsck messages (with compression)
2294 *
2295 * print_e2fsck_message() prints a message to the user, using
2296 * compression techniques and expansions of abbreviations.
2297 *
2298 * The following % expansions are supported:
2299 *
2300 * %b <blk> block number
2301 * %B <blkcount> integer
2302 * %c <blk2> block number
2303 * %Di <dirent>->ino inode number
2304 * %Dn <dirent>->name string
2305 * %Dr <dirent>->rec_len
2306 * %Dl <dirent>->name_len
2307 * %Dt <dirent>->filetype
2308 * %d <dir> inode number
2309 * %g <group> integer
2310 * %i <ino> inode number
2311 * %Is <inode> -> i_size
2312 * %IS <inode> -> i_extra_isize
2313 * %Ib <inode> -> i_blocks
2314 * %Il <inode> -> i_links_count
2315 * %Im <inode> -> i_mode
2316 * %IM <inode> -> i_mtime
2317 * %IF <inode> -> i_faddr
2318 * %If <inode> -> i_file_acl
2319 * %Id <inode> -> i_dir_acl
2320 * %Iu <inode> -> i_uid
2321 * %Ig <inode> -> i_gid
2322 * %j <ino2> inode number
2323 * %m <com_err error message>
2324 * %N <num>
2325 * %p ext2fs_get_pathname of directory <ino>
2326 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
2327 * the containing directory. (If dirent is NULL
2328 * then return the pathname of directory <ino2>)
2329 * %q ext2fs_get_pathname of directory <dir>
2330 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
2331 * the containing directory.
2332 * %s <str> miscellaneous string
2333 * %S backup superblock
2334 * %X <num> hexadecimal format
2335 *
2336 * The following '@' expansions are supported:
2337 *
2338 * @a extended attribute
2339 * @A error allocating
2340 * @b block
2341 * @B bitmap
2342 * @c compress
2343 * @C conflicts with some other fs block
2344 * @D deleted
2345 * @d directory
2346 * @e entry
2347 * @E Entry '%Dn' in %p (%i)
2348 * @f filesystem
2349 * @F for @i %i (%Q) is
2350 * @g group
2351 * @h HTREE directory inode
2352 * @i inode
2353 * @I illegal
2354 * @j journal
2355 * @l lost+found
2356 * @L is a link
2357 * @m multiply-claimed
2358 * @n invalid
2359 * @o orphaned
2360 * @p problem in
2361 * @r root inode
2362 * @s should be
2363 * @S superblock
2364 * @u unattached
2365 * @v device
2366 * @z zero-length
2367 */
2368
2369
2370/*
2371 * This structure defines the abbreviations used by the text strings
2372 * below. The first character in the string is the index letter. An
2373 * abbreviation of the form '@<i>' is expanded by looking up the index
2374 * letter <i> in the table below.
2375 */
2376static const char * const abbrevs[] = {
2377 N_("aextended attribute"),
2378 N_("Aerror allocating"),
2379 N_("bblock"),
2380 N_("Bbitmap"),
2381 N_("ccompress"),
2382 N_("Cconflicts with some other fs @b"),
2383 N_("iinode"),
2384 N_("Iillegal"),
2385 N_("jjournal"),
2386 N_("Ddeleted"),
2387 N_("ddirectory"),
2388 N_("eentry"),
2389 N_("E@e '%Dn' in %p (%i)"),
2390 N_("ffilesystem"),
2391 N_("Ffor @i %i (%Q) is"),
2392 N_("ggroup"),
2393 N_("hHTREE @d @i"),
2394 N_("llost+found"),
2395 N_("Lis a link"),
2396 N_("mmultiply-claimed"),
2397 N_("ninvalid"),
2398 N_("oorphaned"),
2399 N_("pproblem in"),
2400 N_("rroot @i"),
2401 N_("sshould be"),
2402 N_("Ssuper@b"),
2403 N_("uunattached"),
2404 N_("vdevice"),
2405 N_("zzero-length"),
2406 "@@",
2407 0
2408 };
2409
2410/*
2411 * Give more user friendly names to the "special" inodes.
2412 */
2413#define num_special_inodes 11
2414static const char * const special_inode_name[] =
2415{
2416 N_("<The NULL inode>"), /* 0 */
2417 N_("<The bad blocks inode>"), /* 1 */
2418 "/", /* 2 */
2419 N_("<The ACL index inode>"), /* 3 */
2420 N_("<The ACL data inode>"), /* 4 */
2421 N_("<The boot loader inode>"), /* 5 */
2422 N_("<The undelete directory inode>"), /* 6 */
2423 N_("<The group descriptor inode>"), /* 7 */
2424 N_("<The journal inode>"), /* 8 */
2425 N_("<Reserved inode 9>"), /* 9 */
2426 N_("<Reserved inode 10>"), /* 10 */
2427};
2428
2429/*
2430 * This function does "safe" printing. It will convert non-printable
2431 * ASCII characters using '^' and M- notation.
2432 */
2433static void safe_print(const char *cp, int len)
2434{
2435 unsigned char ch;
2436
2437 if (len < 0)
2438 len = strlen(cp);
2439
2440 while (len--) {
2441 ch = *cp++;
2442 if (ch > 128) {
2443 fputs("M-", stdout);
2444 ch -= 128;
2445 }
2446 if ((ch < 32) || (ch == 0x7f)) {
2447 fputc('^', stdout);
2448 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
2449 }
2450 fputc(ch, stdout);
2451 }
2452}
2453
2454
2455/*
2456 * This function prints a pathname, using the ext2fs_get_pathname
2457 * function
2458 */
2459static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
2460{
2461 errcode_t retval;
2462 char *path;
2463
2464 if (!dir && (ino < num_special_inodes)) {
2465 fputs(_(special_inode_name[ino]), stdout);
2466 return;
2467 }
2468
2469 retval = ext2fs_get_pathname(fs, dir, ino, &path);
2470 if (retval)
2471 fputs("???", stdout);
2472 else {
2473 safe_print(path, -1);
2474 ext2fs_free_mem(&path);
2475 }
2476}
2477
2478static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
2479 struct problem_context *pctx, int first);
2480/*
2481 * This function handles the '@' expansion. We allow recursive
2482 * expansion; an @ expression can contain further '@' and '%'
2483 * expressions.
2484 */
2485static void expand_at_expression(e2fsck_t ctx, char ch,
2486 struct problem_context *pctx,
2487 int *first)
2488{
2489 const char * const *cpp;
2490 const char *str;
2491
2492 /* Search for the abbreviation */
2493 for (cpp = abbrevs; *cpp; cpp++) {
2494 if (ch == *cpp[0])
2495 break;
2496 }
2497 if (*cpp) {
2498 str = _(*cpp) + 1;
2499 if (*first && islower(*str)) {
2500 *first = 0;
2501 fputc(toupper(*str++), stdout);
2502 }
2503 print_e2fsck_message(ctx, str, pctx, *first);
2504 } else
2505 printf("@%c", ch);
2506}
2507
2508/*
2509 * This function expands '%IX' expressions
2510 */
2511static void expand_inode_expression(char ch,
2512 struct problem_context *ctx)
2513{
2514 struct ext2_inode *inode;
2515 struct ext2_inode_large *large_inode;
2516 char * time_str;
2517 time_t t;
2518 int do_gmt = -1;
2519
2520 if (!ctx || !ctx->inode)
2521 goto no_inode;
2522
2523 inode = ctx->inode;
2524 large_inode = (struct ext2_inode_large *) inode;
2525
2526 switch (ch) {
2527 case 's':
2528 if (LINUX_S_ISDIR(inode->i_mode))
2529 printf("%u", inode->i_size);
2530 else {
2531 printf("%"PRIu64, (inode->i_size |
2532 ((uint64_t) inode->i_size_high << 32)));
2533 }
2534 break;
2535 case 'S':
2536 printf("%u", large_inode->i_extra_isize);
2537 break;
2538 case 'b':
2539 printf("%u", inode->i_blocks);
2540 break;
2541 case 'l':
2542 printf("%d", inode->i_links_count);
2543 break;
2544 case 'm':
2545 printf("0%o", inode->i_mode);
2546 break;
2547 case 'M':
2548 /* The diet libc doesn't respect the TZ environemnt variable */
2549 if (do_gmt == -1) {
2550 time_str = getenv("TZ");
2551 if (!time_str)
2552 time_str = "";
2553 do_gmt = !strcmp(time_str, "GMT");
2554 }
2555 t = inode->i_mtime;
2556 time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
2557 printf("%.24s", time_str);
2558 break;
2559 case 'F':
2560 printf("%u", inode->i_faddr);
2561 break;
2562 case 'f':
2563 printf("%u", inode->i_file_acl);
2564 break;
2565 case 'd':
2566 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
2567 inode->i_dir_acl : 0));
2568 break;
2569 case 'u':
2570 printf("%d", (inode->i_uid |
2571 (inode->osd2.linux2.l_i_uid_high << 16)));
2572 break;
2573 case 'g':
2574 printf("%d", (inode->i_gid |
2575 (inode->osd2.linux2.l_i_gid_high << 16)));
2576 break;
2577 default:
2578 no_inode:
2579 printf("%%I%c", ch);
2580 break;
2581 }
2582}
2583
2584/*
2585 * This function expands '%dX' expressions
2586 */
2587static void expand_dirent_expression(char ch,
2588 struct problem_context *ctx)
2589{
2590 struct ext2_dir_entry *dirent;
2591 int len;
2592
2593 if (!ctx || !ctx->dirent)
2594 goto no_dirent;
2595
2596 dirent = ctx->dirent;
2597
2598 switch (ch) {
2599 case 'i':
2600 printf("%u", dirent->inode);
2601 break;
2602 case 'n':
2603 len = dirent->name_len & 0xFF;
2604 if (len > EXT2_NAME_LEN)
2605 len = EXT2_NAME_LEN;
2606 if (len > dirent->rec_len)
2607 len = dirent->rec_len;
2608 safe_print(dirent->name, len);
2609 break;
2610 case 'r':
2611 printf("%u", dirent->rec_len);
2612 break;
2613 case 'l':
2614 printf("%u", dirent->name_len & 0xFF);
2615 break;
2616 case 't':
2617 printf("%u", dirent->name_len >> 8);
2618 break;
2619 default:
2620 no_dirent:
2621 printf("%%D%c", ch);
2622 break;
2623 }
2624}
2625
2626static void expand_percent_expression(ext2_filsys fs, char ch,
2627 struct problem_context *ctx)
2628{
2629 if (!ctx)
2630 goto no_context;
2631
2632 switch (ch) {
2633 case '%':
2634 fputc('%', stdout);
2635 break;
2636 case 'b':
2637 printf("%u", ctx->blk);
2638 break;
2639 case 'B':
2640 printf("%"PRIi64, ctx->blkcount);
2641 break;
2642 case 'c':
2643 printf("%u", ctx->blk2);
2644 break;
2645 case 'd':
2646 printf("%u", ctx->dir);
2647 break;
2648 case 'g':
2649 printf("%d", ctx->group);
2650 break;
2651 case 'i':
2652 printf("%u", ctx->ino);
2653 break;
2654 case 'j':
2655 printf("%u", ctx->ino2);
2656 break;
2657 case 'm':
2658 printf("%s", error_message(ctx->errcode));
2659 break;
2660 case 'N':
2661 printf("%"PRIi64, ctx->num);
2662 break;
2663 case 'p':
2664 print_pathname(fs, ctx->ino, 0);
2665 break;
2666 case 'P':
2667 print_pathname(fs, ctx->ino2,
2668 ctx->dirent ? ctx->dirent->inode : 0);
2669 break;
2670 case 'q':
2671 print_pathname(fs, ctx->dir, 0);
2672 break;
2673 case 'Q':
2674 print_pathname(fs, ctx->dir, ctx->ino);
2675 break;
2676 case 'S':
2677 printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
2678 break;
2679 case 's':
2680 printf("%s", ctx->str ? ctx->str : "NULL");
2681 break;
2682 case 'X':
2683 printf("0x%"PRIi64, ctx->num);
2684 break;
2685 default:
2686 no_context:
2687 printf("%%%c", ch);
2688 break;
2689 }
2690}
2691
2692
2693static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
2694 struct problem_context *pctx, int first)
2695{
2696 ext2_filsys fs = ctx->fs;
2697 const char * cp;
2698 int i;
2699
2700 e2fsck_clear_progbar(ctx);
2701 for (cp = msg; *cp; cp++) {
2702 if (cp[0] == '@') {
2703 cp++;
2704 expand_at_expression(ctx, *cp, pctx, &first);
2705 } else if (cp[0] == '%' && cp[1] == 'I') {
2706 cp += 2;
2707 expand_inode_expression(*cp, pctx);
2708 } else if (cp[0] == '%' && cp[1] == 'D') {
2709 cp += 2;
2710 expand_dirent_expression(*cp, pctx);
2711 } else if ((cp[0] == '%')) {
2712 cp++;
2713 expand_percent_expression(fs, *cp, pctx);
2714 } else {
2715 for (i=0; cp[i]; i++)
2716 if ((cp[i] == '@') || cp[i] == '%')
2717 break;
2718 printf("%.*s", i, cp);
2719 cp += i-1;
2720 }
2721 first = 0;
2722 }
2723}
2724
2725
2726/*
2727 * region.c --- code which manages allocations within a region.
2728 */
2729
2730struct region_el {
2731 region_addr_t start;
2732 region_addr_t end;
2733 struct region_el *next;
2734};
2735
2736struct region_struct {
2737 region_addr_t min;
2738 region_addr_t max;
2739 struct region_el *allocated;
2740};
2741
2742static region_t region_create(region_addr_t min, region_addr_t max)
2743{
2744 region_t region;
2745
2746 region = malloc(sizeof(struct region_struct));
2747 if (!region)
2748 return NULL;
2749 memset(region, 0, sizeof(struct region_struct));
2750 region->min = min;
2751 region->max = max;
2752 return region;
2753}
2754
2755static void region_free(region_t region)
2756{
2757 struct region_el *r, *next;
2758
2759 for (r = region->allocated; r; r = next) {
2760 next = r->next;
2761 free(r);
2762 }
2763 memset(region, 0, sizeof(struct region_struct));
2764 free(region);
2765}
2766
2767static int region_allocate(region_t region, region_addr_t start, int n)
2768{
2769 struct region_el *r, *new_region, *prev, *next;
2770 region_addr_t end;
2771
2772 end = start+n;
2773 if ((start < region->min) || (end > region->max))
2774 return -1;
2775 if (n == 0)
2776 return 1;
2777
2778 /*
2779 * Search through the linked list. If we find that it
2780 * conflicts witih something that's already allocated, return
2781 * 1; if we can find an existing region which we can grow, do
2782 * so. Otherwise, stop when we find the appropriate place
2783 * insert a new region element into the linked list.
2784 */
2785 for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
2786 if (((start >= r->start) && (start < r->end)) ||
2787 ((end > r->start) && (end <= r->end)) ||
2788 ((start <= r->start) && (end >= r->end)))
2789 return 1;
2790 if (end == r->start) {
2791 r->start = start;
2792 return 0;
2793 }
2794 if (start == r->end) {
2795 if ((next = r->next)) {
2796 if (end > next->start)
2797 return 1;
2798 if (end == next->start) {
2799 r->end = next->end;
2800 r->next = next->next;
2801 free(next);
2802 return 0;
2803 }
2804 }
2805 r->end = end;
2806 return 0;
2807 }
2808 if (start < r->start)
2809 break;
2810 }
2811 /*
2812 * Insert a new region element structure into the linked list
2813 */
2814 new_region = malloc(sizeof(struct region_el));
2815 if (!new_region)
2816 return -1;
2817 new_region->start = start;
2818 new_region->end = start + n;
2819 new_region->next = r;
2820 if (prev)
2821 prev->next = new_region;
2822 else
2823 region->allocated = new_region;
2824 return 0;
2825}
2826
2827/*
2828 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
2829 *
2830 * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
2831 * and applies the following tests to each inode:
2832 *
2833 * - The mode field of the inode must be legal.
2834 * - The size and block count fields of the inode are correct.
2835 * - A data block must not be used by another inode
2836 *
2837 * Pass 1 also gathers the collects the following information:
2838 *
2839 * - A bitmap of which inodes are in use. (inode_used_map)
2840 * - A bitmap of which inodes are directories. (inode_dir_map)
2841 * - A bitmap of which inodes are regular files. (inode_reg_map)
2842 * - A bitmap of which inodes have bad fields. (inode_bad_map)
2843 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
2844 * - A bitmap of which blocks are in use. (block_found_map)
2845 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
2846 * - The data blocks of the directory inodes. (dir_map)
2847 *
2848 * Pass 1 is designed to stash away enough information so that the
2849 * other passes should not need to read in the inode information
2850 * during the normal course of a filesystem check. (Althogh if an
2851 * inconsistency is detected, other passes may need to read in an
2852 * inode to fix it.)
2853 *
2854 * Note that pass 1B will be invoked if there are any duplicate blocks
2855 * found.
2856 */
2857
2858
2859static int process_block(ext2_filsys fs, blk_t *blocknr,
2860 e2_blkcnt_t blockcnt, blk_t ref_blk,
2861 int ref_offset, void *priv_data);
2862static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
2863 e2_blkcnt_t blockcnt, blk_t ref_blk,
2864 int ref_offset, void *priv_data);
2865static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
2866 char *block_buf);
2867static void mark_table_blocks(e2fsck_t ctx);
2868static void alloc_imagic_map(e2fsck_t ctx);
2869static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
2870static void handle_fs_bad_blocks(e2fsck_t ctx);
2871static void process_inodes(e2fsck_t ctx, char *block_buf);
2872static int process_inode_cmp(const void *a, const void *b);
2873static errcode_t scan_callback(ext2_filsys fs,
2874 dgrp_t group, void * priv_data);
2875static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
2876 char *block_buf, int adjust_sign);
2877/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
2878
2879static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
2880 struct ext2_inode * inode, int bufsize,
2881 const char *proc);
2882
2883struct process_block_struct_1 {
2884 ext2_ino_t ino;
2885 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
2886 fragmented:1, compressed:1, bbcheck:1;
2887 blk_t num_blocks;
2888 blk_t max_blocks;
2889 e2_blkcnt_t last_block;
2890 int num_illegal_blocks;
2891 blk_t previous_block;
2892 struct ext2_inode *inode;
2893 struct problem_context *pctx;
2894 ext2fs_block_bitmap fs_meta_blocks;
2895 e2fsck_t ctx;
2896};
2897
2898struct process_inode_block {
2899 ext2_ino_t ino;
2900 struct ext2_inode inode;
2901};
2902
2903struct scan_callback_struct {
2904 e2fsck_t ctx;
2905 char *block_buf;
2906};
2907
2908/*
2909 * For the inodes to process list.
2910 */
2911static struct process_inode_block *inodes_to_process;
2912static int process_inode_count;
2913
2914static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
2915 EXT2_MIN_BLOCK_LOG_SIZE + 1];
2916
2917/*
2918 * Free all memory allocated by pass1 in preparation for restarting
2919 * things.
2920 */
2921static void unwind_pass1(void)
2922{
2923 ext2fs_free_mem(&inodes_to_process);
2924}
2925
2926/*
2927 * Check to make sure a device inode is real. Returns 1 if the device
2928 * checks out, 0 if not.
2929 *
2930 * Note: this routine is now also used to check FIFO's and Sockets,
2931 * since they have the same requirement; the i_block fields should be
2932 * zero.
2933 */
2934static int
2935e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
2936{
2937 int i;
2938
2939 /*
2940 * If i_blocks is non-zero, or the index flag is set, then
2941 * this is a bogus device/fifo/socket
2942 */
2943 if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
2944 (inode->i_flags & EXT2_INDEX_FL))
2945 return 0;
2946
2947 /*
2948 * We should be able to do the test below all the time, but
2949 * because the kernel doesn't forcibly clear the device
2950 * inode's additional i_block fields, there are some rare
2951 * occasions when a legitimate device inode will have non-zero
2952 * additional i_block fields. So for now, we only complain
2953 * when the immutable flag is set, which should never happen
2954 * for devices. (And that's when the problem is caused, since
2955 * you can't set or clear immutable flags for devices.) Once
2956 * the kernel has been fixed we can change this...
2957 */
2958 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
2959 for (i=4; i < EXT2_N_BLOCKS; i++)
2960 if (inode->i_block[i])
2961 return 0;
2962 }
2963 return 1;
2964}
2965
2966/*
2967 * Check to make sure a symlink inode is real. Returns 1 if the symlink
2968 * checks out, 0 if not.
2969 */
2970static int
2971e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, char *buf)
2972{
2973 unsigned int len;
2974 int i;
2975 blk_t blocks;
2976
2977 if ((inode->i_size_high || inode->i_size == 0) ||
2978 (inode->i_flags & EXT2_INDEX_FL))
2979 return 0;
2980
2981 blocks = ext2fs_inode_data_blocks(fs, inode);
2982 if (blocks) {
2983 if ((inode->i_size >= fs->blocksize) ||
2984 (blocks != fs->blocksize >> 9) ||
2985 (inode->i_block[0] < fs->super->s_first_data_block) ||
2986 (inode->i_block[0] >= fs->super->s_blocks_count))
2987 return 0;
2988
2989 for (i = 1; i < EXT2_N_BLOCKS; i++)
2990 if (inode->i_block[i])
2991 return 0;
2992
2993 if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
2994 return 0;
2995
2996 len = strnlen(buf, fs->blocksize);
2997 if (len == fs->blocksize)
2998 return 0;
2999 } else {
3000 if (inode->i_size >= sizeof(inode->i_block))
3001 return 0;
3002
3003 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
3004 if (len == sizeof(inode->i_block))
3005 return 0;
3006 }
3007 if (len != inode->i_size)
3008 return 0;
3009 return 1;
3010}
3011
3012/*
3013 * If the immutable (or append-only) flag is set on the inode, offer
3014 * to clear it.
3015 */
3016#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
3017static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
3018{
3019 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
3020 return;
3021
3022 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
3023 return;
3024
3025 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
3026 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
3027}
3028
3029/*
3030 * If device, fifo or socket, check size is zero -- if not offer to
3031 * clear it
3032 */
3033static void check_size(e2fsck_t ctx, struct problem_context *pctx)
3034{
3035 struct ext2_inode *inode = pctx->inode;
3036
3037 if ((inode->i_size == 0) && (inode->i_size_high == 0))
3038 return;
3039
3040 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
3041 return;
3042
3043 inode->i_size = 0;
3044 inode->i_size_high = 0;
3045 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
3046}
3047
3048static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
3049{
3050 struct ext2_super_block *sb = ctx->fs->super;
3051 struct ext2_inode_large *inode;
3052 struct ext2_ext_attr_entry *entry;
3053 char *start, *end;
3054 int storage_size, remain, offs;
3055 int problem = 0;
3056
3057 inode = (struct ext2_inode_large *) pctx->inode;
3058 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
3059 inode->i_extra_isize;
3060 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
3061 inode->i_extra_isize + sizeof(__u32);
3062 end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
3063 entry = (struct ext2_ext_attr_entry *) start;
3064
3065 /* scan all entry's headers first */
3066
3067 /* take finish entry 0UL into account */
3068 remain = storage_size - sizeof(__u32);
3069 offs = end - start;
3070
3071 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
3072
3073 /* header eats this space */
3074 remain -= sizeof(struct ext2_ext_attr_entry);
3075
3076 /* is attribute name valid? */
3077 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
3078 pctx->num = entry->e_name_len;
3079 problem = PR_1_ATTR_NAME_LEN;
3080 goto fix;
3081 }
3082
3083 /* attribute len eats this space */
3084 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
3085
3086 /* check value size */
3087 if (entry->e_value_size == 0 || entry->e_value_size > remain) {
3088 pctx->num = entry->e_value_size;
3089 problem = PR_1_ATTR_VALUE_SIZE;
3090 goto fix;
3091 }
3092
3093 /* check value placement */
3094 if (entry->e_value_offs +
3095 EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
3096 printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
3097 pctx->num = entry->e_value_offs;
3098 problem = PR_1_ATTR_VALUE_OFFSET;
3099 goto fix;
3100 }
3101
3102 /* e_value_block must be 0 in inode's ea */
3103 if (entry->e_value_block != 0) {
3104 pctx->num = entry->e_value_block;
3105 problem = PR_1_ATTR_VALUE_BLOCK;
3106 goto fix;
3107 }
3108
3109 /* e_hash must be 0 in inode's ea */
3110 if (entry->e_hash != 0) {
3111 pctx->num = entry->e_hash;
3112 problem = PR_1_ATTR_HASH;
3113 goto fix;
3114 }
3115
3116 remain -= entry->e_value_size;
3117 offs -= EXT2_XATTR_SIZE(entry->e_value_size);
3118
3119 entry = EXT2_EXT_ATTR_NEXT(entry);
3120 }
3121fix:
3122 /*
3123 * it seems like a corruption. it's very unlikely we could repair
3124 * EA(s) in automatic fashion -bzzz
3125 */
3126 if (problem == 0 || !fix_problem(ctx, problem, pctx))
3127 return;
3128
3129 /* simple remove all possible EA(s) */
3130 *((__u32 *)start) = 0UL;
3131 e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
3132 EXT2_INODE_SIZE(sb), "pass1");
3133}
3134
3135static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
3136{
3137 struct ext2_super_block *sb = ctx->fs->super;
3138 struct ext2_inode_large *inode;
3139 __u32 *eamagic;
3140 int min, max;
3141
3142 inode = (struct ext2_inode_large *) pctx->inode;
3143 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
3144 /* this isn't large inode. so, nothing to check */
3145 return;
3146 }
3147
3148 /* i_extra_isize must cover i_extra_isize + i_pad1 at least */
3149 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
3150 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
3151 /*
3152 * For now we will allow i_extra_isize to be 0, but really
3153 * implementations should never allow i_extra_isize to be 0
3154 */
3155 if (inode->i_extra_isize &&
3156 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
3157 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
3158 return;
3159 inode->i_extra_isize = min;
3160 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
3161 EXT2_INODE_SIZE(sb), "pass1");
3162 return;
3163 }
3164
3165 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
3166 inode->i_extra_isize);
3167 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
3168 /* it seems inode has an extended attribute(s) in body */
3169 check_ea_in_inode(ctx, pctx);
3170 }
3171}
3172
3173static void e2fsck_pass1(e2fsck_t ctx)
3174{
3175 int i;
3176 __u64 max_sizes;
3177 ext2_filsys fs = ctx->fs;
3178 ext2_ino_t ino;
3179 struct ext2_inode *inode;
3180 ext2_inode_scan scan;
3181 char *block_buf;
3182 unsigned char frag, fsize;
3183 struct problem_context pctx;
3184 struct scan_callback_struct scan_struct;
3185 struct ext2_super_block *sb = ctx->fs->super;
3186 int imagic_fs;
3187 int busted_fs_time = 0;
3188 int inode_size;
3189
3190 clear_problem_context(&pctx);
3191
3192 if (!(ctx->options & E2F_OPT_PREEN))
3193 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
3194
3195 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
3196 !(ctx->options & E2F_OPT_NO)) {
3197 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
3198 ctx->dirs_to_hash = 0;
3199 }
3200
3201 /* Pass 1 */
3202
3203#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
3204
3205 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
3206 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
3207 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
3208 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
3209 max_sizes = (max_sizes * (1UL << i)) - 1;
3210 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
3211 }
3212#undef EXT2_BPP
3213
3214 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
3215
3216 /*
3217 * Allocate bitmaps structures
3218 */
3219 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
3220 &ctx->inode_used_map);
3221 if (pctx.errcode) {
3222 pctx.num = 1;
3223 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3224 ctx->flags |= E2F_FLAG_ABORT;
3225 return;
3226 }
3227 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
3228 _("directory inode map"), &ctx->inode_dir_map);
3229 if (pctx.errcode) {
3230 pctx.num = 2;
3231 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3232 ctx->flags |= E2F_FLAG_ABORT;
3233 return;
3234 }
3235 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
3236 _("regular file inode map"), &ctx->inode_reg_map);
3237 if (pctx.errcode) {
3238 pctx.num = 6;
3239 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3240 ctx->flags |= E2F_FLAG_ABORT;
3241 return;
3242 }
3243 pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
3244 &ctx->block_found_map);
3245 if (pctx.errcode) {
3246 pctx.num = 1;
3247 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
3248 ctx->flags |= E2F_FLAG_ABORT;
3249 return;
3250 }
3251 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
3252 &ctx->inode_link_info);
3253 if (pctx.errcode) {
3254 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
3255 ctx->flags |= E2F_FLAG_ABORT;
3256 return;
3257 }
3258 inode_size = EXT2_INODE_SIZE(fs->super);
3259 inode = (struct ext2_inode *)
3260 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
3261
3262 inodes_to_process = (struct process_inode_block *)
3263 e2fsck_allocate_memory(ctx,
3264 (ctx->process_inode_size *
3265 sizeof(struct process_inode_block)),
3266 "array of inodes to process");
3267 process_inode_count = 0;
3268
3269 pctx.errcode = ext2fs_init_dblist(fs, 0);
3270 if (pctx.errcode) {
3271 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
3272 ctx->flags |= E2F_FLAG_ABORT;
3273 return;
3274 }
3275
3276 /*
3277 * If the last orphan field is set, clear it, since the pass1
3278 * processing will automatically find and clear the orphans.
3279 * In the future, we may want to try using the last_orphan
3280 * linked list ourselves, but for now, we clear it so that the
3281 * ext3 mount code won't get confused.
3282 */
3283 if (!(ctx->options & E2F_OPT_READONLY)) {
3284 if (fs->super->s_last_orphan) {
3285 fs->super->s_last_orphan = 0;
3286 ext2fs_mark_super_dirty(fs);
3287 }
3288 }
3289
3290 mark_table_blocks(ctx);
3291 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
3292 "block interate buffer");
3293 e2fsck_use_inode_shortcuts(ctx, 1);
3294 ehandler_operation(_("doing inode scan"));
3295 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
3296 &scan);
3297 if (pctx.errcode) {
3298 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
3299 ctx->flags |= E2F_FLAG_ABORT;
3300 return;
3301 }
3302 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
3303 ctx->stashed_inode = inode;
3304 scan_struct.ctx = ctx;
3305 scan_struct.block_buf = block_buf;
3306 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
3307 if (ctx->progress)
3308 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
3309 return;
3310 if ((fs->super->s_wtime < fs->super->s_inodes_count) ||
3311 (fs->super->s_mtime < fs->super->s_inodes_count))
3312 busted_fs_time = 1;
3313
3314 while (1) {
3315 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
3316 inode, inode_size);
3317 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3318 return;
3319 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
3320 continue;
3321 }
3322 if (pctx.errcode) {
3323 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
3324 ctx->flags |= E2F_FLAG_ABORT;
3325 return;
3326 }
3327 if (!ino)
3328 break;
3329 pctx.ino = ino;
3330 pctx.inode = inode;
3331 ctx->stashed_ino = ino;
3332 if (inode->i_links_count) {
3333 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
3334 ino, inode->i_links_count);
3335 if (pctx.errcode) {
3336 pctx.num = inode->i_links_count;
3337 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
3338 ctx->flags |= E2F_FLAG_ABORT;
3339 return;
3340 }
3341 }
3342 if (ino == EXT2_BAD_INO) {
3343 struct process_block_struct_1 pb;
3344
3345 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
3346 &pb.fs_meta_blocks);
3347 if (pctx.errcode) {
3348 pctx.num = 4;
3349 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
3350 ctx->flags |= E2F_FLAG_ABORT;
3351 return;
3352 }
3353 pb.ino = EXT2_BAD_INO;
3354 pb.num_blocks = pb.last_block = 0;
3355 pb.num_illegal_blocks = 0;
3356 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
3357 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
3358 pb.inode = inode;
3359 pb.pctx = &pctx;
3360 pb.ctx = ctx;
3361 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
3362 block_buf, process_bad_block, &pb);
3363 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
3364 if (pctx.errcode) {
3365 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
3366 ctx->flags |= E2F_FLAG_ABORT;
3367 return;
3368 }
3369 if (pb.bbcheck)
3370 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
3371 ctx->flags |= E2F_FLAG_ABORT;
3372 return;
3373 }
3374 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3375 clear_problem_context(&pctx);
3376 continue;
3377 } else if (ino == EXT2_ROOT_INO) {
3378 /*
3379 * Make sure the root inode is a directory; if
3380 * not, offer to clear it. It will be
3381 * regnerated in pass #3.
3382 */
3383 if (!LINUX_S_ISDIR(inode->i_mode)) {
3384 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
3385 inode->i_dtime = time(0);
3386 inode->i_links_count = 0;
3387 ext2fs_icount_store(ctx->inode_link_info,
3388 ino, 0);
3389 e2fsck_write_inode(ctx, ino, inode,
3390 "pass1");
3391 }
3392
3393 }
3394 /*
3395 * If dtime is set, offer to clear it. mke2fs
3396 * version 0.2b created filesystems with the
3397 * dtime field set for the root and lost+found
3398 * directories. We won't worry about
3399 * /lost+found, since that can be regenerated
3400 * easily. But we will fix the root directory
3401 * as a special case.
3402 */
3403 if (inode->i_dtime && inode->i_links_count) {
3404 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
3405 inode->i_dtime = 0;
3406 e2fsck_write_inode(ctx, ino, inode,
3407 "pass1");
3408 }
3409 }
3410 } else if (ino == EXT2_JOURNAL_INO) {
3411 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3412 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
3413 if (!LINUX_S_ISREG(inode->i_mode) &&
3414 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
3415 &pctx)) {
3416 inode->i_mode = LINUX_S_IFREG;
3417 e2fsck_write_inode(ctx, ino, inode,
3418 "pass1");
3419 }
3420 check_blocks(ctx, &pctx, block_buf);
3421 continue;
3422 }
3423 if ((inode->i_links_count || inode->i_blocks ||
3424 inode->i_blocks || inode->i_block[0]) &&
3425 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
3426 &pctx)) {
3427 memset(inode, 0, inode_size);
3428 ext2fs_icount_store(ctx->inode_link_info,
3429 ino, 0);
3430 e2fsck_write_inode_full(ctx, ino, inode,
3431 inode_size, "pass1");
3432 }
3433 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
3434 int problem = 0;
3435
3436 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3437 if (ino == EXT2_BOOT_LOADER_INO) {
3438 if (LINUX_S_ISDIR(inode->i_mode))
3439 problem = PR_1_RESERVED_BAD_MODE;
3440 } else if (ino == EXT2_RESIZE_INO) {
3441 if (inode->i_mode &&
3442 !LINUX_S_ISREG(inode->i_mode))
3443 problem = PR_1_RESERVED_BAD_MODE;
3444 } else {
3445 if (inode->i_mode != 0)
3446 problem = PR_1_RESERVED_BAD_MODE;
3447 }
3448 if (problem) {
3449 if (fix_problem(ctx, problem, &pctx)) {
3450 inode->i_mode = 0;
3451 e2fsck_write_inode(ctx, ino, inode,
3452 "pass1");
3453 }
3454 }
3455 check_blocks(ctx, &pctx, block_buf);
3456 continue;
3457 }
3458 /*
3459 * Check for inodes who might have been part of the
3460 * orphaned list linked list. They should have gotten
3461 * dealt with by now, unless the list had somehow been
3462 * corrupted.
3463 *
3464 * FIXME: In the future, inodes which are still in use
3465 * (and which are therefore) pending truncation should
3466 * be handled specially. Right now we just clear the
3467 * dtime field, and the normal e2fsck handling of
3468 * inodes where i_size and the inode blocks are
3469 * inconsistent is to fix i_size, instead of releasing
3470 * the extra blocks. This won't catch the inodes that
3471 * was at the end of the orphan list, but it's better
3472 * than nothing. The right answer is that there
3473 * shouldn't be any bugs in the orphan list handling. :-)
3474 */
3475 if (inode->i_dtime && !busted_fs_time &&
3476 inode->i_dtime < ctx->fs->super->s_inodes_count) {
3477 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
3478 inode->i_dtime = inode->i_links_count ?
3479 0 : time(0);
3480 e2fsck_write_inode(ctx, ino, inode,
3481 "pass1");
3482 }
3483 }
3484
3485 /*
3486 * This code assumes that deleted inodes have
3487 * i_links_count set to 0.
3488 */
3489 if (!inode->i_links_count) {
3490 if (!inode->i_dtime && inode->i_mode) {
3491 if (fix_problem(ctx,
3492 PR_1_ZERO_DTIME, &pctx)) {
3493 inode->i_dtime = time(0);
3494 e2fsck_write_inode(ctx, ino, inode,
3495 "pass1");
3496 }
3497 }
3498 continue;
3499 }
3500 /*
3501 * n.b. 0.3c ext2fs code didn't clear i_links_count for
3502 * deleted files. Oops.
3503 *
3504 * Since all new ext2 implementations get this right,
3505 * we now assume that the case of non-zero
3506 * i_links_count and non-zero dtime means that we
3507 * should keep the file, not delete it.
3508 *
3509 */
3510 if (inode->i_dtime) {
3511 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
3512 inode->i_dtime = 0;
3513 e2fsck_write_inode(ctx, ino, inode, "pass1");
3514 }
3515 }
3516
3517 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
3518 switch (fs->super->s_creator_os) {
3519 case EXT2_OS_LINUX:
3520 frag = inode->osd2.linux2.l_i_frag;
3521 fsize = inode->osd2.linux2.l_i_fsize;
3522 break;
3523 case EXT2_OS_HURD:
3524 frag = inode->osd2.hurd2.h_i_frag;
3525 fsize = inode->osd2.hurd2.h_i_fsize;
3526 break;
3527 case EXT2_OS_MASIX:
3528 frag = inode->osd2.masix2.m_i_frag;
3529 fsize = inode->osd2.masix2.m_i_fsize;
3530 break;
3531 default:
3532 frag = fsize = 0;
3533 }
3534
3535 if (inode->i_faddr || frag || fsize ||
3536 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
3537 mark_inode_bad(ctx, ino);
3538 if (inode->i_flags & EXT2_IMAGIC_FL) {
3539 if (imagic_fs) {
3540 if (!ctx->inode_imagic_map)
3541 alloc_imagic_map(ctx);
3542 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
3543 ino);
3544 } else {
3545 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
3546 inode->i_flags &= ~EXT2_IMAGIC_FL;
3547 e2fsck_write_inode(ctx, ino,
3548 inode, "pass1");
3549 }
3550 }
3551 }
3552
3553 check_inode_extra_space(ctx, &pctx);
3554
3555 if (LINUX_S_ISDIR(inode->i_mode)) {
3556 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
3557 e2fsck_add_dir_info(ctx, ino, 0);
3558 ctx->fs_directory_count++;
3559 } else if (LINUX_S_ISREG (inode->i_mode)) {
3560 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
3561 ctx->fs_regular_count++;
3562 } else if (LINUX_S_ISCHR (inode->i_mode) &&
3563 e2fsck_pass1_check_device_inode(fs, inode)) {
3564 check_immutable(ctx, &pctx);
3565 check_size(ctx, &pctx);
3566 ctx->fs_chardev_count++;
3567 } else if (LINUX_S_ISBLK (inode->i_mode) &&
3568 e2fsck_pass1_check_device_inode(fs, inode)) {
3569 check_immutable(ctx, &pctx);
3570 check_size(ctx, &pctx);
3571 ctx->fs_blockdev_count++;
3572 } else if (LINUX_S_ISLNK (inode->i_mode) &&
3573 e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
3574 check_immutable(ctx, &pctx);
3575 ctx->fs_symlinks_count++;
3576 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
3577 ctx->fs_fast_symlinks_count++;
3578 check_blocks(ctx, &pctx, block_buf);
3579 continue;
3580 }
3581 }
3582 else if (LINUX_S_ISFIFO (inode->i_mode) &&
3583 e2fsck_pass1_check_device_inode(fs, inode)) {
3584 check_immutable(ctx, &pctx);
3585 check_size(ctx, &pctx);
3586 ctx->fs_fifo_count++;
3587 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
3588 e2fsck_pass1_check_device_inode(fs, inode)) {
3589 check_immutable(ctx, &pctx);
3590 check_size(ctx, &pctx);
3591 ctx->fs_sockets_count++;
3592 } else
3593 mark_inode_bad(ctx, ino);
3594 if (inode->i_block[EXT2_IND_BLOCK])
3595 ctx->fs_ind_count++;
3596 if (inode->i_block[EXT2_DIND_BLOCK])
3597 ctx->fs_dind_count++;
3598 if (inode->i_block[EXT2_TIND_BLOCK])
3599 ctx->fs_tind_count++;
3600 if (inode->i_block[EXT2_IND_BLOCK] ||
3601 inode->i_block[EXT2_DIND_BLOCK] ||
3602 inode->i_block[EXT2_TIND_BLOCK] ||
3603 inode->i_file_acl) {
3604 inodes_to_process[process_inode_count].ino = ino;
3605 inodes_to_process[process_inode_count].inode = *inode;
3606 process_inode_count++;
3607 } else
3608 check_blocks(ctx, &pctx, block_buf);
3609
3610 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3611 return;
3612
3613 if (process_inode_count >= ctx->process_inode_size) {
3614 process_inodes(ctx, block_buf);
3615
3616 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3617 return;
3618 }
3619 }
3620 process_inodes(ctx, block_buf);
3621 ext2fs_close_inode_scan(scan);
3622 ehandler_operation(0);
3623
3624 /*
3625 * If any extended attribute blocks' reference counts need to
3626 * be adjusted, either up (ctx->refcount_extra), or down
3627 * (ctx->refcount), then fix them.
3628 */
3629 if (ctx->refcount) {
3630 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
3631 ea_refcount_free(ctx->refcount);
3632 ctx->refcount = 0;
3633 }
3634 if (ctx->refcount_extra) {
3635 adjust_extattr_refcount(ctx, ctx->refcount_extra,
3636 block_buf, +1);
3637 ea_refcount_free(ctx->refcount_extra);
3638 ctx->refcount_extra = 0;
3639 }
3640
3641 if (ctx->invalid_bitmaps)
3642 handle_fs_bad_blocks(ctx);
3643
3644 /* We don't need the block_ea_map any more */
3645 ext2fs_free_block_bitmap(ctx->block_ea_map);
3646 ctx->block_ea_map = 0;
3647
3648 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
3649 ext2fs_block_bitmap save_bmap;
3650
3651 save_bmap = fs->block_map;
3652 fs->block_map = ctx->block_found_map;
3653 clear_problem_context(&pctx);
3654 pctx.errcode = ext2fs_create_resize_inode(fs);
3655 if (pctx.errcode) {
3656 fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
3657 /* Should never get here */
3658 ctx->flags |= E2F_FLAG_ABORT;
3659 return;
3660 }
3661 e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
3662 "recreate inode");
3663 inode->i_mtime = time(0);
3664 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
3665 "recreate inode");
3666 fs->block_map = save_bmap;
3667 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
3668 }
3669
3670 if (ctx->flags & E2F_FLAG_RESTART) {
3671 /*
3672 * Only the master copy of the superblock and block
3673 * group descriptors are going to be written during a
3674 * restart, so set the superblock to be used to be the
3675 * master superblock.
3676 */
3677 ctx->use_superblock = 0;
3678 unwind_pass1();
3679 goto endit;
3680 }
3681
3682 if (ctx->block_dup_map) {
3683 if (ctx->options & E2F_OPT_PREEN) {
3684 clear_problem_context(&pctx);
3685 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
3686 }
3687 e2fsck_pass1_dupblocks(ctx, block_buf);
3688 }
3689 ext2fs_free_mem(&inodes_to_process);
3690endit:
3691 e2fsck_use_inode_shortcuts(ctx, 0);
3692
3693 ext2fs_free_mem(&block_buf);
3694 ext2fs_free_mem(&inode);
3695
3696}
3697
3698/*
3699 * When the inode_scan routines call this callback at the end of the
3700 * glock group, call process_inodes.
3701 */
3702static errcode_t scan_callback(ext2_filsys fs,
3703 dgrp_t group, void * priv_data)
3704{
3705 struct scan_callback_struct *scan_struct;
3706 e2fsck_t ctx;
3707
3708 scan_struct = (struct scan_callback_struct *) priv_data;
3709 ctx = scan_struct->ctx;
3710
3711 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
3712
3713 if (ctx->progress)
3714 if ((ctx->progress)(ctx, 1, group+1,
3715 ctx->fs->group_desc_count))
3716 return EXT2_ET_CANCEL_REQUESTED;
3717
3718 return 0;
3719}
3720
3721/*
3722 * Process the inodes in the "inodes to process" list.
3723 */
3724static void process_inodes(e2fsck_t ctx, char *block_buf)
3725{
3726 int i;
3727 struct ext2_inode *old_stashed_inode;
3728 ext2_ino_t old_stashed_ino;
3729 const char *old_operation;
3730 char buf[80];
3731 struct problem_context pctx;
3732
3733 /* begin process_inodes */
3734 if (process_inode_count == 0)
3735 return;
3736 old_operation = ehandler_operation(0);
3737 old_stashed_inode = ctx->stashed_inode;
3738 old_stashed_ino = ctx->stashed_ino;
3739 qsort(inodes_to_process, process_inode_count,
3740 sizeof(struct process_inode_block), process_inode_cmp);
3741 clear_problem_context(&pctx);
3742 for (i=0; i < process_inode_count; i++) {
3743 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
3744 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
3745 sprintf(buf, _("reading indirect blocks of inode %u"),
3746 pctx.ino);
3747 ehandler_operation(buf);
3748 check_blocks(ctx, &pctx, block_buf);
3749 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
3750 break;
3751 }
3752 ctx->stashed_inode = old_stashed_inode;
3753 ctx->stashed_ino = old_stashed_ino;
3754 process_inode_count = 0;
3755 /* end process inodes */
3756
3757 ehandler_operation(old_operation);
3758}
3759
3760static int process_inode_cmp(const void *a, const void *b)
3761{
3762 const struct process_inode_block *ib_a =
3763 (const struct process_inode_block *) a;
3764 const struct process_inode_block *ib_b =
3765 (const struct process_inode_block *) b;
3766 int ret;
3767
3768 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
3769 ib_b->inode.i_block[EXT2_IND_BLOCK]);
3770 if (ret == 0)
3771 ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
3772 return ret;
3773}
3774
3775/*
3776 * Mark an inode as being bad in some what
3777 */
3778static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
3779{
3780 struct problem_context pctx;
3781
3782 if (!ctx->inode_bad_map) {
3783 clear_problem_context(&pctx);
3784
3785 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
3786 _("bad inode map"), &ctx->inode_bad_map);
3787 if (pctx.errcode) {
3788 pctx.num = 3;
3789 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3790 /* Should never get here */
3791 ctx->flags |= E2F_FLAG_ABORT;
3792 return;
3793 }
3794 }
3795 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
3796}
3797
3798
3799/*
3800 * This procedure will allocate the inode imagic table
3801 */
3802static void alloc_imagic_map(e2fsck_t ctx)
3803{
3804 struct problem_context pctx;
3805
3806 clear_problem_context(&pctx);
3807 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
3808 _("imagic inode map"),
3809 &ctx->inode_imagic_map);
3810 if (pctx.errcode) {
3811 pctx.num = 5;
3812 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
3813 /* Should never get here */
3814 ctx->flags |= E2F_FLAG_ABORT;
3815 return;
3816 }
3817}
3818
3819/*
3820 * Marks a block as in use, setting the dup_map if it's been set
3821 * already. Called by process_block and process_bad_block.
3822 *
3823 * WARNING: Assumes checks have already been done to make sure block
3824 * is valid. This is true in both process_block and process_bad_block.
3825 */
3826static void mark_block_used(e2fsck_t ctx, blk_t block)
3827{
3828 struct problem_context pctx;
3829
3830 clear_problem_context(&pctx);
3831
3832 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
3833 if (!ctx->block_dup_map) {
3834 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
3835 _("multiply claimed block map"),
3836 &ctx->block_dup_map);
3837 if (pctx.errcode) {
3838 pctx.num = 3;
3839 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
3840 &pctx);
3841 /* Should never get here */
3842 ctx->flags |= E2F_FLAG_ABORT;
3843 return;
3844 }
3845 }
3846 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
3847 } else {
3848 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
3849 }
3850}
3851
3852/*
3853 * Adjust the extended attribute block's reference counts at the end
3854 * of pass 1, either by subtracting out references for EA blocks that
3855 * are still referenced in ctx->refcount, or by adding references for
3856 * EA blocks that had extra references as accounted for in
3857 * ctx->refcount_extra.
3858 */
3859static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
3860 char *block_buf, int adjust_sign)
3861{
3862 struct ext2_ext_attr_header *header;
3863 struct problem_context pctx;
3864 ext2_filsys fs = ctx->fs;
3865 blk_t blk;
3866 __u32 should_be;
3867 int count;
3868
3869 clear_problem_context(&pctx);
3870
3871 ea_refcount_intr_begin(refcount);
3872 while (1) {
3873 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
3874 break;
3875 pctx.blk = blk;
3876 pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
3877 if (pctx.errcode) {
3878 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
3879 return;
3880 }
3881 header = (struct ext2_ext_attr_header *) block_buf;
3882 pctx.blkcount = header->h_refcount;
3883 should_be = header->h_refcount + adjust_sign * count;
3884 pctx.num = should_be;
3885 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
3886 header->h_refcount = should_be;
3887 pctx.errcode = ext2fs_write_ext_attr(fs, blk,
3888 block_buf);
3889 if (pctx.errcode) {
3890 fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
3891 continue;
3892 }
3893 }
3894 }
3895}
3896
3897/*
3898 * Handle processing the extended attribute blocks
3899 */
3900static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
3901 char *block_buf)
3902{
3903 ext2_filsys fs = ctx->fs;
3904 ext2_ino_t ino = pctx->ino;
3905 struct ext2_inode *inode = pctx->inode;
3906 blk_t blk;
3907 char * end;
3908 struct ext2_ext_attr_header *header;
3909 struct ext2_ext_attr_entry *entry;
3910 int count;
3911 region_t region;
3912
3913 blk = inode->i_file_acl;
3914 if (blk == 0)
3915 return 0;
3916
3917 /*
3918 * If the Extended attribute flag isn't set, then a non-zero
3919 * file acl means that the inode is corrupted.
3920 *
3921 * Or if the extended attribute block is an invalid block,
3922 * then the inode is also corrupted.
3923 */
3924 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
3925 (blk < fs->super->s_first_data_block) ||
3926 (blk >= fs->super->s_blocks_count)) {
3927 mark_inode_bad(ctx, ino);
3928 return 0;
3929 }
3930
3931 /* If ea bitmap hasn't been allocated, create it */
3932 if (!ctx->block_ea_map) {
3933 pctx->errcode = ext2fs_allocate_block_bitmap(fs,
3934 _("ext attr block map"),
3935 &ctx->block_ea_map);
3936 if (pctx->errcode) {
3937 pctx->num = 2;
3938 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
3939 ctx->flags |= E2F_FLAG_ABORT;
3940 return 0;
3941 }
3942 }
3943
3944 /* Create the EA refcount structure if necessary */
3945 if (!ctx->refcount) {
3946 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
3947 if (pctx->errcode) {
3948 pctx->num = 1;
3949 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
3950 ctx->flags |= E2F_FLAG_ABORT;
3951 return 0;
3952 }
3953 }
3954
3955 /* Have we seen this EA block before? */
3956 if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
3957 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
3958 return 1;
3959 /* Ooops, this EA was referenced more than it stated */
3960 if (!ctx->refcount_extra) {
3961 pctx->errcode = ea_refcount_create(0,
3962 &ctx->refcount_extra);
3963 if (pctx->errcode) {
3964 pctx->num = 2;
3965 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
3966 ctx->flags |= E2F_FLAG_ABORT;
3967 return 0;
3968 }
3969 }
3970 ea_refcount_increment(ctx->refcount_extra, blk, 0);
3971 return 1;
3972 }
3973
3974 /*
3975 * OK, we haven't seen this EA block yet. So we need to
3976 * validate it
3977 */
3978 pctx->blk = blk;
3979 pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
3980 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
3981 goto clear_extattr;
3982 header = (struct ext2_ext_attr_header *) block_buf;
3983 pctx->blk = inode->i_file_acl;
3984 if (((ctx->ext_attr_ver == 1) &&
3985 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
3986 ((ctx->ext_attr_ver == 2) &&
3987 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
3988 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
3989 goto clear_extattr;
3990 }
3991
3992 if (header->h_blocks != 1) {
3993 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
3994 goto clear_extattr;
3995 }
3996
3997 region = region_create(0, fs->blocksize);
3998 if (!region) {
3999 fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
4000 ctx->flags |= E2F_FLAG_ABORT;
4001 return 0;
4002 }
4003 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
4004 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4005 goto clear_extattr;
4006 }
4007
4008 entry = (struct ext2_ext_attr_entry *)(header+1);
4009 end = block_buf + fs->blocksize;
4010 while ((char *)entry < end && *(__u32 *)entry) {
4011 if (region_allocate(region, (char *)entry - (char *)header,
4012 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
4013 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4014 goto clear_extattr;
4015 }
4016 if ((ctx->ext_attr_ver == 1 &&
4017 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
4018 (ctx->ext_attr_ver == 2 &&
4019 entry->e_name_index == 0)) {
4020 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
4021 goto clear_extattr;
4022 }
4023 if (entry->e_value_block != 0) {
4024 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
4025 goto clear_extattr;
4026 }
4027 if (entry->e_value_size &&
4028 region_allocate(region, entry->e_value_offs,
4029 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
4030 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4031 goto clear_extattr;
4032 }
4033 entry = EXT2_EXT_ATTR_NEXT(entry);
4034 }
4035 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
4036 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
4037 goto clear_extattr;
4038 }
4039 region_free(region);
4040
4041 count = header->h_refcount - 1;
4042 if (count)
4043 ea_refcount_store(ctx->refcount, blk, count);
4044 mark_block_used(ctx, blk);
4045 ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
4046
4047 return 1;
4048
4049clear_extattr:
4050 inode->i_file_acl = 0;
4051 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
4052 return 0;
4053}
4054
4055/* Returns 1 if bad htree, 0 if OK */
4056static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
4057 ext2_ino_t ino FSCK_ATTR((unused)),
4058 struct ext2_inode *inode,
4059 char *block_buf)
4060{
4061 struct ext2_dx_root_info *root;
4062 ext2_filsys fs = ctx->fs;
4063 errcode_t retval;
4064 blk_t blk;
4065
4066 if ((!LINUX_S_ISDIR(inode->i_mode) &&
4067 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
4068 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
4069 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
4070 return 1;
4071
4072 blk = inode->i_block[0];
4073 if (((blk == 0) ||
4074 (blk < fs->super->s_first_data_block) ||
4075 (blk >= fs->super->s_blocks_count)) &&
4076 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
4077 return 1;
4078
4079 retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
4080 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
4081 return 1;
4082
4083 /* XXX should check that beginning matches a directory */
4084 root = (struct ext2_dx_root_info *) (block_buf + 24);
4085
4086 if ((root->reserved_zero || root->info_length < 8) &&
4087 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
4088 return 1;
4089
4090 pctx->num = root->hash_version;
4091 if ((root->hash_version != EXT2_HASH_LEGACY) &&
4092 (root->hash_version != EXT2_HASH_HALF_MD4) &&
4093 (root->hash_version != EXT2_HASH_TEA) &&
4094 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
4095 return 1;
4096
4097 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
4098 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
4099 return 1;
4100
4101 pctx->num = root->indirect_levels;
4102 if ((root->indirect_levels > 1) &&
4103 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
4104 return 1;
4105
4106 return 0;
4107}
4108
4109/*
4110 * This subroutine is called on each inode to account for all of the
4111 * blocks used by that inode.
4112 */
4113static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
4114 char *block_buf)
4115{
4116 ext2_filsys fs = ctx->fs;
4117 struct process_block_struct_1 pb;
4118 ext2_ino_t ino = pctx->ino;
4119 struct ext2_inode *inode = pctx->inode;
4120 int bad_size = 0;
4121 int dirty_inode = 0;
4122 __u64 size;
4123
4124 pb.ino = ino;
4125 pb.num_blocks = 0;
4126 pb.last_block = -1;
4127 pb.num_illegal_blocks = 0;
4128 pb.suppress = 0; pb.clear = 0;
4129 pb.fragmented = 0;
4130 pb.compressed = 0;
4131 pb.previous_block = 0;
4132 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
4133 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
4134 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
4135 pb.inode = inode;
4136 pb.pctx = pctx;
4137 pb.ctx = ctx;
4138 pctx->ino = ino;
4139 pctx->errcode = 0;
4140
4141 if (inode->i_flags & EXT2_COMPRBLK_FL) {
4142 if (fs->super->s_feature_incompat &
4143 EXT2_FEATURE_INCOMPAT_COMPRESSION)
4144 pb.compressed = 1;
4145 else {
4146 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
4147 inode->i_flags &= ~EXT2_COMPRBLK_FL;
4148 dirty_inode++;
4149 }
4150 }
4151 }
4152
4153 if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
4154 pb.num_blocks++;
4155
4156 if (ext2fs_inode_has_valid_blocks(inode))
4157 pctx->errcode = ext2fs_block_iterate2(fs, ino,
4158 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
4159 block_buf, process_block, &pb);
4160 end_problem_latch(ctx, PR_LATCH_BLOCK);
4161 end_problem_latch(ctx, PR_LATCH_TOOBIG);
4162 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4163 goto out;
4164 if (pctx->errcode)
4165 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
4166
4167 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
4168 ctx->fs_fragmented++;
4169
4170 if (pb.clear) {
4171 inode->i_links_count = 0;
4172 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
4173 inode->i_dtime = time(0);
4174 dirty_inode++;
4175 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
4176 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
4177 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
4178 /*
4179 * The inode was probably partially accounted for
4180 * before processing was aborted, so we need to
4181 * restart the pass 1 scan.
4182 */
4183 ctx->flags |= E2F_FLAG_RESTART;
4184 goto out;
4185 }
4186
4187 if (inode->i_flags & EXT2_INDEX_FL) {
4188 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
4189 inode->i_flags &= ~EXT2_INDEX_FL;
4190 dirty_inode++;
4191 } else {
4192#ifdef ENABLE_HTREE
4193 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
4194#endif
4195 }
4196 }
4197 if (ctx->dirs_to_hash && pb.is_dir &&
4198 !(inode->i_flags & EXT2_INDEX_FL) &&
4199 ((inode->i_size / fs->blocksize) >= 3))
4200 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
4201
4202 if (!pb.num_blocks && pb.is_dir) {
4203 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
4204 inode->i_links_count = 0;
4205 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
4206 inode->i_dtime = time(0);
4207 dirty_inode++;
4208 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
4209 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
4210 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
4211 ctx->fs_directory_count--;
4212 goto out;
4213 }
4214 }
4215
4216 pb.num_blocks *= (fs->blocksize / 512);
4217
4218 if (pb.is_dir) {
4219 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
4220 if (nblock > (pb.last_block + 1))
4221 bad_size = 1;
4222 else if (nblock < (pb.last_block + 1)) {
4223 if (((pb.last_block + 1) - nblock) >
4224 fs->super->s_prealloc_dir_blocks)
4225 bad_size = 2;
4226 }
4227 } else {
4228 size = EXT2_I_SIZE(inode);
4229 if ((pb.last_block >= 0) &&
4230 (size < (__u64) pb.last_block * fs->blocksize))
4231 bad_size = 3;
4232 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
4233 bad_size = 4;
4234 }
4235 /* i_size for symlinks is checked elsewhere */
4236 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
4237 pctx->num = (pb.last_block+1) * fs->blocksize;
4238 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
4239 inode->i_size = pctx->num;
4240 if (!LINUX_S_ISDIR(inode->i_mode))
4241 inode->i_size_high = pctx->num >> 32;
4242 dirty_inode++;
4243 }
4244 pctx->num = 0;
4245 }
4246 if (LINUX_S_ISREG(inode->i_mode) &&
4247 (inode->i_size_high || inode->i_size & 0x80000000UL))
4248 ctx->large_files++;
4249 if (pb.num_blocks != inode->i_blocks) {
4250 pctx->num = pb.num_blocks;
4251 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
4252 inode->i_blocks = pb.num_blocks;
4253 dirty_inode++;
4254 }
4255 pctx->num = 0;
4256 }
4257out:
4258 if (dirty_inode)
4259 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
4260}
4261
4262
4263/*
4264 * This is a helper function for check_blocks().
4265 */
4266static int process_block(ext2_filsys fs,
4267 blk_t *block_nr,
4268 e2_blkcnt_t blockcnt,
4269 blk_t ref_block FSCK_ATTR((unused)),
4270 int ref_offset FSCK_ATTR((unused)),
4271 void *priv_data)
4272{
4273 struct process_block_struct_1 *p;
4274 struct problem_context *pctx;
4275 blk_t blk = *block_nr;
4276 int ret_code = 0;
4277 int problem = 0;
4278 e2fsck_t ctx;
4279
4280 p = (struct process_block_struct_1 *) priv_data;
4281 pctx = p->pctx;
4282 ctx = p->ctx;
4283
4284 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
4285 /* todo: Check that the comprblk_fl is high, that the
4286 blkaddr pattern looks right (all non-holes up to
4287 first EXT2FS_COMPRESSED_BLKADDR, then all
4288 EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
4289 that the feature_incompat bit is high, and that the
4290 inode is a regular file. If we're doing a "full
4291 check" (a concept introduced to e2fsck by e2compr,
4292 meaning that we look at data blocks as well as
4293 metadata) then call some library routine that
4294 checks the compressed data. I'll have to think
4295 about this, because one particularly important
4296 problem to be able to fix is to recalculate the
4297 cluster size if necessary. I think that perhaps
4298 we'd better do most/all e2compr-specific checks
4299 separately, after the non-e2compr checks. If not
4300 doing a full check, it may be useful to test that
4301 the personality is linux; e.g. if it isn't then
4302 perhaps this really is just an illegal block. */
4303 return 0;
4304 }
4305
4306 if (blk == 0) {
4307 if (p->is_dir == 0) {
4308 /*
4309 * Should never happen, since only directories
4310 * get called with BLOCK_FLAG_HOLE
4311 */
4312#ifdef DEBUG_E2FSCK
4313 printf("process_block() called with blk == 0, "
4314 "blockcnt=%d, inode %lu???\n",
4315 blockcnt, p->ino);
4316#endif
4317 return 0;
4318 }
4319 if (blockcnt < 0)
4320 return 0;
4321 if (blockcnt * fs->blocksize < p->inode->i_size) {
4322 goto mark_dir;
4323 }
4324 return 0;
4325 }
4326
4327 /*
4328 * Simplistic fragmentation check. We merely require that the
4329 * file be contiguous. (Which can never be true for really
4330 * big files that are greater than a block group.)
4331 */
4332 if (!HOLE_BLKADDR(p->previous_block)) {
4333 if (p->previous_block+1 != blk)
4334 p->fragmented = 1;
4335 }
4336 p->previous_block = blk;
4337
4338 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
4339 problem = PR_1_TOOBIG_DIR;
4340 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
4341 problem = PR_1_TOOBIG_REG;
4342 if (!p->is_dir && !p->is_reg && blockcnt > 0)
4343 problem = PR_1_TOOBIG_SYMLINK;
4344
4345 if (blk < fs->super->s_first_data_block ||
4346 blk >= fs->super->s_blocks_count)
4347 problem = PR_1_ILLEGAL_BLOCK_NUM;
4348
4349 if (problem) {
4350 p->num_illegal_blocks++;
4351 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
4352 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
4353 p->clear = 1;
4354 return BLOCK_ABORT;
4355 }
4356 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
4357 p->suppress = 1;
4358 set_latch_flags(PR_LATCH_BLOCK,
4359 PRL_SUPPRESS, 0);
4360 }
4361 }
4362 pctx->blk = blk;
4363 pctx->blkcount = blockcnt;
4364 if (fix_problem(ctx, problem, pctx)) {
4365 blk = *block_nr = 0;
4366 ret_code = BLOCK_CHANGED;
4367 goto mark_dir;
4368 } else
4369 return 0;
4370 }
4371
4372 if (p->ino == EXT2_RESIZE_INO) {
4373 /*
4374 * The resize inode has already be sanity checked
4375 * during pass #0 (the superblock checks). All we
4376 * have to do is mark the double indirect block as
4377 * being in use; all of the other blocks are handled
4378 * by mark_table_blocks()).
4379 */
4380 if (blockcnt == BLOCK_COUNT_DIND)
4381 mark_block_used(ctx, blk);
4382 } else
4383 mark_block_used(ctx, blk);
4384 p->num_blocks++;
4385 if (blockcnt >= 0)
4386 p->last_block = blockcnt;
4387mark_dir:
4388 if (p->is_dir && (blockcnt >= 0)) {
4389 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
4390 blk, blockcnt);
4391 if (pctx->errcode) {
4392 pctx->blk = blk;
4393 pctx->num = blockcnt;
4394 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
4395 /* Should never get here */
4396 ctx->flags |= E2F_FLAG_ABORT;
4397 return BLOCK_ABORT;
4398 }
4399 }
4400 return ret_code;
4401}
4402
4403static int process_bad_block(ext2_filsys fs FSCK_ATTR((unused)),
4404 blk_t *block_nr,
4405 e2_blkcnt_t blockcnt,
4406 blk_t ref_block FSCK_ATTR((unused)),
4407 int ref_offset FSCK_ATTR((unused)),
4408 void *priv_data EXT2FS_ATTR((unused)))
4409{
4410 /*
4411 * Note: This function processes blocks for the bad blocks
4412 * inode, which is never compressed. So we don't use HOLE_BLKADDR().
4413 */
4414
4415 printf("Unrecoverable Error: Found %"PRIi64" bad blocks starting at block number: %u\n", blockcnt, *block_nr);
4416 return BLOCK_ERROR;
4417}
4418
4419/*
4420 * This routine gets called at the end of pass 1 if bad blocks are
4421 * detected in the superblock, group descriptors, inode_bitmaps, or
4422 * block bitmaps. At this point, all of the blocks have been mapped
4423 * out, so we can try to allocate new block(s) to replace the bad
4424 * blocks.
4425 */
4426static void handle_fs_bad_blocks(e2fsck_t ctx)
4427{
4428 printf("Bad blocks detected on your filesystem\n"
4429 "You should get your data off as the device will soon die\n");
4430}
4431
4432/*
4433 * This routine marks all blocks which are used by the superblock,
4434 * group descriptors, inode bitmaps, and block bitmaps.
4435 */
4436static void mark_table_blocks(e2fsck_t ctx)
4437{
4438 ext2_filsys fs = ctx->fs;
4439 blk_t block, b;
4440 dgrp_t i;
4441 int j;
4442 struct problem_context pctx;
4443
4444 clear_problem_context(&pctx);
4445
4446 block = fs->super->s_first_data_block;
4447 for (i = 0; i < fs->group_desc_count; i++) {
4448 pctx.group = i;
4449
4450 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
4451
4452 /*
4453 * Mark the blocks used for the inode table
4454 */
4455 if (fs->group_desc[i].bg_inode_table) {
4456 for (j = 0, b = fs->group_desc[i].bg_inode_table;
4457 j < fs->inode_blocks_per_group;
4458 j++, b++) {
4459 if (ext2fs_test_block_bitmap(ctx->block_found_map,
4460 b)) {
4461 pctx.blk = b;
4462 if (fix_problem(ctx,
4463 PR_1_ITABLE_CONFLICT, &pctx)) {
4464 ctx->invalid_inode_table_flag[i]++;
4465 ctx->invalid_bitmaps++;
4466 }
4467 } else {
4468 ext2fs_mark_block_bitmap(ctx->block_found_map,
4469 b);
4470 }
4471 }
4472 }
4473
4474 /*
4475 * Mark block used for the block bitmap
4476 */
4477 if (fs->group_desc[i].bg_block_bitmap) {
4478 if (ext2fs_test_block_bitmap(ctx->block_found_map,
4479 fs->group_desc[i].bg_block_bitmap)) {
4480 pctx.blk = fs->group_desc[i].bg_block_bitmap;
4481 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
4482 ctx->invalid_block_bitmap_flag[i]++;
4483 ctx->invalid_bitmaps++;
4484 }
4485 } else {
4486 ext2fs_mark_block_bitmap(ctx->block_found_map,
4487 fs->group_desc[i].bg_block_bitmap);
4488 }
4489
4490 }
4491 /*
4492 * Mark block used for the inode bitmap
4493 */
4494 if (fs->group_desc[i].bg_inode_bitmap) {
4495 if (ext2fs_test_block_bitmap(ctx->block_found_map,
4496 fs->group_desc[i].bg_inode_bitmap)) {
4497 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
4498 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
4499 ctx->invalid_inode_bitmap_flag[i]++;
4500 ctx->invalid_bitmaps++;
4501 }
4502 } else {
4503 ext2fs_mark_block_bitmap(ctx->block_found_map,
4504 fs->group_desc[i].bg_inode_bitmap);
4505 }
4506 }
4507 block += fs->super->s_blocks_per_group;
4508 }
4509}
4510
4511/*
4512 * Thes subroutines short circuits ext2fs_get_blocks and
4513 * ext2fs_check_directory; we use them since we already have the inode
4514 * structure, so there's no point in letting the ext2fs library read
4515 * the inode again.
4516 */
4517static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
4518 blk_t *blocks)
4519{
4520 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4521 int i;
4522
4523 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
4524 return EXT2_ET_CALLBACK_NOTHANDLED;
4525
4526 for (i=0; i < EXT2_N_BLOCKS; i++)
4527 blocks[i] = ctx->stashed_inode->i_block[i];
4528 return 0;
4529}
4530
4531static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
4532 struct ext2_inode *inode)
4533{
4534 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4535
4536 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
4537 return EXT2_ET_CALLBACK_NOTHANDLED;
4538 *inode = *ctx->stashed_inode;
4539 return 0;
4540}
4541
4542static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
4543 struct ext2_inode *inode)
4544{
4545 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4546
4547 if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
4548 *ctx->stashed_inode = *inode;
4549 return EXT2_ET_CALLBACK_NOTHANDLED;
4550}
4551
4552static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
4553{
4554 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
4555
4556 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
4557 return EXT2_ET_CALLBACK_NOTHANDLED;
4558
4559 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
4560 return EXT2_ET_NO_DIRECTORY;
4561 return 0;
4562}
4563
4564void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
4565{
4566 ext2_filsys fs = ctx->fs;
4567
4568 if (bool) {
4569 fs->get_blocks = pass1_get_blocks;
4570 fs->check_directory = pass1_check_directory;
4571 fs->read_inode = pass1_read_inode;
4572 fs->write_inode = pass1_write_inode;
4573 ctx->stashed_ino = 0;
4574 } else {
4575 fs->get_blocks = 0;
4576 fs->check_directory = 0;
4577 fs->read_inode = 0;
4578 fs->write_inode = 0;
4579 }
4580}
4581
4582/*
4583 * pass1b.c --- Pass #1b of e2fsck
4584 *
4585 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
4586 * only invoked if pass 1 discovered blocks which are in use by more
4587 * than one inode.
4588 *
4589 * Pass1B scans the data blocks of all the inodes again, generating a
4590 * complete list of duplicate blocks and which inodes have claimed
4591 * them.
4592 *
4593 * Pass1C does a tree-traversal of the filesystem, to determine the
4594 * parent directories of these inodes. This step is necessary so that
4595 * e2fsck can print out the pathnames of affected inodes.
4596 *
4597 * Pass1D is a reconciliation pass. For each inode with duplicate
4598 * blocks, the user is prompted if s/he would like to clone the file
4599 * (so that the file gets a fresh copy of the duplicated blocks) or
4600 * simply to delete the file.
4601 *
4602 */
4603
4604
4605/* Needed for architectures where sizeof(int) != sizeof(void *) */
4606#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
4607#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
4608
4609/* Define an extension to the ext2 library's block count information */
4610#define BLOCK_COUNT_EXTATTR (-5)
4611
4612struct block_el {
4613 blk_t block;
4614 struct block_el *next;
4615};
4616
4617struct inode_el {
4618 ext2_ino_t inode;
4619 struct inode_el *next;
4620};
4621
4622struct dup_block {
4623 int num_bad;
4624 struct inode_el *inode_list;
4625};
4626
4627/*
4628 * This structure stores information about a particular inode which
4629 * is sharing blocks with other inodes. This information is collected
4630 * to display to the user, so that the user knows what files he or she
4631 * is dealing with, when trying to decide how to resolve the conflict
4632 * of multiply-claimed blocks.
4633 */
4634struct dup_inode {
4635 ext2_ino_t dir;
4636 int num_dupblocks;
4637 struct ext2_inode inode;
4638 struct block_el *block_list;
4639};
4640
4641static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
4642 e2_blkcnt_t blockcnt, blk_t ref_blk,
4643 int ref_offset, void *priv_data);
4644static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
4645 struct dup_inode *dp, char *block_buf);
4646static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
4647 struct dup_inode *dp, char* block_buf);
4648static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
4649
4650static void pass1b(e2fsck_t ctx, char *block_buf);
4651static void pass1c(e2fsck_t ctx, char *block_buf);
4652static void pass1d(e2fsck_t ctx, char *block_buf);
4653
4654static int dup_inode_count = 0;
4655
4656static dict_t blk_dict, ino_dict;
4657
4658static ext2fs_inode_bitmap inode_dup_map;
4659
4660static int dict_int_cmp(const void *a, const void *b)
4661{
4662 intptr_t ia, ib;
4663
4664 ia = (intptr_t)a;
4665 ib = (intptr_t)b;
4666
4667 return (ia-ib);
4668}
4669
4670/*
4671 * Add a duplicate block record
4672 */
4673static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
4674 struct ext2_inode *inode)
4675{
4676 dnode_t *n;
4677 struct dup_block *db;
4678 struct dup_inode *di;
4679 struct block_el *blk_el;
4680 struct inode_el *ino_el;
4681
4682 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
4683 if (n)
4684 db = (struct dup_block *) dnode_get(n);
4685 else {
4686 db = (struct dup_block *) e2fsck_allocate_memory(ctx,
4687 sizeof(struct dup_block), "duplicate block header");
4688 db->num_bad = 0;
4689 db->inode_list = 0;
4690 dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
4691 }
4692 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
4693 sizeof(struct inode_el), "inode element");
4694 ino_el->inode = ino;
4695 ino_el->next = db->inode_list;
4696 db->inode_list = ino_el;
4697 db->num_bad++;
4698
4699 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
4700 if (n)
4701 di = (struct dup_inode *) dnode_get(n);
4702 else {
4703 di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
4704 sizeof(struct dup_inode), "duplicate inode header");
4705 di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0 ;
4706 di->num_dupblocks = 0;
4707 di->block_list = 0;
4708 di->inode = *inode;
4709 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
4710 }
4711 blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
4712 sizeof(struct block_el), "block element");
4713 blk_el->block = blk;
4714 blk_el->next = di->block_list;
4715 di->block_list = blk_el;
4716 di->num_dupblocks++;
4717}
4718
4719/*
4720 * Free a duplicate inode record
4721 */
4722static void inode_dnode_free(dnode_t *node)
4723{
4724 struct dup_inode *di;
4725 struct block_el *p, *next;
4726
4727 di = (struct dup_inode *) dnode_get(node);
4728 for (p = di->block_list; p; p = next) {
4729 next = p->next;
4730 free(p);
4731 }
4732 free(node);
4733}
4734
4735/*
4736 * Free a duplicate block record
4737 */
4738static void block_dnode_free(dnode_t *node)
4739{
4740 struct dup_block *db;
4741 struct inode_el *p, *next;
4742
4743 db = (struct dup_block *) dnode_get(node);
4744 for (p = db->inode_list; p; p = next) {
4745 next = p->next;
4746 free(p);
4747 }
4748 free(node);
4749}
4750
4751
4752/*
4753 * Main procedure for handling duplicate blocks
4754 */
4755void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
4756{
4757 ext2_filsys fs = ctx->fs;
4758 struct problem_context pctx;
4759
4760 clear_problem_context(&pctx);
4761
4762 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4763 _("multiply claimed inode map"), &inode_dup_map);
4764 if (pctx.errcode) {
4765 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
4766 ctx->flags |= E2F_FLAG_ABORT;
4767 return;
4768 }
4769
4770 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
4771 dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
4772 dict_set_allocator(&ino_dict, inode_dnode_free);
4773 dict_set_allocator(&blk_dict, block_dnode_free);
4774
4775 pass1b(ctx, block_buf);
4776 pass1c(ctx, block_buf);
4777 pass1d(ctx, block_buf);
4778
4779 /*
4780 * Time to free all of the accumulated data structures that we
4781 * don't need anymore.
4782 */
4783 dict_free_nodes(&ino_dict);
4784 dict_free_nodes(&blk_dict);
4785}
4786
4787/*
4788 * Scan the inodes looking for inodes that contain duplicate blocks.
4789 */
4790struct process_block_struct_1b {
4791 e2fsck_t ctx;
4792 ext2_ino_t ino;
4793 int dup_blocks;
4794 struct ext2_inode *inode;
4795 struct problem_context *pctx;
4796};
4797
4798static void pass1b(e2fsck_t ctx, char *block_buf)
4799{
4800 ext2_filsys fs = ctx->fs;
4801 ext2_ino_t ino;
4802 struct ext2_inode inode;
4803 ext2_inode_scan scan;
4804 struct process_block_struct_1b pb;
4805 struct problem_context pctx;
4806
4807 clear_problem_context(&pctx);
4808
4809 if (!(ctx->options & E2F_OPT_PREEN))
4810 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
4811 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
4812 &scan);
4813 if (pctx.errcode) {
4814 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
4815 ctx->flags |= E2F_FLAG_ABORT;
4816 return;
4817 }
4818 ctx->stashed_inode = &inode;
4819 pb.ctx = ctx;
4820 pb.pctx = &pctx;
4821 pctx.str = "pass1b";
4822 while (1) {
4823 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
4824 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
4825 continue;
4826 if (pctx.errcode) {
4827 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
4828 ctx->flags |= E2F_FLAG_ABORT;
4829 return;
4830 }
4831 if (!ino)
4832 break;
4833 pctx.ino = ctx->stashed_ino = ino;
4834 if ((ino != EXT2_BAD_INO) &&
4835 !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
4836 continue;
4837
4838 pb.ino = ino;
4839 pb.dup_blocks = 0;
4840 pb.inode = &inode;
4841
4842 if (ext2fs_inode_has_valid_blocks(&inode) ||
4843 (ino == EXT2_BAD_INO))
4844 pctx.errcode = ext2fs_block_iterate2(fs, ino,
4845 0, block_buf, process_pass1b_block, &pb);
4846 if (inode.i_file_acl)
4847 process_pass1b_block(fs, &inode.i_file_acl,
4848 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
4849 if (pb.dup_blocks) {
4850 end_problem_latch(ctx, PR_LATCH_DBLOCK);
4851 if (ino >= EXT2_FIRST_INODE(fs->super) ||
4852 ino == EXT2_ROOT_INO)
4853 dup_inode_count++;
4854 }
4855 if (pctx.errcode)
4856 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
4857 }
4858 ext2fs_close_inode_scan(scan);
4859 e2fsck_use_inode_shortcuts(ctx, 0);
4860}
4861
4862static int process_pass1b_block(ext2_filsys fs FSCK_ATTR((unused)),
4863 blk_t *block_nr,
4864 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
4865 blk_t ref_blk FSCK_ATTR((unused)),
4866 int ref_offset FSCK_ATTR((unused)),
4867 void *priv_data)
4868{
4869 struct process_block_struct_1b *p;
4870 e2fsck_t ctx;
4871
4872 if (HOLE_BLKADDR(*block_nr))
4873 return 0;
4874 p = (struct process_block_struct_1b *) priv_data;
4875 ctx = p->ctx;
4876
4877 if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
4878 return 0;
4879
4880 /* OK, this is a duplicate block */
4881 if (p->ino != EXT2_BAD_INO) {
4882 p->pctx->blk = *block_nr;
4883 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
4884 }
4885 p->dup_blocks++;
4886 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
4887
4888 add_dupe(ctx, p->ino, *block_nr, p->inode);
4889
4890 return 0;
4891}
4892
4893/*
4894 * Pass 1c: Scan directories for inodes with duplicate blocks. This
4895 * is used so that we can print pathnames when prompting the user for
4896 * what to do.
4897 */
4898struct search_dir_struct {
4899 int count;
4900 ext2_ino_t first_inode;
4901 ext2_ino_t max_inode;
4902};
4903
4904static int search_dirent_proc(ext2_ino_t dir, int entry,
4905 struct ext2_dir_entry *dirent,
4906 int offset FSCK_ATTR((unused)),
4907 int blocksize FSCK_ATTR((unused)),
4908 char *buf FSCK_ATTR((unused)),
4909 void *priv_data)
4910{
4911 struct search_dir_struct *sd;
4912 struct dup_inode *p;
4913 dnode_t *n;
4914
4915 sd = (struct search_dir_struct *) priv_data;
4916
4917 if (dirent->inode > sd->max_inode)
4918 /* Should abort this inode, but not everything */
4919 return 0;
4920
4921 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
4922 !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
4923 return 0;
4924
4925 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
4926 if (!n)
4927 return 0;
4928 p = (struct dup_inode *) dnode_get(n);
4929 p->dir = dir;
4930 sd->count--;
4931
4932 return sd->count ? 0 : DIRENT_ABORT;
4933}
4934
4935
4936static void pass1c(e2fsck_t ctx, char *block_buf)
4937{
4938 ext2_filsys fs = ctx->fs;
4939 struct search_dir_struct sd;
4940 struct problem_context pctx;
4941
4942 clear_problem_context(&pctx);
4943
4944 if (!(ctx->options & E2F_OPT_PREEN))
4945 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
4946
4947 /*
4948 * Search through all directories to translate inodes to names
4949 * (by searching for the containing directory for that inode.)
4950 */
4951 sd.count = dup_inode_count;
4952 sd.first_inode = EXT2_FIRST_INODE(fs->super);
4953 sd.max_inode = fs->super->s_inodes_count;
4954 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
4955 search_dirent_proc, &sd);
4956}
4957
4958static void pass1d(e2fsck_t ctx, char *block_buf)
4959{
4960 ext2_filsys fs = ctx->fs;
4961 struct dup_inode *p, *t;
4962 struct dup_block *q;
4963 ext2_ino_t *shared, ino;
4964 int shared_len;
4965 int i;
4966 int file_ok;
4967 int meta_data = 0;
4968 struct problem_context pctx;
4969 dnode_t *n, *m;
4970 struct block_el *s;
4971 struct inode_el *r;
4972
4973 clear_problem_context(&pctx);
4974
4975 if (!(ctx->options & E2F_OPT_PREEN))
4976 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
4977 e2fsck_read_bitmaps(ctx);
4978
4979 pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
4980 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
4981 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
4982 sizeof(ext2_ino_t) * dict_count(&ino_dict),
4983 "Shared inode list");
4984 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
4985 p = (struct dup_inode *) dnode_get(n);
4986 shared_len = 0;
4987 file_ok = 1;
4988 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
4989 if (ino == EXT2_BAD_INO || ino == EXT2_RESIZE_INO)
4990 continue;
4991
4992 /*
4993 * Find all of the inodes which share blocks with this
4994 * one. First we find all of the duplicate blocks
4995 * belonging to this inode, and then search each block
4996 * get the list of inodes, and merge them together.
4997 */
4998 for (s = p->block_list; s; s = s->next) {
4999 m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
5000 if (!m)
5001 continue; /* Should never happen... */
5002 q = (struct dup_block *) dnode_get(m);
5003 if (q->num_bad > 1)
5004 file_ok = 0;
5005 if (check_if_fs_block(ctx, s->block)) {
5006 file_ok = 0;
5007 meta_data = 1;
5008 }
5009
5010 /*
5011 * Add all inodes used by this block to the
5012 * shared[] --- which is a unique list, so
5013 * if an inode is already in shared[], don't
5014 * add it again.
5015 */
5016 for (r = q->inode_list; r; r = r->next) {
5017 if (r->inode == ino)
5018 continue;
5019 for (i = 0; i < shared_len; i++)
5020 if (shared[i] == r->inode)
5021 break;
5022 if (i == shared_len) {
5023 shared[shared_len++] = r->inode;
5024 }
5025 }
5026 }
5027
5028 /*
5029 * Report the inode that we are working on
5030 */
5031 pctx.inode = &p->inode;
5032 pctx.ino = ino;
5033 pctx.dir = p->dir;
5034 pctx.blkcount = p->num_dupblocks;
5035 pctx.num = meta_data ? shared_len+1 : shared_len;
5036 fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
5037 pctx.blkcount = 0;
5038 pctx.num = 0;
5039
5040 if (meta_data)
5041 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
5042
5043 for (i = 0; i < shared_len; i++) {
5044 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
5045 if (!m)
5046 continue; /* should never happen */
5047 t = (struct dup_inode *) dnode_get(m);
5048 /*
5049 * Report the inode that we are sharing with
5050 */
5051 pctx.inode = &t->inode;
5052 pctx.ino = shared[i];
5053 pctx.dir = t->dir;
5054 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
5055 }
5056 if (file_ok) {
5057 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
5058 continue;
5059 }
5060 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
5061 pctx.errcode = clone_file(ctx, ino, p, block_buf);
5062 if (pctx.errcode)
5063 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
5064 else
5065 continue;
5066 }
5067 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
5068 delete_file(ctx, ino, p, block_buf);
5069 else
5070 ext2fs_unmark_valid(fs);
5071 }
5072 ext2fs_free_mem(&shared);
5073}
5074
5075/*
5076 * Drop the refcount on the dup_block structure, and clear the entry
5077 * in the block_dup_map if appropriate.
5078 */
5079static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
5080{
5081 p->num_bad--;
5082 if (p->num_bad <= 0 ||
5083 (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
5084 ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
5085}
5086
5087static int delete_file_block(ext2_filsys fs,
5088 blk_t *block_nr,
5089 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
5090 blk_t ref_block FSCK_ATTR((unused)),
5091 int ref_offset FSCK_ATTR((unused)),
5092 void *priv_data)
5093{
5094 struct process_block_struct_1b *pb;
5095 struct dup_block *p;
5096 dnode_t *n;
5097 e2fsck_t ctx;
5098
5099 pb = (struct process_block_struct_1b *) priv_data;
5100 ctx = pb->ctx;
5101
5102 if (HOLE_BLKADDR(*block_nr))
5103 return 0;
5104
5105 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
5106 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
5107 if (n) {
5108 p = (struct dup_block *) dnode_get(n);
5109 decrement_badcount(ctx, *block_nr, p);
5110 } else
5111 bb_error_msg(_("internal error; can't find dup_blk for %d"),
5112 *block_nr);
5113 } else {
5114 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
5115 ext2fs_block_alloc_stats(fs, *block_nr, -1);
5116 }
5117
5118 return 0;
5119}
5120
5121static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
5122 struct dup_inode *dp, char* block_buf)
5123{
5124 ext2_filsys fs = ctx->fs;
5125 struct process_block_struct_1b pb;
5126 struct ext2_inode inode;
5127 struct problem_context pctx;
5128 unsigned int count;
5129
5130 clear_problem_context(&pctx);
5131 pctx.ino = pb.ino = ino;
5132 pb.dup_blocks = dp->num_dupblocks;
5133 pb.ctx = ctx;
5134 pctx.str = "delete_file";
5135
5136 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
5137 if (ext2fs_inode_has_valid_blocks(&inode))
5138 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
5139 delete_file_block, &pb);
5140 if (pctx.errcode)
5141 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
5142 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5143 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5144 if (ctx->inode_bad_map)
5145 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
5146 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
5147
5148 /* Inode may have changed by block_iterate, so reread it */
5149 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
5150 inode.i_links_count = 0;
5151 inode.i_dtime = time(0);
5152 if (inode.i_file_acl &&
5153 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
5154 count = 1;
5155 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
5156 block_buf, -1, &count);
5157 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
5158 pctx.errcode = 0;
5159 count = 1;
5160 }
5161 if (pctx.errcode) {
5162 pctx.blk = inode.i_file_acl;
5163 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
5164 }
5165 /*
5166 * If the count is zero, then arrange to have the
5167 * block deleted. If the block is in the block_dup_map,
5168 * also call delete_file_block since it will take care
5169 * of keeping the accounting straight.
5170 */
5171 if ((count == 0) ||
5172 ext2fs_test_block_bitmap(ctx->block_dup_map,
5173 inode.i_file_acl))
5174 delete_file_block(fs, &inode.i_file_acl,
5175 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
5176 }
5177 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
5178}
5179
5180struct clone_struct {
5181 errcode_t errcode;
5182 ext2_ino_t dir;
5183 char *buf;
5184 e2fsck_t ctx;
5185};
5186
5187static int clone_file_block(ext2_filsys fs,
5188 blk_t *block_nr,
5189 e2_blkcnt_t blockcnt,
5190 blk_t ref_block FSCK_ATTR((unused)),
5191 int ref_offset FSCK_ATTR((unused)),
5192 void *priv_data)
5193{
5194 struct dup_block *p;
5195 blk_t new_block;
5196 errcode_t retval;
5197 struct clone_struct *cs = (struct clone_struct *) priv_data;
5198 dnode_t *n;
5199 e2fsck_t ctx;
5200
5201 ctx = cs->ctx;
5202
5203 if (HOLE_BLKADDR(*block_nr))
5204 return 0;
5205
5206 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
5207 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
5208 if (n) {
5209 p = (struct dup_block *) dnode_get(n);
5210 retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
5211 &new_block);
5212 if (retval) {
5213 cs->errcode = retval;
5214 return BLOCK_ABORT;
5215 }
5216 if (cs->dir && (blockcnt >= 0)) {
5217 retval = ext2fs_set_dir_block(fs->dblist,
5218 cs->dir, new_block, blockcnt);
5219 if (retval) {
5220 cs->errcode = retval;
5221 return BLOCK_ABORT;
5222 }
5223 }
5224
5225 retval = io_channel_read_blk(fs->io, *block_nr, 1,
5226 cs->buf);
5227 if (retval) {
5228 cs->errcode = retval;
5229 return BLOCK_ABORT;
5230 }
5231 retval = io_channel_write_blk(fs->io, new_block, 1,
5232 cs->buf);
5233 if (retval) {
5234 cs->errcode = retval;
5235 return BLOCK_ABORT;
5236 }
5237 decrement_badcount(ctx, *block_nr, p);
5238 *block_nr = new_block;
5239 ext2fs_mark_block_bitmap(ctx->block_found_map,
5240 new_block);
5241 ext2fs_mark_block_bitmap(fs->block_map, new_block);
5242 return BLOCK_CHANGED;
5243 } else
5244 bb_error_msg(_("internal error; can't find dup_blk for %d"),
5245 *block_nr);
5246 }
5247 return 0;
5248}
5249
5250static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
5251 struct dup_inode *dp, char* block_buf)
5252{
5253 ext2_filsys fs = ctx->fs;
5254 errcode_t retval;
5255 struct clone_struct cs;
5256 struct problem_context pctx;
5257 blk_t blk;
5258 dnode_t *n;
5259 struct inode_el *ino_el;
5260 struct dup_block *db;
5261 struct dup_inode *di;
5262
5263 clear_problem_context(&pctx);
5264 cs.errcode = 0;
5265 cs.dir = 0;
5266 cs.ctx = ctx;
5267 retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
5268 if (retval)
5269 return retval;
5270
5271 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
5272 cs.dir = ino;
5273
5274 pctx.ino = ino;
5275 pctx.str = "clone_file";
5276 if (ext2fs_inode_has_valid_blocks(&dp->inode))
5277 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
5278 clone_file_block, &cs);
5279 ext2fs_mark_bb_dirty(fs);
5280 if (pctx.errcode) {
5281 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
5282 retval = pctx.errcode;
5283 goto errout;
5284 }
5285 if (cs.errcode) {
5286 bb_error_msg(_("returned from clone_file_block"));
5287 retval = cs.errcode;
5288 goto errout;
5289 }
5290 /* The inode may have changed on disk, so we have to re-read it */
5291 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
5292 blk = dp->inode.i_file_acl;
5293 if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
5294 BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
5295 BLOCK_CHANGED)) {
5296 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
5297 /*
5298 * If we cloned the EA block, find all other inodes
5299 * which refered to that EA block, and modify
5300 * them to point to the new EA block.
5301 */
5302 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
5303 db = (struct dup_block *) dnode_get(n);
5304 for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
5305 if (ino_el->inode == ino)
5306 continue;
5307 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
5308 di = (struct dup_inode *) dnode_get(n);
5309 if (di->inode.i_file_acl == blk) {
5310 di->inode.i_file_acl = dp->inode.i_file_acl;
5311 e2fsck_write_inode(ctx, ino_el->inode,
5312 &di->inode, "clone file EA");
5313 decrement_badcount(ctx, blk, db);
5314 }
5315 }
5316 }
5317 retval = 0;
5318errout:
5319 ext2fs_free_mem(&cs.buf);
5320 return retval;
5321}
5322
5323/*
5324 * This routine returns 1 if a block overlaps with one of the superblocks,
5325 * group descriptors, inode bitmaps, or block bitmaps.
5326 */
5327static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
5328{
5329 ext2_filsys fs = ctx->fs;
5330 blk_t block;
5331 dgrp_t i;
5332
5333 block = fs->super->s_first_data_block;
5334 for (i = 0; i < fs->group_desc_count; i++) {
5335
5336 /* Check superblocks/block group descriptros */
5337 if (ext2fs_bg_has_super(fs, i)) {
5338 if (test_block >= block &&
5339 (test_block <= block + fs->desc_blocks))
5340 return 1;
5341 }
5342
5343 /* Check the inode table */
5344 if ((fs->group_desc[i].bg_inode_table) &&
5345 (test_block >= fs->group_desc[i].bg_inode_table) &&
5346 (test_block < (fs->group_desc[i].bg_inode_table +
5347 fs->inode_blocks_per_group)))
5348 return 1;
5349
5350 /* Check the bitmap blocks */
5351 if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
5352 (test_block == fs->group_desc[i].bg_inode_bitmap))
5353 return 1;
5354
5355 block += fs->super->s_blocks_per_group;
5356 }
5357 return 0;
5358}
5359/*
5360 * pass2.c --- check directory structure
5361 *
5362 * Pass 2 of e2fsck iterates through all active directory inodes, and
5363 * applies to following tests to each directory entry in the directory
5364 * blocks in the inodes:
5365 *
5366 * - The length of the directory entry (rec_len) should be at
5367 * least 8 bytes, and no more than the remaining space
5368 * left in the directory block.
5369 * - The length of the name in the directory entry (name_len)
5370 * should be less than (rec_len - 8).
5371 * - The inode number in the directory entry should be within
5372 * legal bounds.
5373 * - The inode number should refer to a in-use inode.
5374 * - The first entry should be '.', and its inode should be
5375 * the inode of the directory.
5376 * - The second entry should be '..'.
5377 *
5378 * To minimize disk seek time, the directory blocks are processed in
5379 * sorted order of block numbers.
5380 *
5381 * Pass 2 also collects the following information:
5382 * - The inode numbers of the subdirectories for each directory.
5383 *
5384 * Pass 2 relies on the following information from previous passes:
5385 * - The directory information collected in pass 1.
5386 * - The inode_used_map bitmap
5387 * - The inode_bad_map bitmap
5388 * - The inode_dir_map bitmap
5389 *
5390 * Pass 2 frees the following data structures
5391 * - The inode_bad_map bitmap
5392 * - The inode_reg_map bitmap
5393 */
5394
5395/*
5396 * Keeps track of how many times an inode is referenced.
5397 */
5398static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
5399static int check_dir_block(ext2_filsys fs,
5400 struct ext2_db_entry *dir_blocks_info,
5401 void *priv_data);
5402static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info,
5403 struct problem_context *pctx);
5404static int update_dir_block(ext2_filsys fs,
5405 blk_t *block_nr,
5406 e2_blkcnt_t blockcnt,
5407 blk_t ref_block,
5408 int ref_offset,
5409 void *priv_data);
5410static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
5411static int htree_depth(struct dx_dir_info *dx_dir,
5412 struct dx_dirblock_info *dx_db);
5413static int special_dir_block_cmp(const void *a, const void *b);
5414
5415struct check_dir_struct {
5416 char *buf;
5417 struct problem_context pctx;
5418 int count, max;
5419 e2fsck_t ctx;
5420};
5421
5422static void e2fsck_pass2(e2fsck_t ctx)
5423{
5424 struct ext2_super_block *sb = ctx->fs->super;
5425 struct problem_context pctx;
5426 ext2_filsys fs = ctx->fs;
5427 char *buf;
5428 struct dir_info *dir;
5429 struct check_dir_struct cd;
5430 struct dx_dir_info *dx_dir;
5431 struct dx_dirblock_info *dx_db, *dx_parent;
5432 int b;
5433 int i, depth;
5434 problem_t code;
5435 int bad_dir;
5436
5437 clear_problem_context(&cd.pctx);
5438
5439 /* Pass 2 */
5440
5441 if (!(ctx->options & E2F_OPT_PREEN))
5442 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
5443
5444 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
5445 0, ctx->inode_link_info,
5446 &ctx->inode_count);
5447 if (cd.pctx.errcode) {
5448 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
5449 ctx->flags |= E2F_FLAG_ABORT;
5450 return;
5451 }
5452 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
5453 "directory scan buffer");
5454
5455 /*
5456 * Set up the parent pointer for the root directory, if
5457 * present. (If the root directory is not present, we will
5458 * create it in pass 3.)
5459 */
5460 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
5461 if (dir)
5462 dir->parent = EXT2_ROOT_INO;
5463
5464 cd.buf = buf;
5465 cd.ctx = ctx;
5466 cd.count = 1;
5467 cd.max = ext2fs_dblist_count(fs->dblist);
5468
5469 if (ctx->progress)
5470 (void) (ctx->progress)(ctx, 2, 0, cd.max);
5471
5472 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
5473 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
5474
5475 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
5476 &cd);
5477 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5478 return;
5479 if (cd.pctx.errcode) {
5480 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
5481 ctx->flags |= E2F_FLAG_ABORT;
5482 return;
5483 }
5484
5485#ifdef ENABLE_HTREE
5486 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
5487 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5488 return;
5489 if (dx_dir->numblocks == 0)
5490 continue;
5491 clear_problem_context(&pctx);
5492 bad_dir = 0;
5493 pctx.dir = dx_dir->ino;
5494 dx_db = dx_dir->dx_block;
5495 if (dx_db->flags & DX_FLAG_REFERENCED)
5496 dx_db->flags |= DX_FLAG_DUP_REF;
5497 else
5498 dx_db->flags |= DX_FLAG_REFERENCED;
5499 /*
5500 * Find all of the first and last leaf blocks, and
5501 * update their parent's min and max hash values
5502 */
5503 for (b=0, dx_db = dx_dir->dx_block;
5504 b < dx_dir->numblocks;
5505 b++, dx_db++) {
5506 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
5507 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
5508 continue;
5509 dx_parent = &dx_dir->dx_block[dx_db->parent];
5510 /*
5511 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
5512 */
5513 if (dx_db->flags & DX_FLAG_FIRST)
5514 dx_parent->min_hash = dx_db->min_hash;
5515 /*
5516 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
5517 */
5518 if (dx_db->flags & DX_FLAG_LAST)
5519 dx_parent->max_hash = dx_db->max_hash;
5520 }
5521
5522 for (b=0, dx_db = dx_dir->dx_block;
5523 b < dx_dir->numblocks;
5524 b++, dx_db++) {
5525 pctx.blkcount = b;
5526 pctx.group = dx_db->parent;
5527 code = 0;
5528 if (!(dx_db->flags & DX_FLAG_FIRST) &&
5529 (dx_db->min_hash < dx_db->node_min_hash)) {
5530 pctx.blk = dx_db->min_hash;
5531 pctx.blk2 = dx_db->node_min_hash;
5532 code = PR_2_HTREE_MIN_HASH;
5533 fix_problem(ctx, code, &pctx);
5534 bad_dir++;
5535 }
5536 if (dx_db->type == DX_DIRBLOCK_LEAF) {
5537 depth = htree_depth(dx_dir, dx_db);
5538 if (depth != dx_dir->depth) {
5539 code = PR_2_HTREE_BAD_DEPTH;
5540 fix_problem(ctx, code, &pctx);
5541 bad_dir++;
5542 }
5543 }
5544 /*
5545 * This test doesn't apply for the root block
5546 * at block #0
5547 */
5548 if (b &&
5549 (dx_db->max_hash > dx_db->node_max_hash)) {
5550 pctx.blk = dx_db->max_hash;
5551 pctx.blk2 = dx_db->node_max_hash;
5552 code = PR_2_HTREE_MAX_HASH;
5553 fix_problem(ctx, code, &pctx);
5554 bad_dir++;
5555 }
5556 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
5557 code = PR_2_HTREE_NOTREF;
5558 fix_problem(ctx, code, &pctx);
5559 bad_dir++;
5560 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
5561 code = PR_2_HTREE_DUPREF;
5562 fix_problem(ctx, code, &pctx);
5563 bad_dir++;
5564 }
5565 if (code == 0)
5566 continue;
5567 }
5568 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
5569 clear_htree(ctx, dx_dir->ino);
5570 dx_dir->numblocks = 0;
5571 }
5572 }
5573#endif
5574 ext2fs_free_mem(&buf);
5575 ext2fs_free_dblist(fs->dblist);
5576
5577 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
5578 ctx->inode_bad_map = 0;
5579 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
5580 ctx->inode_reg_map = 0;
5581
5582 clear_problem_context(&pctx);
5583 if (ctx->large_files) {
5584 if (!(sb->s_feature_ro_compat &
5585 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
5586 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
5587 sb->s_feature_ro_compat |=
5588 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
5589 ext2fs_mark_super_dirty(fs);
5590 }
5591 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
5592 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
5593 ext2fs_update_dynamic_rev(fs);
5594 ext2fs_mark_super_dirty(fs);
5595 }
5596 } else if (!ctx->large_files &&
5597 (sb->s_feature_ro_compat &
5598 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
5599 if (fs->flags & EXT2_FLAG_RW) {
5600 sb->s_feature_ro_compat &=
5601 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
5602 ext2fs_mark_super_dirty(fs);
5603 }
5604 }
5605
5606}
5607
5608#define MAX_DEPTH 32000
5609static int htree_depth(struct dx_dir_info *dx_dir,
5610 struct dx_dirblock_info *dx_db)
5611{
5612 int depth = 0;
5613
5614 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
5615 dx_db = &dx_dir->dx_block[dx_db->parent];
5616 depth++;
5617 }
5618 return depth;
5619}
5620
5621static int dict_de_cmp(const void *a, const void *b)
5622{
5623 const struct ext2_dir_entry *de_a, *de_b;
5624 int a_len, b_len;
5625
5626 de_a = (const struct ext2_dir_entry *) a;
5627 a_len = de_a->name_len & 0xFF;
5628 de_b = (const struct ext2_dir_entry *) b;
5629 b_len = de_b->name_len & 0xFF;
5630
5631 if (a_len != b_len)
5632 return (a_len - b_len);
5633
5634 return strncmp(de_a->name, de_b->name, a_len);
5635}
5636
5637/*
5638 * This is special sort function that makes sure that directory blocks
5639 * with a dirblock of zero are sorted to the beginning of the list.
5640 * This guarantees that the root node of the htree directories are
5641 * processed first, so we know what hash version to use.
5642 */
5643static int special_dir_block_cmp(const void *a, const void *b)
5644{
5645 const struct ext2_db_entry *db_a =
5646 (const struct ext2_db_entry *) a;
5647 const struct ext2_db_entry *db_b =
5648 (const struct ext2_db_entry *) b;
5649
5650 if (db_a->blockcnt && !db_b->blockcnt)
5651 return 1;
5652
5653 if (!db_a->blockcnt && db_b->blockcnt)
5654 return -1;
5655
5656 if (db_a->blk != db_b->blk)
5657 return (int) (db_a->blk - db_b->blk);
5658
5659 if (db_a->ino != db_b->ino)
5660 return (int) (db_a->ino - db_b->ino);
5661
5662 return (int) (db_a->blockcnt - db_b->blockcnt);
5663}
5664
5665
5666/*
5667 * Make sure the first entry in the directory is '.', and that the
5668 * directory entry is sane.
5669 */
5670static int check_dot(e2fsck_t ctx,
5671 struct ext2_dir_entry *dirent,
5672 ext2_ino_t ino, struct problem_context *pctx)
5673{
5674 struct ext2_dir_entry *nextdir;
5675 int status = 0;
5676 int created = 0;
5677 int new_len;
5678 int problem = 0;
5679
5680 if (!dirent->inode)
5681 problem = PR_2_MISSING_DOT;
5682 else if (((dirent->name_len & 0xFF) != 1) ||
5683 (dirent->name[0] != '.'))
5684 problem = PR_2_1ST_NOT_DOT;
5685 else if (dirent->name[1] != '\0')
5686 problem = PR_2_DOT_NULL_TERM;
5687
5688 if (problem) {
5689 if (fix_problem(ctx, problem, pctx)) {
5690 if (dirent->rec_len < 12)
5691 dirent->rec_len = 12;
5692 dirent->inode = ino;
5693 dirent->name_len = 1;
5694 dirent->name[0] = '.';
5695 dirent->name[1] = '\0';
5696 status = 1;
5697 created = 1;
5698 }
5699 }
5700 if (dirent->inode != ino) {
5701 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
5702 dirent->inode = ino;
5703 status = 1;
5704 }
5705 }
5706 if (dirent->rec_len > 12) {
5707 new_len = dirent->rec_len - 12;
5708 if (new_len > 12) {
5709 if (created ||
5710 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
5711 nextdir = (struct ext2_dir_entry *)
5712 ((char *) dirent + 12);
5713 dirent->rec_len = 12;
5714 nextdir->rec_len = new_len;
5715 nextdir->inode = 0;
5716 nextdir->name_len = 0;
5717 status = 1;
5718 }
5719 }
5720 }
5721 return status;
5722}
5723
5724/*
5725 * Make sure the second entry in the directory is '..', and that the
5726 * directory entry is sane. We do not check the inode number of '..'
5727 * here; this gets done in pass 3.
5728 */
5729static int check_dotdot(e2fsck_t ctx,
5730 struct ext2_dir_entry *dirent,
5731 struct dir_info *dir, struct problem_context *pctx)
5732{
5733 int problem = 0;
5734
5735 if (!dirent->inode)
5736 problem = PR_2_MISSING_DOT_DOT;
5737 else if (((dirent->name_len & 0xFF) != 2) ||
5738 (dirent->name[0] != '.') ||
5739 (dirent->name[1] != '.'))
5740 problem = PR_2_2ND_NOT_DOT_DOT;
5741 else if (dirent->name[2] != '\0')
5742 problem = PR_2_DOT_DOT_NULL_TERM;
5743
5744 if (problem) {
5745 if (fix_problem(ctx, problem, pctx)) {
5746 if (dirent->rec_len < 12)
5747 dirent->rec_len = 12;
5748 /*
5749 * Note: we don't have the parent inode just
5750 * yet, so we will fill it in with the root
5751 * inode. This will get fixed in pass 3.
5752 */
5753 dirent->inode = EXT2_ROOT_INO;
5754 dirent->name_len = 2;
5755 dirent->name[0] = '.';
5756 dirent->name[1] = '.';
5757 dirent->name[2] = '\0';
5758 return 1;
5759 }
5760 return 0;
5761 }
5762 dir->dotdot = dirent->inode;
5763 return 0;
5764}
5765
5766/*
5767 * Check to make sure a directory entry doesn't contain any illegal
5768 * characters.
5769 */
5770static int check_name(e2fsck_t ctx,
5771 struct ext2_dir_entry *dirent,
5772 struct problem_context *pctx)
5773{
5774 int i;
5775 int fixup = -1;
5776 int ret = 0;
5777
5778 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
5779 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
5780 if (fixup < 0) {
5781 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
5782 }
5783 if (fixup) {
5784 dirent->name[i] = '.';
5785 ret = 1;
5786 }
5787 }
5788 }
5789 return ret;
5790}
5791
5792/*
5793 * Check the directory filetype (if present)
5794 */
5795
5796/*
5797 * Given a mode, return the ext2 file type
5798 */
5799static int ext2_file_type(unsigned int mode)
5800{
5801 if (LINUX_S_ISREG(mode))
5802 return EXT2_FT_REG_FILE;
5803
5804 if (LINUX_S_ISDIR(mode))
5805 return EXT2_FT_DIR;
5806
5807 if (LINUX_S_ISCHR(mode))
5808 return EXT2_FT_CHRDEV;
5809
5810 if (LINUX_S_ISBLK(mode))
5811 return EXT2_FT_BLKDEV;
5812
5813 if (LINUX_S_ISLNK(mode))
5814 return EXT2_FT_SYMLINK;
5815
5816 if (LINUX_S_ISFIFO(mode))
5817 return EXT2_FT_FIFO;
5818
5819 if (LINUX_S_ISSOCK(mode))
5820 return EXT2_FT_SOCK;
5821
5822 return 0;
5823}
5824
5825static int check_filetype(e2fsck_t ctx,
5826 struct ext2_dir_entry *dirent,
5827 struct problem_context *pctx)
5828{
5829 int filetype = dirent->name_len >> 8;
5830 int should_be = EXT2_FT_UNKNOWN;
5831 struct ext2_inode inode;
5832
5833 if (!(ctx->fs->super->s_feature_incompat &
5834 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
5835 if (filetype == 0 ||
5836 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
5837 return 0;
5838 dirent->name_len = dirent->name_len & 0xFF;
5839 return 1;
5840 }
5841
5842 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
5843 should_be = EXT2_FT_DIR;
5844 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
5845 dirent->inode)) {
5846 should_be = EXT2_FT_REG_FILE;
5847 } else if (ctx->inode_bad_map &&
5848 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
5849 dirent->inode))
5850 should_be = 0;
5851 else {
5852 e2fsck_read_inode(ctx, dirent->inode, &inode,
5853 "check_filetype");
5854 should_be = ext2_file_type(inode.i_mode);
5855 }
5856 if (filetype == should_be)
5857 return 0;
5858 pctx->num = should_be;
5859
5860 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
5861 pctx) == 0)
5862 return 0;
5863
5864 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
5865 return 1;
5866}
5867
5868#ifdef ENABLE_HTREE
5869static void parse_int_node(ext2_filsys fs,
5870 struct ext2_db_entry *db,
5871 struct check_dir_struct *cd,
5872 struct dx_dir_info *dx_dir,
5873 char *block_buf)
5874{
5875 struct ext2_dx_root_info *root;
5876 struct ext2_dx_entry *ent;
5877 struct ext2_dx_countlimit *limit;
5878 struct dx_dirblock_info *dx_db;
5879 int i, expect_limit, count;
5880 blk_t blk;
5881 ext2_dirhash_t min_hash = 0xffffffff;
5882 ext2_dirhash_t max_hash = 0;
5883 ext2_dirhash_t hash = 0, prev_hash;
5884
5885 if (db->blockcnt == 0) {
5886 root = (struct ext2_dx_root_info *) (block_buf + 24);
5887 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
5888 } else {
5889 ent = (struct ext2_dx_entry *) (block_buf+8);
5890 }
5891 limit = (struct ext2_dx_countlimit *) ent;
5892
5893 count = ext2fs_le16_to_cpu(limit->count);
5894 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
5895 sizeof(struct ext2_dx_entry);
5896 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
5897 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
5898 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
5899 goto clear_and_exit;
5900 }
5901 if (count > expect_limit) {
5902 cd->pctx.num = count;
5903 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
5904 goto clear_and_exit;
5905 count = expect_limit;
5906 }
5907
5908 for (i=0; i < count; i++) {
5909 prev_hash = hash;
5910 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
5911 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
5912 /* Check to make sure the block is valid */
5913 if (blk > (blk_t) dx_dir->numblocks) {
5914 cd->pctx.blk = blk;
5915 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
5916 &cd->pctx))
5917 goto clear_and_exit;
5918 }
5919 if (hash < prev_hash &&
5920 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
5921 goto clear_and_exit;
5922 dx_db = &dx_dir->dx_block[blk];
5923 if (dx_db->flags & DX_FLAG_REFERENCED) {
5924 dx_db->flags |= DX_FLAG_DUP_REF;
5925 } else {
5926 dx_db->flags |= DX_FLAG_REFERENCED;
5927 dx_db->parent = db->blockcnt;
5928 }
5929 if (hash < min_hash)
5930 min_hash = hash;
5931 if (hash > max_hash)
5932 max_hash = hash;
5933 dx_db->node_min_hash = hash;
5934 if ((i+1) < count)
5935 dx_db->node_max_hash =
5936 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
5937 else {
5938 dx_db->node_max_hash = 0xfffffffe;
5939 dx_db->flags |= DX_FLAG_LAST;
5940 }
5941 if (i == 0)
5942 dx_db->flags |= DX_FLAG_FIRST;
5943 }
5944 dx_db = &dx_dir->dx_block[db->blockcnt];
5945 dx_db->min_hash = min_hash;
5946 dx_db->max_hash = max_hash;
5947 return;
5948
5949clear_and_exit:
5950 clear_htree(cd->ctx, cd->pctx.ino);
5951 dx_dir->numblocks = 0;
5952}
5953#endif /* ENABLE_HTREE */
5954
5955/*
5956 * Given a busted directory, try to salvage it somehow.
5957 *
5958 */
5959static void salvage_directory(ext2_filsys fs,
5960 struct ext2_dir_entry *dirent,
5961 struct ext2_dir_entry *prev,
5962 unsigned int *offset)
5963{
5964 char *cp = (char *) dirent;
5965 int left = fs->blocksize - *offset - dirent->rec_len;
5966 int name_len = dirent->name_len & 0xFF;
5967
5968 /*
5969 * Special case of directory entry of size 8: copy what's left
5970 * of the directory block up to cover up the invalid hole.
5971 */
5972 if ((left >= 12) && (dirent->rec_len == 8)) {
5973 memmove(cp, cp+8, left);
5974 memset(cp + left, 0, 8);
5975 return;
5976 }
5977 /*
5978 * If the directory entry overruns the end of the directory
5979 * block, and the name is small enough to fit, then adjust the
5980 * record length.
5981 */
5982 if ((left < 0) &&
5983 (name_len + 8 <= dirent->rec_len + left) &&
5984 dirent->inode <= fs->super->s_inodes_count &&
5985 strnlen(dirent->name, name_len) == name_len) {
5986 dirent->rec_len += left;
5987 return;
5988 }
5989 /*
5990 * If the directory entry is a multiple of four, so it is
5991 * valid, let the previous directory entry absorb the invalid
5992 * one.
5993 */
5994 if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
5995 prev->rec_len += dirent->rec_len;
5996 *offset += dirent->rec_len;
5997 return;
5998 }
5999 /*
6000 * Default salvage method --- kill all of the directory
6001 * entries for the rest of the block. We will either try to
6002 * absorb it into the previous directory entry, or create a
6003 * new empty directory entry the rest of the directory block.
6004 */
6005 if (prev) {
6006 prev->rec_len += fs->blocksize - *offset;
6007 *offset = fs->blocksize;
6008 } else {
6009 dirent->rec_len = fs->blocksize - *offset;
6010 dirent->name_len = 0;
6011 dirent->inode = 0;
6012 }
6013}
6014
6015static int check_dir_block(ext2_filsys fs,
6016 struct ext2_db_entry *db,
6017 void *priv_data)
6018{
6019 struct dir_info *subdir, *dir;
6020 struct dx_dir_info *dx_dir;
6021#ifdef ENABLE_HTREE
6022 struct dx_dirblock_info *dx_db = 0;
6023#endif /* ENABLE_HTREE */
6024 struct ext2_dir_entry *dirent, *prev;
6025 ext2_dirhash_t hash;
6026 unsigned int offset = 0;
6027 int dir_modified = 0;
6028 int dot_state;
6029 blk_t block_nr = db->blk;
6030 ext2_ino_t ino = db->ino;
6031 __u16 links;
6032 struct check_dir_struct *cd;
6033 char *buf;
6034 e2fsck_t ctx;
6035 int problem;
6036 struct ext2_dx_root_info *root;
6037 struct ext2_dx_countlimit *limit;
6038 static dict_t de_dict;
6039 struct problem_context pctx;
6040 int dups_found = 0;
6041
6042 cd = (struct check_dir_struct *) priv_data;
6043 buf = cd->buf;
6044 ctx = cd->ctx;
6045
6046 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6047 return DIRENT_ABORT;
6048
6049 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
6050 return DIRENT_ABORT;
6051
6052 /*
6053 * Make sure the inode is still in use (could have been
6054 * deleted in the duplicate/bad blocks pass.
6055 */
6056 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
6057 return 0;
6058
6059 cd->pctx.ino = ino;
6060 cd->pctx.blk = block_nr;
6061 cd->pctx.blkcount = db->blockcnt;
6062 cd->pctx.ino2 = 0;
6063 cd->pctx.dirent = 0;
6064 cd->pctx.num = 0;
6065
6066 if (db->blk == 0) {
6067 if (allocate_dir_block(ctx, db, &cd->pctx))
6068 return 0;
6069 block_nr = db->blk;
6070 }
6071
6072 if (db->blockcnt)
6073 dot_state = 2;
6074 else
6075 dot_state = 0;
6076
6077 if (ctx->dirs_to_hash &&
6078 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
6079 dups_found++;
6080
6081 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
6082 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
6083 cd->pctx.errcode = 0; /* We'll handle this ourselves */
6084 if (cd->pctx.errcode) {
6085 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
6086 ctx->flags |= E2F_FLAG_ABORT;
6087 return DIRENT_ABORT;
6088 }
6089 memset(buf, 0, fs->blocksize);
6090 }
6091#ifdef ENABLE_HTREE
6092 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
6093 if (dx_dir && dx_dir->numblocks) {
6094 if (db->blockcnt >= dx_dir->numblocks) {
6095 printf("XXX should never happen!!!\n");
6096 abort();
6097 }
6098 dx_db = &dx_dir->dx_block[db->blockcnt];
6099 dx_db->type = DX_DIRBLOCK_LEAF;
6100 dx_db->phys = block_nr;
6101 dx_db->min_hash = ~0;
6102 dx_db->max_hash = 0;
6103
6104 dirent = (struct ext2_dir_entry *) buf;
6105 limit = (struct ext2_dx_countlimit *) (buf+8);
6106 if (db->blockcnt == 0) {
6107 root = (struct ext2_dx_root_info *) (buf + 24);
6108 dx_db->type = DX_DIRBLOCK_ROOT;
6109 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
6110 if ((root->reserved_zero ||
6111 root->info_length < 8 ||
6112 root->indirect_levels > 1) &&
6113 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
6114 clear_htree(ctx, ino);
6115 dx_dir->numblocks = 0;
6116 dx_db = 0;
6117 }
6118 dx_dir->hashversion = root->hash_version;
6119 dx_dir->depth = root->indirect_levels + 1;
6120 } else if ((dirent->inode == 0) &&
6121 (dirent->rec_len == fs->blocksize) &&
6122 (dirent->name_len == 0) &&
6123 (ext2fs_le16_to_cpu(limit->limit) ==
6124 ((fs->blocksize-8) /
6125 sizeof(struct ext2_dx_entry))))
6126 dx_db->type = DX_DIRBLOCK_NODE;
6127 }
6128#endif /* ENABLE_HTREE */
6129
6130 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
6131 prev = 0;
6132 do {
6133 problem = 0;
6134 dirent = (struct ext2_dir_entry *) (buf + offset);
6135 cd->pctx.dirent = dirent;
6136 cd->pctx.num = offset;
6137 if (((offset + dirent->rec_len) > fs->blocksize) ||
6138 (dirent->rec_len < 12) ||
6139 ((dirent->rec_len % 4) != 0) ||
6140 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
6141 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
6142 salvage_directory(fs, dirent, prev, &offset);
6143 dir_modified++;
6144 continue;
6145 } else
6146 goto abort_free_dict;
6147 }
6148 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
6149 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
6150 dirent->name_len = EXT2_NAME_LEN;
6151 dir_modified++;
6152 }
6153 }
6154
6155 if (dot_state == 0) {
6156 if (check_dot(ctx, dirent, ino, &cd->pctx))
6157 dir_modified++;
6158 } else if (dot_state == 1) {
6159 dir = e2fsck_get_dir_info(ctx, ino);
6160 if (!dir) {
6161 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
6162 goto abort_free_dict;
6163 }
6164 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
6165 dir_modified++;
6166 } else if (dirent->inode == ino) {
6167 problem = PR_2_LINK_DOT;
6168 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
6169 dirent->inode = 0;
6170 dir_modified++;
6171 goto next;
6172 }
6173 }
6174 if (!dirent->inode)
6175 goto next;
6176
6177 /*
6178 * Make sure the inode listed is a legal one.
6179 */
6180 if (((dirent->inode != EXT2_ROOT_INO) &&
6181 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
6182 (dirent->inode > fs->super->s_inodes_count)) {
6183 problem = PR_2_BAD_INO;
6184 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
6185 dirent->inode))) {
6186 /*
6187 * If the inode is unused, offer to clear it.
6188 */
6189 problem = PR_2_UNUSED_INODE;
6190 } else if ((dot_state > 1) &&
6191 ((dirent->name_len & 0xFF) == 1) &&
6192 (dirent->name[0] == '.')) {
6193 /*
6194 * If there's a '.' entry in anything other
6195 * than the first directory entry, it's a
6196 * duplicate entry that should be removed.
6197 */
6198 problem = PR_2_DUP_DOT;
6199 } else if ((dot_state > 1) &&
6200 ((dirent->name_len & 0xFF) == 2) &&
6201 (dirent->name[0] == '.') &&
6202 (dirent->name[1] == '.')) {
6203 /*
6204 * If there's a '..' entry in anything other
6205 * than the second directory entry, it's a
6206 * duplicate entry that should be removed.
6207 */
6208 problem = PR_2_DUP_DOT_DOT;
6209 } else if ((dot_state > 1) &&
6210 (dirent->inode == EXT2_ROOT_INO)) {
6211 /*
6212 * Don't allow links to the root directory.
6213 * We check this specially to make sure we
6214 * catch this error case even if the root
6215 * directory hasn't been created yet.
6216 */
6217 problem = PR_2_LINK_ROOT;
6218 } else if ((dot_state > 1) &&
6219 (dirent->name_len & 0xFF) == 0) {
6220 /*
6221 * Don't allow zero-length directory names.
6222 */
6223 problem = PR_2_NULL_NAME;
6224 }
6225
6226 if (problem) {
6227 if (fix_problem(ctx, problem, &cd->pctx)) {
6228 dirent->inode = 0;
6229 dir_modified++;
6230 goto next;
6231 } else {
6232 ext2fs_unmark_valid(fs);
6233 if (problem == PR_2_BAD_INO)
6234 goto next;
6235 }
6236 }
6237
6238 /*
6239 * If the inode was marked as having bad fields in
6240 * pass1, process it and offer to fix/clear it.
6241 * (We wait until now so that we can display the
6242 * pathname to the user.)
6243 */
6244 if (ctx->inode_bad_map &&
6245 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
6246 dirent->inode)) {
6247 if (e2fsck_process_bad_inode(ctx, ino,
6248 dirent->inode,
6249 buf + fs->blocksize)) {
6250 dirent->inode = 0;
6251 dir_modified++;
6252 goto next;
6253 }
6254 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6255 return DIRENT_ABORT;
6256 }
6257
6258 if (check_name(ctx, dirent, &cd->pctx))
6259 dir_modified++;
6260
6261 if (check_filetype(ctx, dirent, &cd->pctx))
6262 dir_modified++;
6263
6264#ifdef ENABLE_HTREE
6265 if (dx_db) {
6266 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
6267 (dirent->name_len & 0xFF),
6268 fs->super->s_hash_seed, &hash, 0);
6269 if (hash < dx_db->min_hash)
6270 dx_db->min_hash = hash;
6271 if (hash > dx_db->max_hash)
6272 dx_db->max_hash = hash;
6273 }
6274#endif
6275
6276 /*
6277 * If this is a directory, then mark its parent in its
6278 * dir_info structure. If the parent field is already
6279 * filled in, then this directory has more than one
6280 * hard link. We assume the first link is correct,
6281 * and ask the user if he/she wants to clear this one.
6282 */
6283 if ((dot_state > 1) &&
6284 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
6285 dirent->inode))) {
6286 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
6287 if (!subdir) {
6288 cd->pctx.ino = dirent->inode;
6289 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
6290 goto abort_free_dict;
6291 }
6292 if (subdir->parent) {
6293 cd->pctx.ino2 = subdir->parent;
6294 if (fix_problem(ctx, PR_2_LINK_DIR,
6295 &cd->pctx)) {
6296 dirent->inode = 0;
6297 dir_modified++;
6298 goto next;
6299 }
6300 cd->pctx.ino2 = 0;
6301 } else
6302 subdir->parent = ino;
6303 }
6304
6305 if (dups_found) {
6306 ;
6307 } else if (dict_lookup(&de_dict, dirent)) {
6308 clear_problem_context(&pctx);
6309 pctx.ino = ino;
6310 pctx.dirent = dirent;
6311 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
6312 if (!ctx->dirs_to_hash)
6313 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
6314 if (ctx->dirs_to_hash)
6315 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
6316 dups_found++;
6317 } else
6318 dict_alloc_insert(&de_dict, dirent, dirent);
6319
6320 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
6321 &links);
6322 if (links > 1)
6323 ctx->fs_links_count++;
6324 ctx->fs_total_count++;
6325 next:
6326 prev = dirent;
6327 offset += dirent->rec_len;
6328 dot_state++;
6329 } while (offset < fs->blocksize);
6330#ifdef ENABLE_HTREE
6331 if (dx_db) {
6332 cd->pctx.dir = cd->pctx.ino;
6333 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
6334 (dx_db->type == DX_DIRBLOCK_NODE))
6335 parse_int_node(fs, db, cd, dx_dir, buf);
6336 }
6337#endif /* ENABLE_HTREE */
6338 if (offset != fs->blocksize) {
6339 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
6340 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
6341 dirent->rec_len = cd->pctx.num;
6342 dir_modified++;
6343 }
6344 }
6345 if (dir_modified) {
6346 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
6347 if (cd->pctx.errcode) {
6348 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
6349 &cd->pctx))
6350 goto abort_free_dict;
6351 }
6352 ext2fs_mark_changed(fs);
6353 }
6354 dict_free_nodes(&de_dict);
6355 return 0;
6356abort_free_dict:
6357 dict_free_nodes(&de_dict);
6358 ctx->flags |= E2F_FLAG_ABORT;
6359 return DIRENT_ABORT;
6360}
6361
6362/*
6363 * This function is called to deallocate a block, and is an interator
6364 * functioned called by deallocate inode via ext2fs_iterate_block().
6365 */
6366static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr,
6367 e2_blkcnt_t blockcnt FSCK_ATTR((unused)),
6368 blk_t ref_block FSCK_ATTR((unused)),
6369 int ref_offset FSCK_ATTR((unused)),
6370 void *priv_data)
6371{
6372 e2fsck_t ctx = (e2fsck_t) priv_data;
6373
6374 if (HOLE_BLKADDR(*block_nr))
6375 return 0;
6376 if ((*block_nr < fs->super->s_first_data_block) ||
6377 (*block_nr >= fs->super->s_blocks_count))
6378 return 0;
6379 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
6380 ext2fs_block_alloc_stats(fs, *block_nr, -1);
6381 return 0;
6382}
6383
6384/*
6385 * This fuction deallocates an inode
6386 */
6387static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
6388{
6389 ext2_filsys fs = ctx->fs;
6390 struct ext2_inode inode;
6391 struct problem_context pctx;
6392 __u32 count;
6393
6394 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
6395 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
6396 inode.i_links_count = 0;
6397 inode.i_dtime = time(0);
6398 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
6399 clear_problem_context(&pctx);
6400 pctx.ino = ino;
6401
6402 /*
6403 * Fix up the bitmaps...
6404 */
6405 e2fsck_read_bitmaps(ctx);
6406 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
6407 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
6408 if (ctx->inode_bad_map)
6409 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
6410 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
6411
6412 if (inode.i_file_acl &&
6413 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
6414 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
6415 block_buf, -1, &count);
6416 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
6417 pctx.errcode = 0;
6418 count = 1;
6419 }
6420 if (pctx.errcode) {
6421 pctx.blk = inode.i_file_acl;
6422 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
6423 ctx->flags |= E2F_FLAG_ABORT;
6424 return;
6425 }
6426 if (count == 0) {
6427 ext2fs_unmark_block_bitmap(ctx->block_found_map,
6428 inode.i_file_acl);
6429 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
6430 }
6431 inode.i_file_acl = 0;
6432 }
6433
6434 if (!ext2fs_inode_has_valid_blocks(&inode))
6435 return;
6436
6437 if (LINUX_S_ISREG(inode.i_mode) &&
6438 (inode.i_size_high || inode.i_size & 0x80000000UL))
6439 ctx->large_files--;
6440
6441 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
6442 deallocate_inode_block, ctx);
6443 if (pctx.errcode) {
6444 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
6445 ctx->flags |= E2F_FLAG_ABORT;
6446 return;
6447 }
6448}
6449
6450/*
6451 * This fuction clears the htree flag on an inode
6452 */
6453static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
6454{
6455 struct ext2_inode inode;
6456
6457 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
6458 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
6459 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
6460 if (ctx->dirs_to_hash)
6461 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
6462}
6463
6464
6465static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
6466 ext2_ino_t ino, char *buf)
6467{
6468 ext2_filsys fs = ctx->fs;
6469 struct ext2_inode inode;
6470 int inode_modified = 0;
6471 int not_fixed = 0;
6472 unsigned char *frag, *fsize;
6473 struct problem_context pctx;
6474 int problem = 0;
6475
6476 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
6477
6478 clear_problem_context(&pctx);
6479 pctx.ino = ino;
6480 pctx.dir = dir;
6481 pctx.inode = &inode;
6482
6483 if (inode.i_file_acl &&
6484 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
6485 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
6486 inode.i_file_acl = 0;
6487#if BB_BIG_ENDIAN
6488 /*
6489 * This is a special kludge to deal with long symlinks
6490 * on big endian systems. i_blocks had already been
6491 * decremented earlier in pass 1, but since i_file_acl
6492 * hadn't yet been cleared, ext2fs_read_inode()
6493 * assumed that the file was short symlink and would
6494 * not have byte swapped i_block[0]. Hence, we have
6495 * to byte-swap it here.
6496 */
6497 if (LINUX_S_ISLNK(inode.i_mode) &&
6498 (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
6499 (inode.i_blocks == fs->blocksize >> 9))
6500 inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
6501#endif
6502 inode_modified++;
6503 } else
6504 not_fixed++;
6505
6506 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
6507 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
6508 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
6509 !(LINUX_S_ISSOCK(inode.i_mode)))
6510 problem = PR_2_BAD_MODE;
6511 else if (LINUX_S_ISCHR(inode.i_mode)
6512 && !e2fsck_pass1_check_device_inode(fs, &inode))
6513 problem = PR_2_BAD_CHAR_DEV;
6514 else if (LINUX_S_ISBLK(inode.i_mode)
6515 && !e2fsck_pass1_check_device_inode(fs, &inode))
6516 problem = PR_2_BAD_BLOCK_DEV;
6517 else if (LINUX_S_ISFIFO(inode.i_mode)
6518 && !e2fsck_pass1_check_device_inode(fs, &inode))
6519 problem = PR_2_BAD_FIFO;
6520 else if (LINUX_S_ISSOCK(inode.i_mode)
6521 && !e2fsck_pass1_check_device_inode(fs, &inode))
6522 problem = PR_2_BAD_SOCKET;
6523 else if (LINUX_S_ISLNK(inode.i_mode)
6524 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
6525 problem = PR_2_INVALID_SYMLINK;
6526 }
6527
6528 if (problem) {
6529 if (fix_problem(ctx, problem, &pctx)) {
6530 deallocate_inode(ctx, ino, 0);
6531 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6532 return 0;
6533 return 1;
6534 } else
6535 not_fixed++;
6536 problem = 0;
6537 }
6538
6539 if (inode.i_faddr) {
6540 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
6541 inode.i_faddr = 0;
6542 inode_modified++;
6543 } else
6544 not_fixed++;
6545 }
6546
6547 switch (fs->super->s_creator_os) {
6548 case EXT2_OS_LINUX:
6549 frag = &inode.osd2.linux2.l_i_frag;
6550 fsize = &inode.osd2.linux2.l_i_fsize;
6551 break;
6552 case EXT2_OS_HURD:
6553 frag = &inode.osd2.hurd2.h_i_frag;
6554 fsize = &inode.osd2.hurd2.h_i_fsize;
6555 break;
6556 case EXT2_OS_MASIX:
6557 frag = &inode.osd2.masix2.m_i_frag;
6558 fsize = &inode.osd2.masix2.m_i_fsize;
6559 break;
6560 default:
6561 frag = fsize = 0;
6562 }
6563 if (frag && *frag) {
6564 pctx.num = *frag;
6565 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
6566 *frag = 0;
6567 inode_modified++;
6568 } else
6569 not_fixed++;
6570 pctx.num = 0;
6571 }
6572 if (fsize && *fsize) {
6573 pctx.num = *fsize;
6574 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
6575 *fsize = 0;
6576 inode_modified++;
6577 } else
6578 not_fixed++;
6579 pctx.num = 0;
6580 }
6581
6582 if (inode.i_file_acl &&
6583 ((inode.i_file_acl < fs->super->s_first_data_block) ||
6584 (inode.i_file_acl >= fs->super->s_blocks_count))) {
6585 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
6586 inode.i_file_acl = 0;
6587 inode_modified++;
6588 } else
6589 not_fixed++;
6590 }
6591 if (inode.i_dir_acl &&
6592 LINUX_S_ISDIR(inode.i_mode)) {
6593 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
6594 inode.i_dir_acl = 0;
6595 inode_modified++;
6596 } else
6597 not_fixed++;
6598 }
6599
6600 if (inode_modified)
6601 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
6602 if (!not_fixed)
6603 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
6604 return 0;
6605}
6606
6607
6608/*
6609 * allocate_dir_block --- this function allocates a new directory
6610 * block for a particular inode; this is done if a directory has
6611 * a "hole" in it, or if a directory has a illegal block number
6612 * that was zeroed out and now needs to be replaced.
6613 */
6614static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db,
6615 struct problem_context *pctx)
6616{
6617 ext2_filsys fs = ctx->fs;
6618 blk_t blk;
6619 char *block;
6620 struct ext2_inode inode;
6621
6622 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
6623 return 1;
6624
6625 /*
6626 * Read the inode and block bitmaps in; we'll be messing with
6627 * them.
6628 */
6629 e2fsck_read_bitmaps(ctx);
6630
6631 /*
6632 * First, find a free block
6633 */
6634 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
6635 if (pctx->errcode) {
6636 pctx->str = "ext2fs_new_block";
6637 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
6638 return 1;
6639 }
6640 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
6641 ext2fs_mark_block_bitmap(fs->block_map, blk);
6642 ext2fs_mark_bb_dirty(fs);
6643
6644 /*
6645 * Now let's create the actual data block for the inode
6646 */
6647 if (db->blockcnt)
6648 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
6649 else
6650 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
6651 EXT2_ROOT_INO, &block);
6652
6653 if (pctx->errcode) {
6654 pctx->str = "ext2fs_new_dir_block";
6655 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
6656 return 1;
6657 }
6658
6659 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
6660 ext2fs_free_mem(&block);
6661 if (pctx->errcode) {
6662 pctx->str = "ext2fs_write_dir_block";
6663 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
6664 return 1;
6665 }
6666
6667 /*
6668 * Update the inode block count
6669 */
6670 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
6671 inode.i_blocks += fs->blocksize / 512;
6672 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
6673 inode.i_size = (db->blockcnt+1) * fs->blocksize;
6674 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
6675
6676 /*
6677 * Finally, update the block pointers for the inode
6678 */
6679 db->blk = blk;
6680 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
6681 0, update_dir_block, db);
6682 if (pctx->errcode) {
6683 pctx->str = "ext2fs_block_iterate";
6684 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
6685 return 1;
6686 }
6687
6688 return 0;
6689}
6690
6691/*
6692 * This is a helper function for allocate_dir_block().
6693 */
6694static int update_dir_block(ext2_filsys fs FSCK_ATTR((unused)),
6695 blk_t *block_nr,
6696 e2_blkcnt_t blockcnt,
6697 blk_t ref_block FSCK_ATTR((unused)),
6698 int ref_offset FSCK_ATTR((unused)),
6699 void *priv_data)
6700{
6701 struct ext2_db_entry *db;
6702
6703 db = (struct ext2_db_entry *) priv_data;
6704 if (db->blockcnt == (int) blockcnt) {
6705 *block_nr = db->blk;
6706 return BLOCK_CHANGED;
6707 }
6708 return 0;
6709}
6710
6711/*
6712 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
6713 *
6714 * Pass #3 assures that all directories are connected to the
6715 * filesystem tree, using the following algorithm:
6716 *
6717 * First, the root directory is checked to make sure it exists; if
6718 * not, e2fsck will offer to create a new one. It is then marked as
6719 * "done".
6720 *
6721 * Then, pass3 interates over all directory inodes; for each directory
6722 * it attempts to trace up the filesystem tree, using dirinfo.parent
6723 * until it reaches a directory which has been marked "done". If it
6724 * cannot do so, then the directory must be disconnected, and e2fsck
6725 * will offer to reconnect it to /lost+found. While it is chasing
6726 * parent pointers up the filesystem tree, if pass3 sees a directory
6727 * twice, then it has detected a filesystem loop, and it will again
6728 * offer to reconnect the directory to /lost+found in to break the
6729 * filesystem loop.
6730 *
6731 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
6732 * reconnect inodes to /lost+found; this subroutine is also used by
6733 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
6734 * is responsible for creating /lost+found if it does not exist.
6735 *
6736 * Pass 3 frees the following data structures:
6737 * - The dirinfo directory information cache.
6738 */
6739
6740static void check_root(e2fsck_t ctx);
6741static int check_directory(e2fsck_t ctx, struct dir_info *dir,
6742 struct problem_context *pctx);
6743static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
6744
6745static ext2fs_inode_bitmap inode_loop_detect;
6746static ext2fs_inode_bitmap inode_done_map;
6747
6748static void e2fsck_pass3(e2fsck_t ctx)
6749{
6750 ext2_filsys fs = ctx->fs;
6751 int i;
6752 struct problem_context pctx;
6753 struct dir_info *dir;
6754 unsigned long maxdirs, count;
6755
6756 clear_problem_context(&pctx);
6757
6758 /* Pass 3 */
6759
6760 if (!(ctx->options & E2F_OPT_PREEN))
6761 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
6762
6763 /*
6764 * Allocate some bitmaps to do loop detection.
6765 */
6766 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
6767 &inode_done_map);
6768 if (pctx.errcode) {
6769 pctx.num = 2;
6770 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
6771 ctx->flags |= E2F_FLAG_ABORT;
6772 goto abort_exit;
6773 }
6774 check_root(ctx);
6775 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6776 goto abort_exit;
6777
6778 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
6779
6780 maxdirs = e2fsck_get_num_dirinfo(ctx);
6781 count = 1;
6782
6783 if (ctx->progress)
6784 if ((ctx->progress)(ctx, 3, 0, maxdirs))
6785 goto abort_exit;
6786
6787 for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
6788 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6789 goto abort_exit;
6790 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
6791 goto abort_exit;
6792 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
6793 if (check_directory(ctx, dir, &pctx))
6794 goto abort_exit;
6795 }
6796
6797 /*
6798 * Force the creation of /lost+found if not present
6799 */
6800 if ((ctx->flags & E2F_OPT_READONLY) == 0)
6801 e2fsck_get_lost_and_found(ctx, 1);
6802
6803 /*
6804 * If there are any directories that need to be indexed or
6805 * optimized, do it here.
6806 */
6807 e2fsck_rehash_directories(ctx);
6808
6809abort_exit:
6810 e2fsck_free_dir_info(ctx);
6811 ext2fs_free_inode_bitmap(inode_loop_detect);
6812 inode_loop_detect = 0;
6813 ext2fs_free_inode_bitmap(inode_done_map);
6814 inode_done_map = 0;
6815}
6816
6817/*
6818 * This makes sure the root inode is present; if not, we ask if the
6819 * user wants us to create it. Not creating it is a fatal error.
6820 */
6821static void check_root(e2fsck_t ctx)
6822{
6823 ext2_filsys fs = ctx->fs;
6824 blk_t blk;
6825 struct ext2_inode inode;
6826 char * block;
6827 struct problem_context pctx;
6828
6829 clear_problem_context(&pctx);
6830
6831 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
6832 /*
6833 * If the root inode is not a directory, die here. The
6834 * user must have answered 'no' in pass1 when we
6835 * offered to clear it.
6836 */
6837 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
6838 EXT2_ROOT_INO))) {
6839 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
6840 ctx->flags |= E2F_FLAG_ABORT;
6841 }
6842 return;
6843 }
6844
6845 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
6846 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
6847 ctx->flags |= E2F_FLAG_ABORT;
6848 return;
6849 }
6850
6851 e2fsck_read_bitmaps(ctx);
6852
6853 /*
6854 * First, find a free block
6855 */
6856 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
6857 if (pctx.errcode) {
6858 pctx.str = "ext2fs_new_block";
6859 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
6860 ctx->flags |= E2F_FLAG_ABORT;
6861 return;
6862 }
6863 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
6864 ext2fs_mark_block_bitmap(fs->block_map, blk);
6865 ext2fs_mark_bb_dirty(fs);
6866
6867 /*
6868 * Now let's create the actual data block for the inode
6869 */
6870 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
6871 &block);
6872 if (pctx.errcode) {
6873 pctx.str = "ext2fs_new_dir_block";
6874 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
6875 ctx->flags |= E2F_FLAG_ABORT;
6876 return;
6877 }
6878
6879 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
6880 if (pctx.errcode) {
6881 pctx.str = "ext2fs_write_dir_block";
6882 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
6883 ctx->flags |= E2F_FLAG_ABORT;
6884 return;
6885 }
6886 ext2fs_free_mem(&block);
6887
6888 /*
6889 * Set up the inode structure
6890 */
6891 memset(&inode, 0, sizeof(inode));
6892 inode.i_mode = 040755;
6893 inode.i_size = fs->blocksize;
6894 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
6895 inode.i_links_count = 2;
6896 inode.i_blocks = fs->blocksize / 512;
6897 inode.i_block[0] = blk;
6898
6899 /*
6900 * Write out the inode.
6901 */
6902 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
6903 if (pctx.errcode) {
6904 pctx.str = "ext2fs_write_inode";
6905 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
6906 ctx->flags |= E2F_FLAG_ABORT;
6907 return;
6908 }
6909
6910 /*
6911 * Miscellaneous bookkeeping...
6912 */
6913 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
6914 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
6915 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
6916
6917 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
6918 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
6919 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
6920 ext2fs_mark_ib_dirty(fs);
6921}
6922
6923/*
6924 * This subroutine is responsible for making sure that a particular
6925 * directory is connected to the root; if it isn't we trace it up as
6926 * far as we can go, and then offer to connect the resulting parent to
6927 * the lost+found. We have to do loop detection; if we ever discover
6928 * a loop, we treat that as a disconnected directory and offer to
6929 * reparent it to lost+found.
6930 *
6931 * However, loop detection is expensive, because for very large
6932 * filesystems, the inode_loop_detect bitmap is huge, and clearing it
6933 * is non-trivial. Loops in filesystems are also a rare error case,
6934 * and we shouldn't optimize for error cases. So we try two passes of
6935 * the algorithm. The first time, we ignore loop detection and merely
6936 * increment a counter; if the counter exceeds some extreme threshold,
6937 * then we try again with the loop detection bitmap enabled.
6938 */
6939static int check_directory(e2fsck_t ctx, struct dir_info *dir,
6940 struct problem_context *pctx)
6941{
6942 ext2_filsys fs = ctx->fs;
6943 struct dir_info *p = dir;
6944 int loop_pass = 0, parent_count = 0;
6945
6946 if (!p)
6947 return 0;
6948
6949 while (1) {
6950 /*
6951 * Mark this inode as being "done"; by the time we
6952 * return from this function, the inode we either be
6953 * verified as being connected to the directory tree,
6954 * or we will have offered to reconnect this to
6955 * lost+found.
6956 *
6957 * If it was marked done already, then we've reached a
6958 * parent we've already checked.
6959 */
6960 if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
6961 break;
6962
6963 /*
6964 * If this directory doesn't have a parent, or we've
6965 * seen the parent once already, then offer to
6966 * reparent it to lost+found
6967 */
6968 if (!p->parent ||
6969 (loop_pass &&
6970 (ext2fs_test_inode_bitmap(inode_loop_detect,
6971 p->parent)))) {
6972 pctx->ino = p->ino;
6973 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
6974 if (e2fsck_reconnect_file(ctx, pctx->ino))
6975 ext2fs_unmark_valid(fs);
6976 else {
6977 p = e2fsck_get_dir_info(ctx, pctx->ino);
6978 p->parent = ctx->lost_and_found;
6979 fix_dotdot(ctx, p, ctx->lost_and_found);
6980 }
6981 }
6982 break;
6983 }
6984 p = e2fsck_get_dir_info(ctx, p->parent);
6985 if (!p) {
6986 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
6987 return 0;
6988 }
6989 if (loop_pass) {
6990 ext2fs_mark_inode_bitmap(inode_loop_detect,
6991 p->ino);
6992 } else if (parent_count++ > 2048) {
6993 /*
6994 * If we've run into a path depth that's
6995 * greater than 2048, try again with the inode
6996 * loop bitmap turned on and start from the
6997 * top.
6998 */
6999 loop_pass = 1;
7000 if (inode_loop_detect)
7001 ext2fs_clear_inode_bitmap(inode_loop_detect);
7002 else {
7003 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
7004 if (pctx->errcode) {
7005 pctx->num = 1;
7006 fix_problem(ctx,
7007 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
7008 ctx->flags |= E2F_FLAG_ABORT;
7009 return -1;
7010 }
7011 }
7012 p = dir;
7013 }
7014 }
7015
7016 /*
7017 * Make sure that .. and the parent directory are the same;
7018 * offer to fix it if not.
7019 */
7020 if (dir->parent != dir->dotdot) {
7021 pctx->ino = dir->ino;
7022 pctx->ino2 = dir->dotdot;
7023 pctx->dir = dir->parent;
7024 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
7025 fix_dotdot(ctx, dir, dir->parent);
7026 }
7027 return 0;
7028}
7029
7030/*
7031 * This routine gets the lost_and_found inode, making it a directory
7032 * if necessary
7033 */
7034ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
7035{
7036 ext2_filsys fs = ctx->fs;
7037 ext2_ino_t ino;
7038 blk_t blk;
7039 errcode_t retval;
7040 struct ext2_inode inode;
7041 char * block;
7042 static const char name[] = "lost+found";
7043 struct problem_context pctx;
7044 struct dir_info *dirinfo;
7045
7046 if (ctx->lost_and_found)
7047 return ctx->lost_and_found;
7048
7049 clear_problem_context(&pctx);
7050
7051 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
7052 sizeof(name)-1, 0, &ino);
7053 if (retval && !fix)
7054 return 0;
7055 if (!retval) {
7056 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
7057 ctx->lost_and_found = ino;
7058 return ino;
7059 }
7060
7061 /* Lost+found isn't a directory! */
7062 if (!fix)
7063 return 0;
7064 pctx.ino = ino;
7065 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
7066 return 0;
7067
7068 /* OK, unlink the old /lost+found file. */
7069 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
7070 if (pctx.errcode) {
7071 pctx.str = "ext2fs_unlink";
7072 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
7073 return 0;
7074 }
7075 dirinfo = e2fsck_get_dir_info(ctx, ino);
7076 if (dirinfo)
7077 dirinfo->parent = 0;
7078 e2fsck_adjust_inode_count(ctx, ino, -1);
7079 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
7080 pctx.errcode = retval;
7081 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
7082 }
7083 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
7084 return 0;
7085
7086 /*
7087 * Read the inode and block bitmaps in; we'll be messing with
7088 * them.
7089 */
7090 e2fsck_read_bitmaps(ctx);
7091
7092 /*
7093 * First, find a free block
7094 */
7095 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
7096 if (retval) {
7097 pctx.errcode = retval;
7098 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
7099 return 0;
7100 }
7101 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
7102 ext2fs_block_alloc_stats(fs, blk, +1);
7103
7104 /*
7105 * Next find a free inode.
7106 */
7107 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
7108 ctx->inode_used_map, &ino);
7109 if (retval) {
7110 pctx.errcode = retval;
7111 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
7112 return 0;
7113 }
7114 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
7115 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
7116 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
7117
7118 /*
7119 * Now let's create the actual data block for the inode
7120 */
7121 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
7122 if (retval) {
7123 pctx.errcode = retval;
7124 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
7125 return 0;
7126 }
7127
7128 retval = ext2fs_write_dir_block(fs, blk, block);
7129 ext2fs_free_mem(&block);
7130 if (retval) {
7131 pctx.errcode = retval;
7132 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
7133 return 0;
7134 }
7135
7136 /*
7137 * Set up the inode structure
7138 */
7139 memset(&inode, 0, sizeof(inode));
7140 inode.i_mode = 040700;
7141 inode.i_size = fs->blocksize;
7142 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
7143 inode.i_links_count = 2;
7144 inode.i_blocks = fs->blocksize / 512;
7145 inode.i_block[0] = blk;
7146
7147 /*
7148 * Next, write out the inode.
7149 */
7150 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
7151 if (pctx.errcode) {
7152 pctx.str = "ext2fs_write_inode";
7153 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
7154 return 0;
7155 }
7156 /*
7157 * Finally, create the directory link
7158 */
7159 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
7160 if (pctx.errcode) {
7161 pctx.str = "ext2fs_link";
7162 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
7163 return 0;
7164 }
7165
7166 /*
7167 * Miscellaneous bookkeeping that needs to be kept straight.
7168 */
7169 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
7170 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
7171 ext2fs_icount_store(ctx->inode_count, ino, 2);
7172 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
7173 ctx->lost_and_found = ino;
7174 return ino;
7175}
7176
7177/*
7178 * This routine will connect a file to lost+found
7179 */
7180int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
7181{
7182 ext2_filsys fs = ctx->fs;
7183 errcode_t retval;
7184 char name[80];
7185 struct problem_context pctx;
7186 struct ext2_inode inode;
7187 int file_type = 0;
7188
7189 clear_problem_context(&pctx);
7190 pctx.ino = ino;
7191
7192 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
7193 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
7194 ctx->bad_lost_and_found++;
7195 }
7196 if (ctx->bad_lost_and_found) {
7197 fix_problem(ctx, PR_3_NO_LPF, &pctx);
7198 return 1;
7199 }
7200
7201 sprintf(name, "#%u", ino);
7202 if (ext2fs_read_inode(fs, ino, &inode) == 0)
7203 file_type = ext2_file_type(inode.i_mode);
7204 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
7205 if (retval == EXT2_ET_DIR_NO_SPACE) {
7206 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
7207 return 1;
7208 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
7209 1, 0);
7210 if (retval) {
7211 pctx.errcode = retval;
7212 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
7213 return 1;
7214 }
7215 retval = ext2fs_link(fs, ctx->lost_and_found, name,
7216 ino, file_type);
7217 }
7218 if (retval) {
7219 pctx.errcode = retval;
7220 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
7221 return 1;
7222 }
7223 e2fsck_adjust_inode_count(ctx, ino, 1);
7224
7225 return 0;
7226}
7227
7228/*
7229 * Utility routine to adjust the inode counts on an inode.
7230 */
7231errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
7232{
7233 ext2_filsys fs = ctx->fs;
7234 errcode_t retval;
7235 struct ext2_inode inode;
7236
7237 if (!ino)
7238 return 0;
7239
7240 retval = ext2fs_read_inode(fs, ino, &inode);
7241 if (retval)
7242 return retval;
7243
7244 if (adj == 1) {
7245 ext2fs_icount_increment(ctx->inode_count, ino, 0);
7246 if (inode.i_links_count == (__u16) ~0)
7247 return 0;
7248 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
7249 inode.i_links_count++;
7250 } else if (adj == -1) {
7251 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
7252 if (inode.i_links_count == 0)
7253 return 0;
7254 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
7255 inode.i_links_count--;
7256 }
7257
7258 retval = ext2fs_write_inode(fs, ino, &inode);
7259 if (retval)
7260 return retval;
7261
7262 return 0;
7263}
7264
7265/*
7266 * Fix parent --- this routine fixes up the parent of a directory.
7267 */
7268struct fix_dotdot_struct {
7269 ext2_filsys fs;
7270 ext2_ino_t parent;
7271 int done;
7272 e2fsck_t ctx;
7273};
7274
7275static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
7276 int offset FSCK_ATTR((unused)),
7277 int blocksize FSCK_ATTR((unused)),
7278 char *buf FSCK_ATTR((unused)),
7279 void *priv_data)
7280{
7281 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
7282 errcode_t retval;
7283 struct problem_context pctx;
7284
7285 if ((dirent->name_len & 0xFF) != 2)
7286 return 0;
7287 if (strncmp(dirent->name, "..", 2))
7288 return 0;
7289
7290 clear_problem_context(&pctx);
7291
7292 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
7293 if (retval) {
7294 pctx.errcode = retval;
7295 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
7296 }
7297 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
7298 if (retval) {
7299 pctx.errcode = retval;
7300 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
7301 }
7302 dirent->inode = fp->parent;
7303
7304 fp->done++;
7305 return DIRENT_ABORT | DIRENT_CHANGED;
7306}
7307
7308static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
7309{
7310 ext2_filsys fs = ctx->fs;
7311 errcode_t retval;
7312 struct fix_dotdot_struct fp;
7313 struct problem_context pctx;
7314
7315 fp.fs = fs;
7316 fp.parent = parent;
7317 fp.done = 0;
7318 fp.ctx = ctx;
7319
7320 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
7321 0, fix_dotdot_proc, &fp);
7322 if (retval || !fp.done) {
7323 clear_problem_context(&pctx);
7324 pctx.ino = dir->ino;
7325 pctx.errcode = retval;
7326 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
7327 PR_3_FIX_PARENT_NOFIND, &pctx);
7328 ext2fs_unmark_valid(fs);
7329 }
7330 dir->dotdot = parent;
7331
7332 return;
7333}
7334
7335/*
7336 * These routines are responsible for expanding a /lost+found if it is
7337 * too small.
7338 */
7339
7340struct expand_dir_struct {
7341 int num;
7342 int guaranteed_size;
7343 int newblocks;
7344 int last_block;
7345 errcode_t err;
7346 e2fsck_t ctx;
7347};
7348
7349static int expand_dir_proc(ext2_filsys fs,
7350 blk_t *blocknr,
7351 e2_blkcnt_t blockcnt,
7352 blk_t ref_block FSCK_ATTR((unused)),
7353 int ref_offset FSCK_ATTR((unused)),
7354 void *priv_data)
7355{
7356 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
7357 blk_t new_blk;
7358 static blk_t last_blk = 0;
7359 char *block;
7360 errcode_t retval;
7361 e2fsck_t ctx;
7362
7363 ctx = es->ctx;
7364
7365 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
7366 return BLOCK_ABORT;
7367
7368 if (blockcnt > 0)
7369 es->last_block = blockcnt;
7370 if (*blocknr) {
7371 last_blk = *blocknr;
7372 return 0;
7373 }
7374 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
7375 &new_blk);
7376 if (retval) {
7377 es->err = retval;
7378 return BLOCK_ABORT;
7379 }
7380 if (blockcnt > 0) {
7381 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
7382 if (retval) {
7383 es->err = retval;
7384 return BLOCK_ABORT;
7385 }
7386 es->num--;
7387 retval = ext2fs_write_dir_block(fs, new_blk, block);
7388 } else {
7389 retval = ext2fs_get_mem(fs->blocksize, &block);
7390 if (retval) {
7391 es->err = retval;
7392 return BLOCK_ABORT;
7393 }
7394 memset(block, 0, fs->blocksize);
7395 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
7396 }
7397 if (retval) {
7398 es->err = retval;
7399 return BLOCK_ABORT;
7400 }
7401 ext2fs_free_mem(&block);
7402 *blocknr = new_blk;
7403 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
7404 ext2fs_block_alloc_stats(fs, new_blk, +1);
7405 es->newblocks++;
7406
7407 if (es->num == 0)
7408 return (BLOCK_CHANGED | BLOCK_ABORT);
7409 else
7410 return BLOCK_CHANGED;
7411}
7412
7413errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
7414 int num, int guaranteed_size)
7415{
7416 ext2_filsys fs = ctx->fs;
7417 errcode_t retval;
7418 struct expand_dir_struct es;
7419 struct ext2_inode inode;
7420
7421 if (!(fs->flags & EXT2_FLAG_RW))
7422 return EXT2_ET_RO_FILSYS;
7423
7424 /*
7425 * Read the inode and block bitmaps in; we'll be messing with
7426 * them.
7427 */
7428 e2fsck_read_bitmaps(ctx);
7429
7430 retval = ext2fs_check_directory(fs, dir);
7431 if (retval)
7432 return retval;
7433
7434 es.num = num;
7435 es.guaranteed_size = guaranteed_size;
7436 es.last_block = 0;
7437 es.err = 0;
7438 es.newblocks = 0;
7439 es.ctx = ctx;
7440
7441 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
7442 0, expand_dir_proc, &es);
7443
7444 if (es.err)
7445 return es.err;
7446
7447 /*
7448 * Update the size and block count fields in the inode.
7449 */
7450 retval = ext2fs_read_inode(fs, dir, &inode);
7451 if (retval)
7452 return retval;
7453
7454 inode.i_size = (es.last_block + 1) * fs->blocksize;
7455 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
7456
7457 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
7458
7459 return 0;
7460}
7461
7462/*
7463 * pass4.c -- pass #4 of e2fsck: Check reference counts
7464 *
7465 * Pass 4 frees the following data structures:
7466 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
7467 */
7468
7469/*
7470 * This routine is called when an inode is not connected to the
7471 * directory tree.
7472 *
7473 * This subroutine returns 1 then the caller shouldn't bother with the
7474 * rest of the pass 4 tests.
7475 */
7476static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
7477{
7478 ext2_filsys fs = ctx->fs;
7479 struct ext2_inode inode;
7480 struct problem_context pctx;
7481
7482 e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
7483 clear_problem_context(&pctx);
7484 pctx.ino = i;
7485 pctx.inode = &inode;
7486
7487 /*
7488 * Offer to delete any zero-length files that does not have
7489 * blocks. If there is an EA block, it might have useful
7490 * information, so we won't prompt to delete it, but let it be
7491 * reconnected to lost+found.
7492 */
7493 if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
7494 LINUX_S_ISDIR(inode.i_mode))) {
7495 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
7496 ext2fs_icount_store(ctx->inode_link_info, i, 0);
7497 inode.i_links_count = 0;
7498 inode.i_dtime = time(0);
7499 e2fsck_write_inode(ctx, i, &inode,
7500 "disconnect_inode");
7501 /*
7502 * Fix up the bitmaps...
7503 */
7504 e2fsck_read_bitmaps(ctx);
7505 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
7506 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
7507 ext2fs_inode_alloc_stats2(fs, i, -1,
7508 LINUX_S_ISDIR(inode.i_mode));
7509 return 0;
7510 }
7511 }
7512
7513 /*
7514 * Prompt to reconnect.
7515 */
7516 if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
7517 if (e2fsck_reconnect_file(ctx, i))
7518 ext2fs_unmark_valid(fs);
7519 } else {
7520 /*
7521 * If we don't attach the inode, then skip the
7522 * i_links_test since there's no point in trying to
7523 * force i_links_count to zero.
7524 */
7525 ext2fs_unmark_valid(fs);
7526 return 1;
7527 }
7528 return 0;
7529}
7530
7531
7532static void e2fsck_pass4(e2fsck_t ctx)
7533{
7534 ext2_filsys fs = ctx->fs;
7535 ext2_ino_t i;
7536 struct ext2_inode inode;
7537 struct problem_context pctx;
7538 __u16 link_count, link_counted;
7539 char *buf = 0;
7540 int group, maxgroup;
7541
7542 /* Pass 4 */
7543
7544 clear_problem_context(&pctx);
7545
7546 if (!(ctx->options & E2F_OPT_PREEN))
7547 fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
7548
7549 group = 0;
7550 maxgroup = fs->group_desc_count;
7551 if (ctx->progress)
7552 if ((ctx->progress)(ctx, 4, 0, maxgroup))
7553 return;
7554
7555 for (i=1; i <= fs->super->s_inodes_count; i++) {
7556 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7557 return;
7558 if ((i % fs->super->s_inodes_per_group) == 0) {
7559 group++;
7560 if (ctx->progress)
7561 if ((ctx->progress)(ctx, 4, group, maxgroup))
7562 return;
7563 }
7564 if (i == EXT2_BAD_INO ||
7565 (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
7566 continue;
7567 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
7568 (ctx->inode_imagic_map &&
7569 ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)))
7570 continue;
7571 ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
7572 ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
7573 if (link_counted == 0) {
7574 if (!buf)
7575 buf = e2fsck_allocate_memory(ctx,
7576 fs->blocksize, "bad_inode buffer");
7577 if (e2fsck_process_bad_inode(ctx, 0, i, buf))
7578 continue;
7579 if (disconnect_inode(ctx, i))
7580 continue;
7581 ext2fs_icount_fetch(ctx->inode_link_info, i,
7582 &link_count);
7583 ext2fs_icount_fetch(ctx->inode_count, i,
7584 &link_counted);
7585 }
7586 if (link_counted != link_count) {
7587 e2fsck_read_inode(ctx, i, &inode, "pass4");
7588 pctx.ino = i;
7589 pctx.inode = &inode;
7590 if (link_count != inode.i_links_count) {
7591 pctx.num = link_count;
7592 fix_problem(ctx,
7593 PR_4_INCONSISTENT_COUNT, &pctx);
7594 }
7595 pctx.num = link_counted;
7596 if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
7597 inode.i_links_count = link_counted;
7598 e2fsck_write_inode(ctx, i, &inode, "pass4");
7599 }
7600 }
7601 }
7602 ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
7603 ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
7604 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
7605 ctx->inode_imagic_map = 0;
7606 ext2fs_free_mem(&buf);
7607}
7608
7609/*
7610 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
7611 */
7612
7613#define NO_BLK ((blk_t) -1)
7614
7615static void print_bitmap_problem(e2fsck_t ctx, int problem,
7616 struct problem_context *pctx)
7617{
7618 switch (problem) {
7619 case PR_5_BLOCK_UNUSED:
7620 if (pctx->blk == pctx->blk2)
7621 pctx->blk2 = 0;
7622 else
7623 problem = PR_5_BLOCK_RANGE_UNUSED;
7624 break;
7625 case PR_5_BLOCK_USED:
7626 if (pctx->blk == pctx->blk2)
7627 pctx->blk2 = 0;
7628 else
7629 problem = PR_5_BLOCK_RANGE_USED;
7630 break;
7631 case PR_5_INODE_UNUSED:
7632 if (pctx->ino == pctx->ino2)
7633 pctx->ino2 = 0;
7634 else
7635 problem = PR_5_INODE_RANGE_UNUSED;
7636 break;
7637 case PR_5_INODE_USED:
7638 if (pctx->ino == pctx->ino2)
7639 pctx->ino2 = 0;
7640 else
7641 problem = PR_5_INODE_RANGE_USED;
7642 break;
7643 }
7644 fix_problem(ctx, problem, pctx);
7645 pctx->blk = pctx->blk2 = NO_BLK;
7646 pctx->ino = pctx->ino2 = 0;
7647}
7648
7649static void check_block_bitmaps(e2fsck_t ctx)
7650{
7651 ext2_filsys fs = ctx->fs;
7652 blk_t i;
7653 int *free_array;
7654 int group = 0;
7655 unsigned int blocks = 0;
7656 unsigned int free_blocks = 0;
7657 int group_free = 0;
7658 int actual, bitmap;
7659 struct problem_context pctx;
7660 int problem, save_problem, fixit, had_problem;
7661 errcode_t retval;
7662
7663 clear_problem_context(&pctx);
7664 free_array = (int *) e2fsck_allocate_memory(ctx,
7665 fs->group_desc_count * sizeof(int), "free block count array");
7666
7667 if ((fs->super->s_first_data_block <
7668 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
7669 (fs->super->s_blocks_count-1 >
7670 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
7671 pctx.num = 1;
7672 pctx.blk = fs->super->s_first_data_block;
7673 pctx.blk2 = fs->super->s_blocks_count -1;
7674 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
7675 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
7676 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
7677
7678 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
7679 return;
7680 }
7681
7682 if ((fs->super->s_first_data_block <
7683 ext2fs_get_block_bitmap_start(fs->block_map)) ||
7684 (fs->super->s_blocks_count-1 >
7685 ext2fs_get_block_bitmap_end(fs->block_map))) {
7686 pctx.num = 2;
7687 pctx.blk = fs->super->s_first_data_block;
7688 pctx.blk2 = fs->super->s_blocks_count -1;
7689 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
7690 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
7691 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
7692
7693 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
7694 return;
7695 }
7696
7697redo_counts:
7698 had_problem = 0;
7699 save_problem = 0;
7700 pctx.blk = pctx.blk2 = NO_BLK;
7701 for (i = fs->super->s_first_data_block;
7702 i < fs->super->s_blocks_count;
7703 i++) {
7704 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
7705 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
7706
7707 if (actual == bitmap)
7708 goto do_counts;
7709
7710 if (!actual && bitmap) {
7711 /*
7712 * Block not used, but marked in use in the bitmap.
7713 */
7714 problem = PR_5_BLOCK_UNUSED;
7715 } else {
7716 /*
7717 * Block used, but not marked in use in the bitmap.
7718 */
7719 problem = PR_5_BLOCK_USED;
7720 }
7721 if (pctx.blk == NO_BLK) {
7722 pctx.blk = pctx.blk2 = i;
7723 save_problem = problem;
7724 } else {
7725 if ((problem == save_problem) &&
7726 (pctx.blk2 == i-1))
7727 pctx.blk2++;
7728 else {
7729 print_bitmap_problem(ctx, save_problem, &pctx);
7730 pctx.blk = pctx.blk2 = i;
7731 save_problem = problem;
7732 }
7733 }
7734 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
7735 had_problem++;
7736
7737 do_counts:
7738 if (!bitmap) {
7739 group_free++;
7740 free_blocks++;
7741 }
7742 blocks ++;
7743 if ((blocks == fs->super->s_blocks_per_group) ||
7744 (i == fs->super->s_blocks_count-1)) {
7745 free_array[group] = group_free;
7746 group ++;
7747 blocks = 0;
7748 group_free = 0;
7749 if (ctx->progress)
7750 if ((ctx->progress)(ctx, 5, group,
7751 fs->group_desc_count*2))
7752 return;
7753 }
7754 }
7755 if (pctx.blk != NO_BLK)
7756 print_bitmap_problem(ctx, save_problem, &pctx);
7757 if (had_problem)
7758 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
7759 else
7760 fixit = -1;
7761 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
7762
7763 if (fixit == 1) {
7764 ext2fs_free_block_bitmap(fs->block_map);
7765 retval = ext2fs_copy_bitmap(ctx->block_found_map,
7766 &fs->block_map);
7767 if (retval) {
7768 clear_problem_context(&pctx);
7769 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
7770 ctx->flags |= E2F_FLAG_ABORT;
7771 return;
7772 }
7773 ext2fs_set_bitmap_padding(fs->block_map);
7774 ext2fs_mark_bb_dirty(fs);
7775
7776 /* Redo the counts */
7777 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
7778 memset(free_array, 0, fs->group_desc_count * sizeof(int));
7779 goto redo_counts;
7780 } else if (fixit == 0)
7781 ext2fs_unmark_valid(fs);
7782
7783 for (i = 0; i < fs->group_desc_count; i++) {
7784 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
7785 pctx.group = i;
7786 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
7787 pctx.blk2 = free_array[i];
7788
7789 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
7790 &pctx)) {
7791 fs->group_desc[i].bg_free_blocks_count =
7792 free_array[i];
7793 ext2fs_mark_super_dirty(fs);
7794 } else
7795 ext2fs_unmark_valid(fs);
7796 }
7797 }
7798 if (free_blocks != fs->super->s_free_blocks_count) {
7799 pctx.group = 0;
7800 pctx.blk = fs->super->s_free_blocks_count;
7801 pctx.blk2 = free_blocks;
7802
7803 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
7804 fs->super->s_free_blocks_count = free_blocks;
7805 ext2fs_mark_super_dirty(fs);
7806 } else
7807 ext2fs_unmark_valid(fs);
7808 }
7809 ext2fs_free_mem(&free_array);
7810}
7811
7812static void check_inode_bitmaps(e2fsck_t ctx)
7813{
7814 ext2_filsys fs = ctx->fs;
7815 ext2_ino_t i;
7816 unsigned int free_inodes = 0;
7817 int group_free = 0;
7818 int dirs_count = 0;
7819 int group = 0;
7820 unsigned int inodes = 0;
7821 int *free_array;
7822 int *dir_array;
7823 int actual, bitmap;
7824 errcode_t retval;
7825 struct problem_context pctx;
7826 int problem, save_problem, fixit, had_problem;
7827
7828 clear_problem_context(&pctx);
7829 free_array = (int *) e2fsck_allocate_memory(ctx,
7830 fs->group_desc_count * sizeof(int), "free inode count array");
7831
7832 dir_array = (int *) e2fsck_allocate_memory(ctx,
7833 fs->group_desc_count * sizeof(int), "directory count array");
7834
7835 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
7836 (fs->super->s_inodes_count >
7837 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
7838 pctx.num = 3;
7839 pctx.blk = 1;
7840 pctx.blk2 = fs->super->s_inodes_count;
7841 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
7842 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
7843 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
7844
7845 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
7846 return;
7847 }
7848 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
7849 (fs->super->s_inodes_count >
7850 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
7851 pctx.num = 4;
7852 pctx.blk = 1;
7853 pctx.blk2 = fs->super->s_inodes_count;
7854 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
7855 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
7856 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
7857
7858 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
7859 return;
7860 }
7861
7862redo_counts:
7863 had_problem = 0;
7864 save_problem = 0;
7865 pctx.ino = pctx.ino2 = 0;
7866 for (i = 1; i <= fs->super->s_inodes_count; i++) {
7867 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
7868 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
7869
7870 if (actual == bitmap)
7871 goto do_counts;
7872
7873 if (!actual && bitmap) {
7874 /*
7875 * Inode wasn't used, but marked in bitmap
7876 */
7877 problem = PR_5_INODE_UNUSED;
7878 } else /* if (actual && !bitmap) */ {
7879 /*
7880 * Inode used, but not in bitmap
7881 */
7882 problem = PR_5_INODE_USED;
7883 }
7884 if (pctx.ino == 0) {
7885 pctx.ino = pctx.ino2 = i;
7886 save_problem = problem;
7887 } else {
7888 if ((problem == save_problem) &&
7889 (pctx.ino2 == i-1))
7890 pctx.ino2++;
7891 else {
7892 print_bitmap_problem(ctx, save_problem, &pctx);
7893 pctx.ino = pctx.ino2 = i;
7894 save_problem = problem;
7895 }
7896 }
7897 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
7898 had_problem++;
7899
7900do_counts:
7901 if (!bitmap) {
7902 group_free++;
7903 free_inodes++;
7904 } else {
7905 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
7906 dirs_count++;
7907 }
7908 inodes++;
7909 if ((inodes == fs->super->s_inodes_per_group) ||
7910 (i == fs->super->s_inodes_count)) {
7911 free_array[group] = group_free;
7912 dir_array[group] = dirs_count;
7913 group ++;
7914 inodes = 0;
7915 group_free = 0;
7916 dirs_count = 0;
7917 if (ctx->progress)
7918 if ((ctx->progress)(ctx, 5,
7919 group + fs->group_desc_count,
7920 fs->group_desc_count*2))
7921 return;
7922 }
7923 }
7924 if (pctx.ino)
7925 print_bitmap_problem(ctx, save_problem, &pctx);
7926
7927 if (had_problem)
7928 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
7929 else
7930 fixit = -1;
7931 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
7932
7933 if (fixit == 1) {
7934 ext2fs_free_inode_bitmap(fs->inode_map);
7935 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
7936 &fs->inode_map);
7937 if (retval) {
7938 clear_problem_context(&pctx);
7939 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
7940 ctx->flags |= E2F_FLAG_ABORT;
7941 return;
7942 }
7943 ext2fs_set_bitmap_padding(fs->inode_map);
7944 ext2fs_mark_ib_dirty(fs);
7945
7946 /* redo counts */
7947 inodes = 0; free_inodes = 0; group_free = 0;
7948 dirs_count = 0; group = 0;
7949 memset(free_array, 0, fs->group_desc_count * sizeof(int));
7950 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
7951 goto redo_counts;
7952 } else if (fixit == 0)
7953 ext2fs_unmark_valid(fs);
7954
7955 for (i = 0; i < fs->group_desc_count; i++) {
7956 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
7957 pctx.group = i;
7958 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
7959 pctx.ino2 = free_array[i];
7960 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
7961 &pctx)) {
7962 fs->group_desc[i].bg_free_inodes_count =
7963 free_array[i];
7964 ext2fs_mark_super_dirty(fs);
7965 } else
7966 ext2fs_unmark_valid(fs);
7967 }
7968 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
7969 pctx.group = i;
7970 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
7971 pctx.ino2 = dir_array[i];
7972
7973 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
7974 &pctx)) {
7975 fs->group_desc[i].bg_used_dirs_count =
7976 dir_array[i];
7977 ext2fs_mark_super_dirty(fs);
7978 } else
7979 ext2fs_unmark_valid(fs);
7980 }
7981 }
7982 if (free_inodes != fs->super->s_free_inodes_count) {
7983 pctx.group = -1;
7984 pctx.ino = fs->super->s_free_inodes_count;
7985 pctx.ino2 = free_inodes;
7986
7987 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
7988 fs->super->s_free_inodes_count = free_inodes;
7989 ext2fs_mark_super_dirty(fs);
7990 } else
7991 ext2fs_unmark_valid(fs);
7992 }
7993 ext2fs_free_mem(&free_array);
7994 ext2fs_free_mem(&dir_array);
7995}
7996
7997static void check_inode_end(e2fsck_t ctx)
7998{
7999 ext2_filsys fs = ctx->fs;
8000 ext2_ino_t end, save_inodes_count, i;
8001 struct problem_context pctx;
8002
8003 clear_problem_context(&pctx);
8004
8005 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
8006 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
8007 &save_inodes_count);
8008 if (pctx.errcode) {
8009 pctx.num = 1;
8010 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8011 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8012 return;
8013 }
8014 if (save_inodes_count == end)
8015 return;
8016
8017 for (i = save_inodes_count + 1; i <= end; i++) {
8018 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
8019 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
8020 for (i = save_inodes_count + 1; i <= end; i++)
8021 ext2fs_mark_inode_bitmap(fs->inode_map,
8022 i);
8023 ext2fs_mark_ib_dirty(fs);
8024 } else
8025 ext2fs_unmark_valid(fs);
8026 break;
8027 }
8028 }
8029
8030 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
8031 save_inodes_count, 0);
8032 if (pctx.errcode) {
8033 pctx.num = 2;
8034 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8035 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8036 return;
8037 }
8038}
8039
8040static void check_block_end(e2fsck_t ctx)
8041{
8042 ext2_filsys fs = ctx->fs;
8043 blk_t end, save_blocks_count, i;
8044 struct problem_context pctx;
8045
8046 clear_problem_context(&pctx);
8047
8048 end = fs->block_map->start +
8049 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
8050 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
8051 &save_blocks_count);
8052 if (pctx.errcode) {
8053 pctx.num = 3;
8054 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8055 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8056 return;
8057 }
8058 if (save_blocks_count == end)
8059 return;
8060
8061 for (i = save_blocks_count + 1; i <= end; i++) {
8062 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
8063 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
8064 for (i = save_blocks_count + 1; i <= end; i++)
8065 ext2fs_mark_block_bitmap(fs->block_map,
8066 i);
8067 ext2fs_mark_bb_dirty(fs);
8068 } else
8069 ext2fs_unmark_valid(fs);
8070 break;
8071 }
8072 }
8073
8074 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
8075 save_blocks_count, 0);
8076 if (pctx.errcode) {
8077 pctx.num = 4;
8078 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
8079 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
8080 return;
8081 }
8082}
8083
8084static void e2fsck_pass5(e2fsck_t ctx)
8085{
8086 struct problem_context pctx;
8087
8088 /* Pass 5 */
8089
8090 clear_problem_context(&pctx);
8091
8092 if (!(ctx->options & E2F_OPT_PREEN))
8093 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
8094
8095 if (ctx->progress)
8096 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
8097 return;
8098
8099 e2fsck_read_bitmaps(ctx);
8100
8101 check_block_bitmaps(ctx);
8102 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8103 return;
8104 check_inode_bitmaps(ctx);
8105 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8106 return;
8107 check_inode_end(ctx);
8108 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8109 return;
8110 check_block_end(ctx);
8111 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8112 return;
8113
8114 ext2fs_free_inode_bitmap(ctx->inode_used_map);
8115 ctx->inode_used_map = 0;
8116 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
8117 ctx->inode_dir_map = 0;
8118 ext2fs_free_block_bitmap(ctx->block_found_map);
8119 ctx->block_found_map = 0;
8120}
8121
8122/*
8123 * problem.c --- report filesystem problems to the user
8124 */
8125
8126#define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */
8127#define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */
8128#define PR_NO_DEFAULT 0x000004 /* Default to no */
8129#define PR_MSG_ONLY 0x000008 /* Print message only */
8130
8131/* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */
8132
8133#define PR_FATAL 0x001000 /* Fatal error */
8134#define PR_AFTER_CODE 0x002000 /* After asking the first question, */
8135 /* ask another */
8136#define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */
8137#define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */
8138#define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */
8139#define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */
8140#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
8141
8142
8143#define PROMPT_NONE 0
8144#define PROMPT_FIX 1
8145#define PROMPT_CLEAR 2
8146#define PROMPT_RELOCATE 3
8147#define PROMPT_ALLOCATE 4
8148#define PROMPT_EXPAND 5
8149#define PROMPT_CONNECT 6
8150#define PROMPT_CREATE 7
8151#define PROMPT_SALVAGE 8
8152#define PROMPT_TRUNCATE 9
8153#define PROMPT_CLEAR_INODE 10
8154#define PROMPT_ABORT 11
8155#define PROMPT_SPLIT 12
8156#define PROMPT_CONTINUE 13
8157#define PROMPT_CLONE 14
8158#define PROMPT_DELETE 15
8159#define PROMPT_SUPPRESS 16
8160#define PROMPT_UNLINK 17
8161#define PROMPT_CLEAR_HTREE 18
8162#define PROMPT_RECREATE 19
8163#define PROMPT_NULL 20
8164
8165struct e2fsck_problem {
8166 problem_t e2p_code;
8167 const char * e2p_description;
8168 char prompt;
8169 int flags;
8170 problem_t second_code;
8171};
8172
8173struct latch_descr {
8174 int latch_code;
8175 problem_t question;
8176 problem_t end_message;
8177 int flags;
8178};
8179
8180/*
8181 * These are the prompts which are used to ask the user if they want
8182 * to fix a problem.
8183 */
8184static const char * const prompt[] = {
8185 N_("(no prompt)"), /* 0 */
8186 N_("Fix"), /* 1 */
8187 N_("Clear"), /* 2 */
8188 N_("Relocate"), /* 3 */
8189 N_("Allocate"), /* 4 */
8190 N_("Expand"), /* 5 */
8191 N_("Connect to /lost+found"), /* 6 */
8192 N_("Create"), /* 7 */
8193 N_("Salvage"), /* 8 */
8194 N_("Truncate"), /* 9 */
8195 N_("Clear inode"), /* 10 */
8196 N_("Abort"), /* 11 */
8197 N_("Split"), /* 12 */
8198 N_("Continue"), /* 13 */
8199 N_("Clone multiply-claimed blocks"), /* 14 */
8200 N_("Delete file"), /* 15 */
8201 N_("Suppress messages"),/* 16 */
8202 N_("Unlink"), /* 17 */
8203 N_("Clear HTree index"),/* 18 */
8204 N_("Recreate"), /* 19 */
8205 "", /* 20 */
8206};
8207
8208/*
8209 * These messages are printed when we are preen mode and we will be
8210 * automatically fixing the problem.
8211 */
8212static const char * const preen_msg[] = {
8213 N_("(NONE)"), /* 0 */
8214 N_("FIXED"), /* 1 */
8215 N_("CLEARED"), /* 2 */
8216 N_("RELOCATED"), /* 3 */
8217 N_("ALLOCATED"), /* 4 */
8218 N_("EXPANDED"), /* 5 */
8219 N_("RECONNECTED"), /* 6 */
8220 N_("CREATED"), /* 7 */
8221 N_("SALVAGED"), /* 8 */
8222 N_("TRUNCATED"), /* 9 */
8223 N_("INODE CLEARED"), /* 10 */
8224 N_("ABORTED"), /* 11 */
8225 N_("SPLIT"), /* 12 */
8226 N_("CONTINUING"), /* 13 */
8227 N_("MULTIPLY-CLAIMED BLOCKS CLONED"), /* 14 */
8228 N_("FILE DELETED"), /* 15 */
8229 N_("SUPPRESSED"), /* 16 */
8230 N_("UNLINKED"), /* 17 */
8231 N_("HTREE INDEX CLEARED"),/* 18 */
8232 N_("WILL RECREATE"), /* 19 */
8233 "", /* 20 */
8234};
8235
8236static const struct e2fsck_problem problem_table[] = {
8237
8238 /* Pre-Pass 1 errors */
8239
8240 /* Block bitmap not in group */
8241 { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
8242 PROMPT_RELOCATE, PR_LATCH_RELOC },
8243
8244 /* Inode bitmap not in group */
8245 { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
8246 PROMPT_RELOCATE, PR_LATCH_RELOC },
8247
8248 /* Inode table not in group */
8249 { PR_0_ITABLE_NOT_GROUP,
8250 N_("@i table for @g %g is not in @g. (@b %b)\n"
8251 "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
8252 PROMPT_RELOCATE, PR_LATCH_RELOC },
8253
8254 /* Superblock corrupt */
8255 { PR_0_SB_CORRUPT,
8256 N_("\nThe @S could not be read or does not describe a correct ext2\n"
8257 "@f. If the @v is valid and it really contains an ext2\n"
8258 "@f (and not swap or ufs or something else), then the @S\n"
8259 "is corrupt, and you might try running e2fsck with an alternate @S:\n"
8260 " e2fsck -b %S <@v>\n\n"),
8261 PROMPT_NONE, PR_FATAL },
8262
8263 /* Filesystem size is wrong */
8264 { PR_0_FS_SIZE_WRONG,
8265 N_("The @f size (according to the @S) is %b @bs\n"
8266 "The physical size of the @v is %c @bs\n"
8267 "Either the @S or the partition table is likely to be corrupt!\n"),
8268 PROMPT_ABORT, 0 },
8269
8270 /* Fragments not supported */
8271 { PR_0_NO_FRAGMENTS,
8272 N_("@S @b_size = %b, fragsize = %c.\n"
8273 "This version of e2fsck does not support fragment sizes different\n"
8274 "from the @b size.\n"),
8275 PROMPT_NONE, PR_FATAL },
8276
8277 /* Bad blocks_per_group */
8278 { PR_0_BLOCKS_PER_GROUP,
8279 N_("@S @bs_per_group = %b, should have been %c\n"),
8280 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
8281
8282 /* Bad first_data_block */
8283 { PR_0_FIRST_DATA_BLOCK,
8284 N_("@S first_data_@b = %b, should have been %c\n"),
8285 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
8286
8287 /* Adding UUID to filesystem */
8288 { PR_0_ADD_UUID,
8289 N_("@f did not have a UUID; generating one.\n\n"),
8290 PROMPT_NONE, 0 },
8291
8292 /* Relocate hint */
8293 { PR_0_RELOCATE_HINT,
8294 N_("Note: if several inode or block bitmap blocks or part\n"
8295 "of the inode table require relocation, you may wish to try\n"
8296 "running e2fsck with the '-b %S' option first. The problem\n"
8297 "may lie only with the primary block group descriptors, and\n"
8298 "the backup block group descriptors may be OK.\n\n"),
8299 PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
8300
8301 /* Miscellaneous superblock corruption */
8302 { PR_0_MISC_CORRUPT_SUPER,
8303 N_("Corruption found in @S. (%s = %N).\n"),
8304 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
8305
8306 /* Error determing physical device size of filesystem */
8307 { PR_0_GETSIZE_ERROR,
8308 N_("Error determining size of the physical @v: %m\n"),
8309 PROMPT_NONE, PR_FATAL },
8310
8311 /* Inode count in superblock is incorrect */
8312 { PR_0_INODE_COUNT_WRONG,
8313 N_("@i count in @S is %i, @s %j.\n"),
8314 PROMPT_FIX, 0 },
8315
8316 { PR_0_HURD_CLEAR_FILETYPE,
8317 N_("The Hurd does not support the filetype feature.\n"),
8318 PROMPT_CLEAR, 0 },
8319
8320 /* Journal inode is invalid */
8321 { PR_0_JOURNAL_BAD_INODE,
8322 N_("@S has an @n ext3 @j (@i %i).\n"),
8323 PROMPT_CLEAR, PR_PREEN_OK },
8324
8325 /* The external journal has (unsupported) multiple filesystems */
8326 { PR_0_JOURNAL_UNSUPP_MULTIFS,
8327 N_("External @j has multiple @f users (unsupported).\n"),
8328 PROMPT_NONE, PR_FATAL },
8329
8330 /* Can't find external journal */
8331 { PR_0_CANT_FIND_JOURNAL,
8332 N_("Can't find external @j\n"),
8333 PROMPT_NONE, PR_FATAL },
8334
8335 /* External journal has bad superblock */
8336 { PR_0_EXT_JOURNAL_BAD_SUPER,
8337 N_("External @j has bad @S\n"),
8338 PROMPT_NONE, PR_FATAL },
8339
8340 /* Superblock has a bad journal UUID */
8341 { PR_0_JOURNAL_BAD_UUID,
8342 N_("External @j does not support this @f\n"),
8343 PROMPT_NONE, PR_FATAL },
8344
8345 /* Journal has an unknown superblock type */
8346 { PR_0_JOURNAL_UNSUPP_SUPER,
8347 N_("Ext3 @j @S is unknown type %N (unsupported).\n"
8348 "It is likely that your copy of e2fsck is old and/or doesn't "
8349 "support this @j format.\n"
8350 "It is also possible the @j @S is corrupt.\n"),
8351 PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
8352
8353 /* Journal superblock is corrupt */
8354 { PR_0_JOURNAL_BAD_SUPER,
8355 N_("Ext3 @j @S is corrupt.\n"),
8356 PROMPT_FIX, PR_PREEN_OK },
8357
8358 /* Superblock flag should be cleared */
8359 { PR_0_JOURNAL_HAS_JOURNAL,
8360 N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
8361 PROMPT_CLEAR, PR_PREEN_OK },
8362
8363 /* Superblock flag is incorrect */
8364 { PR_0_JOURNAL_RECOVER_SET,
8365 N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
8366 PROMPT_CLEAR, PR_PREEN_OK },
8367
8368 /* Journal has data, but recovery flag is clear */
8369 { PR_0_JOURNAL_RECOVERY_CLEAR,
8370 N_("ext3 recovery flag is clear, but @j has data.\n"),
8371 PROMPT_NONE, 0 },
8372
8373 /* Ask if we should clear the journal */
8374 { PR_0_JOURNAL_RESET_JOURNAL,
8375 N_("Clear @j"),
8376 PROMPT_NULL, PR_PREEN_NOMSG },
8377
8378 /* Ask if we should run the journal anyway */
8379 { PR_0_JOURNAL_RUN,
8380 N_("Run @j anyway"),
8381 PROMPT_NULL, 0 },
8382
8383 /* Run the journal by default */
8384 { PR_0_JOURNAL_RUN_DEFAULT,
8385 N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
8386 PROMPT_NONE, 0 },
8387
8388 /* Clearing orphan inode */
8389 { PR_0_ORPHAN_CLEAR_INODE,
8390 N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
8391 PROMPT_NONE, 0 },
8392
8393 /* Illegal block found in orphaned inode */
8394 { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
8395 N_("@I @b #%B (%b) found in @o @i %i.\n"),
8396 PROMPT_NONE, 0 },
8397
8398 /* Already cleared block found in orphaned inode */
8399 { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
8400 N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
8401 PROMPT_NONE, 0 },
8402
8403 /* Illegal orphan inode in superblock */
8404 { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
8405 N_("@I @o @i %i in @S.\n"),
8406 PROMPT_NONE, 0 },
8407
8408 /* Illegal inode in orphaned inode list */
8409 { PR_0_ORPHAN_ILLEGAL_INODE,
8410 N_("@I @i %i in @o @i list.\n"),
8411 PROMPT_NONE, 0 },
8412
8413 /* Filesystem revision is 0, but feature flags are set */
8414 { PR_0_FS_REV_LEVEL,
8415 N_("@f has feature flag(s) set, but is a revision 0 @f. "),
8416 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
8417
8418 /* Journal superblock has an unknown read-only feature flag set */
8419 { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
8420 N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
8421 PROMPT_ABORT, 0 },
8422
8423 /* Journal superblock has an unknown incompatible feature flag set */
8424 { PR_0_JOURNAL_UNSUPP_INCOMPAT,
8425 N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
8426 PROMPT_ABORT, 0 },
8427
8428 /* Journal has unsupported version number */
8429 { PR_0_JOURNAL_UNSUPP_VERSION,
8430 N_("@j version not supported by this e2fsck.\n"),
8431 PROMPT_ABORT, 0 },
8432
8433 /* Moving journal to hidden file */
8434 { PR_0_MOVE_JOURNAL,
8435 N_("Moving @j from /%s to hidden @i.\n\n"),
8436 PROMPT_NONE, 0 },
8437
8438 /* Error moving journal to hidden file */
8439 { PR_0_ERR_MOVE_JOURNAL,
8440 N_("Error moving @j: %m\n\n"),
8441 PROMPT_NONE, 0 },
8442
8443 /* Clearing V2 journal superblock */
8444 { PR_0_CLEAR_V2_JOURNAL,
8445 N_("Found @n V2 @j @S fields (from V1 @j).\n"
8446 "Clearing fields beyond the V1 @j @S...\n\n"),
8447 PROMPT_NONE, 0 },
8448
8449 /* Backup journal inode blocks */
8450 { PR_0_BACKUP_JNL,
8451 N_("Backing up @j @i @b information.\n\n"),
8452 PROMPT_NONE, 0 },
8453
8454 /* Reserved blocks w/o resize_inode */
8455 { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
8456 N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
8457 "is %N; @s zero. "),
8458 PROMPT_FIX, 0 },
8459
8460 /* Resize_inode not enabled, but resize inode is non-zero */
8461 { PR_0_CLEAR_RESIZE_INODE,
8462 N_("Resize_@i not enabled, but the resize @i is non-zero. "),
8463 PROMPT_CLEAR, 0 },
8464
8465 /* Resize inode invalid */
8466 { PR_0_RESIZE_INODE_INVALID,
8467 N_("Resize @i not valid. "),
8468 PROMPT_RECREATE, 0 },
8469
8470 /* Pass 1 errors */
8471
8472 /* Pass 1: Checking inodes, blocks, and sizes */
8473 { PR_1_PASS_HEADER,
8474 N_("Pass 1: Checking @is, @bs, and sizes\n"),
8475 PROMPT_NONE, 0 },
8476
8477 /* Root directory is not an inode */
8478 { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
8479 PROMPT_CLEAR, 0 },
8480
8481 /* Root directory has dtime set */
8482 { PR_1_ROOT_DTIME,
8483 N_("@r has dtime set (probably due to old mke2fs). "),
8484 PROMPT_FIX, PR_PREEN_OK },
8485
8486 /* Reserved inode has bad mode */
8487 { PR_1_RESERVED_BAD_MODE,
8488 N_("Reserved @i %i (%Q) has @n mode. "),
8489 PROMPT_CLEAR, PR_PREEN_OK },
8490
8491 /* Deleted inode has zero dtime */
8492 { PR_1_ZERO_DTIME,
8493 N_("@D @i %i has zero dtime. "),
8494 PROMPT_FIX, PR_PREEN_OK },
8495
8496 /* Inode in use, but dtime set */
8497 { PR_1_SET_DTIME,
8498 N_("@i %i is in use, but has dtime set. "),
8499 PROMPT_FIX, PR_PREEN_OK },
8500
8501 /* Zero-length directory */
8502 { PR_1_ZERO_LENGTH_DIR,
8503 N_("@i %i is a @z @d. "),
8504 PROMPT_CLEAR, PR_PREEN_OK },
8505
8506 /* Block bitmap conflicts with some other fs block */
8507 { PR_1_BB_CONFLICT,
8508 N_("@g %g's @b @B at %b @C.\n"),
8509 PROMPT_RELOCATE, 0 },
8510
8511 /* Inode bitmap conflicts with some other fs block */
8512 { PR_1_IB_CONFLICT,
8513 N_("@g %g's @i @B at %b @C.\n"),
8514 PROMPT_RELOCATE, 0 },
8515
8516 /* Inode table conflicts with some other fs block */
8517 { PR_1_ITABLE_CONFLICT,
8518 N_("@g %g's @i table at %b @C.\n"),
8519 PROMPT_RELOCATE, 0 },
8520
8521 /* Block bitmap is on a bad block */
8522 { PR_1_BB_BAD_BLOCK,
8523 N_("@g %g's @b @B (%b) is bad. "),
8524 PROMPT_RELOCATE, 0 },
8525
8526 /* Inode bitmap is on a bad block */
8527 { PR_1_IB_BAD_BLOCK,
8528 N_("@g %g's @i @B (%b) is bad. "),
8529 PROMPT_RELOCATE, 0 },
8530
8531 /* Inode has incorrect i_size */
8532 { PR_1_BAD_I_SIZE,
8533 N_("@i %i, i_size is %Is, @s %N. "),
8534 PROMPT_FIX, PR_PREEN_OK },
8535
8536 /* Inode has incorrect i_blocks */
8537 { PR_1_BAD_I_BLOCKS,
8538 N_("@i %i, i_@bs is %Ib, @s %N. "),
8539 PROMPT_FIX, PR_PREEN_OK },
8540
8541 /* Illegal blocknumber in inode */
8542 { PR_1_ILLEGAL_BLOCK_NUM,
8543 N_("@I @b #%B (%b) in @i %i. "),
8544 PROMPT_CLEAR, PR_LATCH_BLOCK },
8545
8546 /* Block number overlaps fs metadata */
8547 { PR_1_BLOCK_OVERLAPS_METADATA,
8548 N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
8549 PROMPT_CLEAR, PR_LATCH_BLOCK },
8550
8551 /* Inode has illegal blocks (latch question) */
8552 { PR_1_INODE_BLOCK_LATCH,
8553 N_("@i %i has illegal @b(s). "),
8554 PROMPT_CLEAR, 0 },
8555
8556 /* Too many bad blocks in inode */
8557 { PR_1_TOO_MANY_BAD_BLOCKS,
8558 N_("Too many illegal @bs in @i %i.\n"),
8559 PROMPT_CLEAR_INODE, PR_NO_OK },
8560
8561 /* Illegal block number in bad block inode */
8562 { PR_1_BB_ILLEGAL_BLOCK_NUM,
8563 N_("@I @b #%B (%b) in bad @b @i. "),
8564 PROMPT_CLEAR, PR_LATCH_BBLOCK },
8565
8566 /* Bad block inode has illegal blocks (latch question) */
8567 { PR_1_INODE_BBLOCK_LATCH,
8568 N_("Bad @b @i has illegal @b(s). "),
8569 PROMPT_CLEAR, 0 },
8570
8571 /* Duplicate or bad blocks in use! */
8572 { PR_1_DUP_BLOCKS_PREENSTOP,
8573 N_("Duplicate or bad @b in use!\n"),
8574 PROMPT_NONE, 0 },
8575
8576 /* Bad block used as bad block indirect block */
8577 { PR_1_BBINODE_BAD_METABLOCK,
8578 N_("Bad @b %b used as bad @b @i indirect @b. "),
8579 PROMPT_CLEAR, PR_LATCH_BBLOCK },
8580
8581 /* Inconsistency can't be fixed prompt */
8582 { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
8583 N_("\nThe bad @b @i has probably been corrupted. You probably\n"
8584 "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
8585 "in the @f.\n"),
8586 PROMPT_CONTINUE, PR_PREEN_NOMSG },
8587
8588 /* Bad primary block */
8589 { PR_1_BAD_PRIMARY_BLOCK,
8590 N_("\nIf the @b is really bad, the @f cannot be fixed.\n"),
8591 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
8592
8593 /* Bad primary block prompt */
8594 { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
8595 N_("You can remove this @b from the bad @b list and hope\n"
8596 "that the @b is really OK. But there are no guarantees.\n\n"),
8597 PROMPT_CLEAR, PR_PREEN_NOMSG },
8598
8599 /* Bad primary superblock */
8600 { PR_1_BAD_PRIMARY_SUPERBLOCK,
8601 N_("The primary @S (%b) is on the bad @b list.\n"),
8602 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
8603
8604 /* Bad primary block group descriptors */
8605 { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
8606 N_("Block %b in the primary @g descriptors "
8607 "is on the bad @b list\n"),
8608 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
8609
8610 /* Bad superblock in group */
8611 { PR_1_BAD_SUPERBLOCK,
8612 N_("Warning: Group %g's @S (%b) is bad.\n"),
8613 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
8614
8615 /* Bad block group descriptors in group */
8616 { PR_1_BAD_GROUP_DESCRIPTORS,
8617 N_("Warning: Group %g's copy of the @g descriptors has a bad "
8618 "@b (%b).\n"),
8619 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
8620
8621 /* Block claimed for no reason */
8622 { PR_1_PROGERR_CLAIMED_BLOCK,
8623 N_("Programming error? @b #%b claimed for no reason in "
8624 "process_bad_@b.\n"),
8625 PROMPT_NONE, PR_PREEN_OK },
8626
8627 /* Error allocating blocks for relocating metadata */
8628 { PR_1_RELOC_BLOCK_ALLOCATE,
8629 N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
8630 PROMPT_NONE, PR_PREEN_OK },
8631
8632 /* Error allocating block buffer during relocation process */
8633 { PR_1_RELOC_MEMORY_ALLOCATE,
8634 N_("@A @b buffer for relocating %s\n"),
8635 PROMPT_NONE, PR_PREEN_OK },
8636
8637 /* Relocating metadata group information from X to Y */
8638 { PR_1_RELOC_FROM_TO,
8639 N_("Relocating @g %g's %s from %b to %c...\n"),
8640 PROMPT_NONE, PR_PREEN_OK },
8641
8642 /* Relocating metatdata group information to X */
8643 { PR_1_RELOC_TO,
8644 N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
8645 PROMPT_NONE, PR_PREEN_OK },
8646
8647 /* Block read error during relocation process */
8648 { PR_1_RELOC_READ_ERR,
8649 N_("Warning: could not read @b %b of %s: %m\n"),
8650 PROMPT_NONE, PR_PREEN_OK },
8651
8652 /* Block write error during relocation process */
8653 { PR_1_RELOC_WRITE_ERR,
8654 N_("Warning: could not write @b %b for %s: %m\n"),
8655 PROMPT_NONE, PR_PREEN_OK },
8656
8657 /* Error allocating inode bitmap */
8658 { PR_1_ALLOCATE_IBITMAP_ERROR,
8659 N_("@A @i @B (%N): %m\n"),
8660 PROMPT_NONE, PR_FATAL },
8661
8662 /* Error allocating block bitmap */
8663 { PR_1_ALLOCATE_BBITMAP_ERROR,
8664 N_("@A @b @B (%N): %m\n"),
8665 PROMPT_NONE, PR_FATAL },
8666
8667 /* Error allocating icount structure */
8668 { PR_1_ALLOCATE_ICOUNT,
8669 N_("@A icount link information: %m\n"),
8670 PROMPT_NONE, PR_FATAL },
8671
8672 /* Error allocating dbcount */
8673 { PR_1_ALLOCATE_DBCOUNT,
8674 N_("@A @d @b array: %m\n"),
8675 PROMPT_NONE, PR_FATAL },
8676
8677 /* Error while scanning inodes */
8678 { PR_1_ISCAN_ERROR,
8679 N_("Error while scanning @is (%i): %m\n"),
8680 PROMPT_NONE, PR_FATAL },
8681
8682 /* Error while iterating over blocks */
8683 { PR_1_BLOCK_ITERATE,
8684 N_("Error while iterating over @bs in @i %i: %m\n"),
8685 PROMPT_NONE, PR_FATAL },
8686
8687 /* Error while storing inode count information */
8688 { PR_1_ICOUNT_STORE,
8689 N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
8690 PROMPT_NONE, PR_FATAL },
8691
8692 /* Error while storing directory block information */
8693 { PR_1_ADD_DBLOCK,
8694 N_("Error storing @d @b information "
8695 "(@i=%i, @b=%b, num=%N): %m\n"),
8696 PROMPT_NONE, PR_FATAL },
8697
8698 /* Error while reading inode (for clearing) */
8699 { PR_1_READ_INODE,
8700 N_("Error reading @i %i: %m\n"),
8701 PROMPT_NONE, PR_FATAL },
8702
8703 /* Suppress messages prompt */
8704 { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
8705
8706 /* Imagic flag set on an inode when filesystem doesn't support it */
8707 { PR_1_SET_IMAGIC,
8708 N_("@i %i has imagic flag set. "),
8709 PROMPT_CLEAR, 0 },
8710
8711 /* Immutable flag set on a device or socket inode */
8712 { PR_1_SET_IMMUTABLE,
8713 N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
8714 "or append-only flag set. "),
8715 PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
8716
8717 /* Compression flag set on an inode when filesystem doesn't support it */
8718 { PR_1_COMPR_SET,
8719 N_("@i %i has @cion flag set on @f without @cion support. "),
8720 PROMPT_CLEAR, 0 },
8721
8722 /* Non-zero size for device, fifo or socket inode */
8723 { PR_1_SET_NONZSIZE,
8724 N_("Special (@v/socket/fifo) @i %i has non-zero size. "),
8725 PROMPT_FIX, PR_PREEN_OK },
8726
8727 /* Filesystem revision is 0, but feature flags are set */
8728 { PR_1_FS_REV_LEVEL,
8729 N_("@f has feature flag(s) set, but is a revision 0 @f. "),
8730 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
8731
8732 /* Journal inode is not in use, but contains data */
8733 { PR_1_JOURNAL_INODE_NOT_CLEAR,
8734 N_("@j @i is not in use, but contains data. "),
8735 PROMPT_CLEAR, PR_PREEN_OK },
8736
8737 /* Journal has bad mode */
8738 { PR_1_JOURNAL_BAD_MODE,
8739 N_("@j is not regular file. "),
8740 PROMPT_FIX, PR_PREEN_OK },
8741
8742 /* Deal with inodes that were part of orphan linked list */
8743 { PR_1_LOW_DTIME,
8744 N_("@i %i was part of the @o @i list. "),
8745 PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
8746
8747 /* Deal with inodes that were part of corrupted orphan linked
8748 list (latch question) */
8749 { PR_1_ORPHAN_LIST_REFUGEES,
8750 N_("@is that were part of a corrupted orphan linked list found. "),
8751 PROMPT_FIX, 0 },
8752
8753 /* Error allocating refcount structure */
8754 { PR_1_ALLOCATE_REFCOUNT,
8755 N_("@A refcount structure (%N): %m\n"),
8756 PROMPT_NONE, PR_FATAL },
8757
8758 /* Error reading extended attribute block */
8759 { PR_1_READ_EA_BLOCK,
8760 N_("Error reading @a @b %b for @i %i. "),
8761 PROMPT_CLEAR, 0 },
8762
8763 /* Invalid extended attribute block */
8764 { PR_1_BAD_EA_BLOCK,
8765 N_("@i %i has a bad @a @b %b. "),
8766 PROMPT_CLEAR, 0 },
8767
8768 /* Error reading Extended Attribute block while fixing refcount */
8769 { PR_1_EXTATTR_READ_ABORT,
8770 N_("Error reading @a @b %b (%m). "),
8771 PROMPT_ABORT, 0 },
8772
8773 /* Extended attribute reference count incorrect */
8774 { PR_1_EXTATTR_REFCOUNT,
8775 N_("@a @b %b has reference count %B, @s %N. "),
8776 PROMPT_FIX, 0 },
8777
8778 /* Error writing Extended Attribute block while fixing refcount */
8779 { PR_1_EXTATTR_WRITE,
8780 N_("Error writing @a @b %b (%m). "),
8781 PROMPT_ABORT, 0 },
8782
8783 /* Multiple EA blocks not supported */
8784 { PR_1_EA_MULTI_BLOCK,
8785 N_("@a @b %b has h_@bs > 1. "),
8786 PROMPT_CLEAR, 0},
8787
8788 /* Error allocating EA region allocation structure */
8789 { PR_1_EA_ALLOC_REGION,
8790 N_("@A @a @b %b. "),
8791 PROMPT_ABORT, 0},
8792
8793 /* Error EA allocation collision */
8794 { PR_1_EA_ALLOC_COLLISION,
8795 N_("@a @b %b is corrupt (allocation collision). "),
8796 PROMPT_CLEAR, 0},
8797
8798 /* Bad extended attribute name */
8799 { PR_1_EA_BAD_NAME,
8800 N_("@a @b %b is corrupt (@n name). "),
8801 PROMPT_CLEAR, 0},
8802
8803 /* Bad extended attribute value */
8804 { PR_1_EA_BAD_VALUE,
8805 N_("@a @b %b is corrupt (@n value). "),
8806 PROMPT_CLEAR, 0},
8807
8808 /* Inode too big (latch question) */
8809 { PR_1_INODE_TOOBIG,
8810 N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
8811
8812 /* Directory too big */
8813 { PR_1_TOOBIG_DIR,
8814 N_("@b #%B (%b) causes @d to be too big. "),
8815 PROMPT_CLEAR, PR_LATCH_TOOBIG },
8816
8817 /* Regular file too big */
8818 { PR_1_TOOBIG_REG,
8819 N_("@b #%B (%b) causes file to be too big. "),
8820 PROMPT_CLEAR, PR_LATCH_TOOBIG },
8821
8822 /* Symlink too big */
8823 { PR_1_TOOBIG_SYMLINK,
8824 N_("@b #%B (%b) causes symlink to be too big. "),
8825 PROMPT_CLEAR, PR_LATCH_TOOBIG },
8826
8827 /* INDEX_FL flag set on a non-HTREE filesystem */
8828 { PR_1_HTREE_SET,
8829 N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
8830 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8831
8832 /* INDEX_FL flag set on a non-directory */
8833 { PR_1_HTREE_NODIR,
8834 N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
8835 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8836
8837 /* Invalid root node in HTREE directory */
8838 { PR_1_HTREE_BADROOT,
8839 N_("@h %i has an @n root node.\n"),
8840 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8841
8842 /* Unsupported hash version in HTREE directory */
8843 { PR_1_HTREE_HASHV,
8844 N_("@h %i has an unsupported hash version (%N)\n"),
8845 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8846
8847 /* Incompatible flag in HTREE root node */
8848 { PR_1_HTREE_INCOMPAT,
8849 N_("@h %i uses an incompatible htree root node flag.\n"),
8850 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8851
8852 /* HTREE too deep */
8853 { PR_1_HTREE_DEPTH,
8854 N_("@h %i has a tree depth (%N) which is too big\n"),
8855 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
8856
8857 /* Bad block has indirect block that conflicts with filesystem block */
8858 { PR_1_BB_FS_BLOCK,
8859 N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
8860 "@f metadata. "),
8861 PROMPT_CLEAR, PR_LATCH_BBLOCK },
8862
8863 /* Resize inode failed */
8864 { PR_1_RESIZE_INODE_CREATE,
8865 N_("Resize @i (re)creation failed: %m."),
8866 PROMPT_ABORT, 0 },
8867
8868 /* invalid inode->i_extra_isize */
8869 { PR_1_EXTRA_ISIZE,
8870 N_("@i %i has a extra size (%IS) which is @n\n"),
8871 PROMPT_FIX, PR_PREEN_OK },
8872
8873 /* invalid ea entry->e_name_len */
8874 { PR_1_ATTR_NAME_LEN,
8875 N_("@a in @i %i has a namelen (%N) which is @n\n"),
8876 PROMPT_CLEAR, PR_PREEN_OK },
8877
8878 /* invalid ea entry->e_value_size */
8879 { PR_1_ATTR_VALUE_SIZE,
8880 N_("@a in @i %i has a value size (%N) which is @n\n"),
8881 PROMPT_CLEAR, PR_PREEN_OK },
8882
8883 /* invalid ea entry->e_value_offs */
8884 { PR_1_ATTR_VALUE_OFFSET,
8885 N_("@a in @i %i has a value offset (%N) which is @n\n"),
8886 PROMPT_CLEAR, PR_PREEN_OK },
8887
8888 /* invalid ea entry->e_value_block */
8889 { PR_1_ATTR_VALUE_BLOCK,
8890 N_("@a in @i %i has a value @b (%N) which is @n (must be 0)\n"),
8891 PROMPT_CLEAR, PR_PREEN_OK },
8892
8893 /* invalid ea entry->e_hash */
8894 { PR_1_ATTR_HASH,
8895 N_("@a in @i %i has a hash (%N) which is @n (must be 0)\n"),
8896 PROMPT_CLEAR, PR_PREEN_OK },
8897
8898 /* Pass 1b errors */
8899
8900 /* Pass 1B: Rescan for duplicate/bad blocks */
8901 { PR_1B_PASS_HEADER,
8902 N_("\nRunning additional passes to resolve @bs claimed by more than one @i...\n"
8903 "Pass 1B: Rescanning for @m @bs\n"),
8904 PROMPT_NONE, 0 },
8905
8906 /* Duplicate/bad block(s) header */
8907 { PR_1B_DUP_BLOCK_HEADER,
8908 N_("@m @b(s) in @i %i:"),
8909 PROMPT_NONE, 0 },
8910
8911 /* Duplicate/bad block(s) in inode */
8912 { PR_1B_DUP_BLOCK,
8913 " %b",
8914 PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
8915
8916 /* Duplicate/bad block(s) end */
8917 { PR_1B_DUP_BLOCK_END,
8918 "\n",
8919 PROMPT_NONE, PR_PREEN_NOHDR },
8920
8921 /* Error while scanning inodes */
8922 { PR_1B_ISCAN_ERROR,
8923 N_("Error while scanning inodes (%i): %m\n"),
8924 PROMPT_NONE, PR_FATAL },
8925
8926 /* Error allocating inode bitmap */
8927 { PR_1B_ALLOCATE_IBITMAP_ERROR,
8928 N_("@A @i @B (@i_dup_map): %m\n"),
8929 PROMPT_NONE, PR_FATAL },
8930
8931 /* Error while iterating over blocks */
8932 { PR_1B_BLOCK_ITERATE,
8933 N_("Error while iterating over @bs in @i %i (%s): %m\n"),
8934 PROMPT_NONE, 0 },
8935
8936 /* Error adjusting EA refcount */
8937 { PR_1B_ADJ_EA_REFCOUNT,
8938 N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
8939 PROMPT_NONE, 0 },
8940
8941
8942 /* Pass 1C: Scan directories for inodes with multiply-claimed blocks. */
8943 { PR_1C_PASS_HEADER,
8944 N_("Pass 1C: Scanning directories for @is with @m @bs.\n"),
8945 PROMPT_NONE, 0 },
8946
8947
8948 /* Pass 1D: Reconciling multiply-claimed blocks */
8949 { PR_1D_PASS_HEADER,
8950 N_("Pass 1D: Reconciling @m @bs\n"),
8951 PROMPT_NONE, 0 },
8952
8953 /* File has duplicate blocks */
8954 { PR_1D_DUP_FILE,
8955 N_("File %Q (@i #%i, mod time %IM)\n"
8956 " has %B @m @b(s), shared with %N file(s):\n"),
8957 PROMPT_NONE, 0 },
8958
8959 /* List of files sharing duplicate blocks */
8960 { PR_1D_DUP_FILE_LIST,
8961 N_("\t%Q (@i #%i, mod time %IM)\n"),
8962 PROMPT_NONE, 0 },
8963
8964 /* File sharing blocks with filesystem metadata */
8965 { PR_1D_SHARE_METADATA,
8966 N_("\t<@f metadata>\n"),
8967 PROMPT_NONE, 0 },
8968
8969 /* Report of how many duplicate/bad inodes */
8970 { PR_1D_NUM_DUP_INODES,
8971 N_("(There are %N @is containing @m @bs.)\n\n"),
8972 PROMPT_NONE, 0 },
8973
8974 /* Duplicated blocks already reassigned or cloned. */
8975 { PR_1D_DUP_BLOCKS_DEALT,
8976 N_("@m @bs already reassigned or cloned.\n\n"),
8977 PROMPT_NONE, 0 },
8978
8979 /* Clone duplicate/bad blocks? */
8980 { PR_1D_CLONE_QUESTION,
8981 "", PROMPT_CLONE, PR_NO_OK },
8982
8983 /* Delete file? */
8984 { PR_1D_DELETE_QUESTION,
8985 "", PROMPT_DELETE, 0 },
8986
8987 /* Couldn't clone file (error) */
8988 { PR_1D_CLONE_ERROR,
8989 N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
8990
8991 /* Pass 2 errors */
8992
8993 /* Pass 2: Checking directory structure */
8994 { PR_2_PASS_HEADER,
8995 N_("Pass 2: Checking @d structure\n"),
8996 PROMPT_NONE, 0 },
8997
8998 /* Bad inode number for '.' */
8999 { PR_2_BAD_INODE_DOT,
9000 N_("@n @i number for '.' in @d @i %i.\n"),
9001 PROMPT_FIX, 0 },
9002
9003 /* Directory entry has bad inode number */
9004 { PR_2_BAD_INO,
9005 N_("@E has @n @i #: %Di.\n"),
9006 PROMPT_CLEAR, 0 },
9007
9008 /* Directory entry has deleted or unused inode */
9009 { PR_2_UNUSED_INODE,
9010 N_("@E has @D/unused @i %Di. "),
9011 PROMPT_CLEAR, PR_PREEN_OK },
9012
9013 /* Directry entry is link to '.' */
9014 { PR_2_LINK_DOT,
9015 N_("@E @L to '.' "),
9016 PROMPT_CLEAR, 0 },
9017
9018 /* Directory entry points to inode now located in a bad block */
9019 { PR_2_BB_INODE,
9020 N_("@E points to @i (%Di) located in a bad @b.\n"),
9021 PROMPT_CLEAR, 0 },
9022
9023 /* Directory entry contains a link to a directory */
9024 { PR_2_LINK_DIR,
9025 N_("@E @L to @d %P (%Di).\n"),
9026 PROMPT_CLEAR, 0 },
9027
9028 /* Directory entry contains a link to the root directry */
9029 { PR_2_LINK_ROOT,
9030 N_("@E @L to the @r.\n"),
9031 PROMPT_CLEAR, 0 },
9032
9033 /* Directory entry has illegal characters in its name */
9034 { PR_2_BAD_NAME,
9035 N_("@E has illegal characters in its name.\n"),
9036 PROMPT_FIX, 0 },
9037
9038 /* Missing '.' in directory inode */
9039 { PR_2_MISSING_DOT,
9040 N_("Missing '.' in @d @i %i.\n"),
9041 PROMPT_FIX, 0 },
9042
9043 /* Missing '..' in directory inode */
9044 { PR_2_MISSING_DOT_DOT,
9045 N_("Missing '..' in @d @i %i.\n"),
9046 PROMPT_FIX, 0 },
9047
9048 /* First entry in directory inode doesn't contain '.' */
9049 { PR_2_1ST_NOT_DOT,
9050 N_("First @e '%Dn' (@i=%Di) in @d @i %i (%p) @s '.'\n"),
9051 PROMPT_FIX, 0 },
9052
9053 /* Second entry in directory inode doesn't contain '..' */
9054 { PR_2_2ND_NOT_DOT_DOT,
9055 N_("Second @e '%Dn' (@i=%Di) in @d @i %i @s '..'\n"),
9056 PROMPT_FIX, 0 },
9057
9058 /* i_faddr should be zero */
9059 { PR_2_FADDR_ZERO,
9060 N_("i_faddr @F %IF, @s zero.\n"),
9061 PROMPT_CLEAR, 0 },
9062
9063 /* i_file_acl should be zero */
9064 { PR_2_FILE_ACL_ZERO,
9065 N_("i_file_acl @F %If, @s zero.\n"),
9066 PROMPT_CLEAR, 0 },
9067
9068 /* i_dir_acl should be zero */
9069 { PR_2_DIR_ACL_ZERO,
9070 N_("i_dir_acl @F %Id, @s zero.\n"),
9071 PROMPT_CLEAR, 0 },
9072
9073 /* i_frag should be zero */
9074 { PR_2_FRAG_ZERO,
9075 N_("i_frag @F %N, @s zero.\n"),
9076 PROMPT_CLEAR, 0 },
9077
9078 /* i_fsize should be zero */
9079 { PR_2_FSIZE_ZERO,
9080 N_("i_fsize @F %N, @s zero.\n"),
9081 PROMPT_CLEAR, 0 },
9082
9083 /* inode has bad mode */
9084 { PR_2_BAD_MODE,
9085 N_("@i %i (%Q) has @n mode (%Im).\n"),
9086 PROMPT_CLEAR, 0 },
9087
9088 /* directory corrupted */
9089 { PR_2_DIR_CORRUPTED,
9090 N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
9091 PROMPT_SALVAGE, 0 },
9092
9093 /* filename too long */
9094 { PR_2_FILENAME_LONG,
9095 N_("@d @i %i, @b %B, offset %N: filename too long\n"),
9096 PROMPT_TRUNCATE, 0 },
9097
9098 /* Directory inode has a missing block (hole) */
9099 { PR_2_DIRECTORY_HOLE,
9100 N_("@d @i %i has an unallocated @b #%B. "),
9101 PROMPT_ALLOCATE, 0 },
9102
9103 /* '.' is not NULL terminated */
9104 { PR_2_DOT_NULL_TERM,
9105 N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
9106 PROMPT_FIX, 0 },
9107
9108 /* '..' is not NULL terminated */
9109 { PR_2_DOT_DOT_NULL_TERM,
9110 N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
9111 PROMPT_FIX, 0 },
9112
9113 /* Illegal character device inode */
9114 { PR_2_BAD_CHAR_DEV,
9115 N_("@i %i (%Q) is an @I character @v.\n"),
9116 PROMPT_CLEAR, 0 },
9117
9118 /* Illegal block device inode */
9119 { PR_2_BAD_BLOCK_DEV,
9120 N_("@i %i (%Q) is an @I @b @v.\n"),
9121 PROMPT_CLEAR, 0 },
9122
9123 /* Duplicate '.' entry */
9124 { PR_2_DUP_DOT,
9125 N_("@E is duplicate '.' @e.\n"),
9126 PROMPT_FIX, 0 },
9127
9128 /* Duplicate '..' entry */
9129 { PR_2_DUP_DOT_DOT,
9130 N_("@E is duplicate '..' @e.\n"),
9131 PROMPT_FIX, 0 },
9132
9133 /* Internal error: couldn't find dir_info */
9134 { PR_2_NO_DIRINFO,
9135 N_("Internal error: cannot find dir_info for %i.\n"),
9136 PROMPT_NONE, PR_FATAL },
9137
9138 /* Final rec_len is wrong */
9139 { PR_2_FINAL_RECLEN,
9140 N_("@E has rec_len of %Dr, @s %N.\n"),
9141 PROMPT_FIX, 0 },
9142
9143 /* Error allocating icount structure */
9144 { PR_2_ALLOCATE_ICOUNT,
9145 N_("@A icount structure: %m\n"),
9146 PROMPT_NONE, PR_FATAL },
9147
9148 /* Error iterating over directory blocks */
9149 { PR_2_DBLIST_ITERATE,
9150 N_("Error iterating over @d @bs: %m\n"),
9151 PROMPT_NONE, PR_FATAL },
9152
9153 /* Error reading directory block */
9154 { PR_2_READ_DIRBLOCK,
9155 N_("Error reading @d @b %b (@i %i): %m\n"),
9156 PROMPT_CONTINUE, 0 },
9157
9158 /* Error writing directory block */
9159 { PR_2_WRITE_DIRBLOCK,
9160 N_("Error writing @d @b %b (@i %i): %m\n"),
9161 PROMPT_CONTINUE, 0 },
9162
9163 /* Error allocating new directory block */
9164 { PR_2_ALLOC_DIRBOCK,
9165 N_("@A new @d @b for @i %i (%s): %m\n"),
9166 PROMPT_NONE, 0 },
9167
9168 /* Error deallocating inode */
9169 { PR_2_DEALLOC_INODE,
9170 N_("Error deallocating @i %i: %m\n"),
9171 PROMPT_NONE, PR_FATAL },
9172
9173 /* Directory entry for '.' is big. Split? */
9174 { PR_2_SPLIT_DOT,
9175 N_("@d @e for '.' is big. "),
9176 PROMPT_SPLIT, PR_NO_OK },
9177
9178 /* Illegal FIFO inode */
9179 { PR_2_BAD_FIFO,
9180 N_("@i %i (%Q) is an @I FIFO.\n"),
9181 PROMPT_CLEAR, 0 },
9182
9183 /* Illegal socket inode */
9184 { PR_2_BAD_SOCKET,
9185 N_("@i %i (%Q) is an @I socket.\n"),
9186 PROMPT_CLEAR, 0 },
9187
9188 /* Directory filetype not set */
9189 { PR_2_SET_FILETYPE,
9190 N_("Setting filetype for @E to %N.\n"),
9191 PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
9192
9193 /* Directory filetype incorrect */
9194 { PR_2_BAD_FILETYPE,
9195 N_("@E has an incorrect filetype (was %Dt, @s %N).\n"),
9196 PROMPT_FIX, 0 },
9197
9198 /* Directory filetype set on filesystem */
9199 { PR_2_CLEAR_FILETYPE,
9200 N_("@E has filetype set.\n"),
9201 PROMPT_CLEAR, PR_PREEN_OK },
9202
9203 /* Directory filename is null */
9204 { PR_2_NULL_NAME,
9205 N_("@E has a @z name.\n"),
9206 PROMPT_CLEAR, 0 },
9207
9208 /* Invalid symlink */
9209 { PR_2_INVALID_SYMLINK,
9210 N_("Symlink %Q (@i #%i) is @n.\n"),
9211 PROMPT_CLEAR, 0 },
9212
9213 /* i_file_acl (extended attribute block) is bad */
9214 { PR_2_FILE_ACL_BAD,
9215 N_("@a @b @F @n (%If).\n"),
9216 PROMPT_CLEAR, 0 },
9217
9218 /* Filesystem contains large files, but has no such flag in sb */
9219 { PR_2_FEATURE_LARGE_FILES,
9220 N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
9221 PROMPT_FIX, 0 },
9222
9223 /* Node in HTREE directory not referenced */
9224 { PR_2_HTREE_NOTREF,
9225 N_("@p @h %d: node (%B) not referenced\n"),
9226 PROMPT_NONE, 0 },
9227
9228 /* Node in HTREE directory referenced twice */
9229 { PR_2_HTREE_DUPREF,
9230 N_("@p @h %d: node (%B) referenced twice\n"),
9231 PROMPT_NONE, 0 },
9232
9233 /* Node in HTREE directory has bad min hash */
9234 { PR_2_HTREE_MIN_HASH,
9235 N_("@p @h %d: node (%B) has bad min hash\n"),
9236 PROMPT_NONE, 0 },
9237
9238 /* Node in HTREE directory has bad max hash */
9239 { PR_2_HTREE_MAX_HASH,
9240 N_("@p @h %d: node (%B) has bad max hash\n"),
9241 PROMPT_NONE, 0 },
9242
9243 /* Clear invalid HTREE directory */
9244 { PR_2_HTREE_CLEAR,
9245 N_("@n @h %d (%q). "), PROMPT_CLEAR, 0 },
9246
9247 /* Bad block in htree interior node */
9248 { PR_2_HTREE_BADBLK,
9249 N_("@p @h %d (%q): bad @b number %b.\n"),
9250 PROMPT_CLEAR_HTREE, 0 },
9251
9252 /* Error adjusting EA refcount */
9253 { PR_2_ADJ_EA_REFCOUNT,
9254 N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
9255 PROMPT_NONE, PR_FATAL },
9256
9257 /* Invalid HTREE root node */
9258 { PR_2_HTREE_BAD_ROOT,
9259 N_("@p @h %d: root node is @n\n"),
9260 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9261
9262 /* Invalid HTREE limit */
9263 { PR_2_HTREE_BAD_LIMIT,
9264 N_("@p @h %d: node (%B) has @n limit (%N)\n"),
9265 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9266
9267 /* Invalid HTREE count */
9268 { PR_2_HTREE_BAD_COUNT,
9269 N_("@p @h %d: node (%B) has @n count (%N)\n"),
9270 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9271
9272 /* HTREE interior node has out-of-order hashes in table */
9273 { PR_2_HTREE_HASH_ORDER,
9274 N_("@p @h %d: node (%B) has an unordered hash table\n"),
9275 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
9276
9277 /* Node in HTREE directory has invalid depth */
9278 { PR_2_HTREE_BAD_DEPTH,
9279 N_("@p @h %d: node (%B) has @n depth\n"),
9280 PROMPT_NONE, 0 },
9281
9282 /* Duplicate directory entry found */
9283 { PR_2_DUPLICATE_DIRENT,
9284 N_("Duplicate @E found. "),
9285 PROMPT_CLEAR, 0 },
9286
9287 /* Non-unique filename found */
9288 { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
9289 N_("@E has a non-unique filename.\nRename to %s"),
9290 PROMPT_NULL, 0 },
9291
9292 /* Duplicate directory entry found */
9293 { PR_2_REPORT_DUP_DIRENT,
9294 N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
9295 PROMPT_NONE, 0 },
9296
9297 /* Pass 3 errors */
9298
9299 /* Pass 3: Checking directory connectivity */
9300 { PR_3_PASS_HEADER,
9301 N_("Pass 3: Checking @d connectivity\n"),
9302 PROMPT_NONE, 0 },
9303
9304 /* Root inode not allocated */
9305 { PR_3_NO_ROOT_INODE,
9306 N_("@r not allocated. "),
9307 PROMPT_ALLOCATE, 0 },
9308
9309 /* No room in lost+found */
9310 { PR_3_EXPAND_LF_DIR,
9311 N_("No room in @l @d. "),
9312 PROMPT_EXPAND, 0 },
9313
9314 /* Unconnected directory inode */
9315 { PR_3_UNCONNECTED_DIR,
9316 N_("Unconnected @d @i %i (%p)\n"),
9317 PROMPT_CONNECT, 0 },
9318
9319 /* /lost+found not found */
9320 { PR_3_NO_LF_DIR,
9321 N_("/@l not found. "),
9322 PROMPT_CREATE, PR_PREEN_OK },
9323
9324 /* .. entry is incorrect */
9325 { PR_3_BAD_DOT_DOT,
9326 N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
9327 PROMPT_FIX, 0 },
9328
9329 /* Bad or non-existent /lost+found. Cannot reconnect */
9330 { PR_3_NO_LPF,
9331 N_("Bad or non-existent /@l. Cannot reconnect.\n"),
9332 PROMPT_NONE, 0 },
9333
9334 /* Could not expand /lost+found */
9335 { PR_3_CANT_EXPAND_LPF,
9336 N_("Could not expand /@l: %m\n"),
9337 PROMPT_NONE, 0 },
9338
9339 /* Could not reconnect inode */
9340 { PR_3_CANT_RECONNECT,
9341 N_("Could not reconnect %i: %m\n"),
9342 PROMPT_NONE, 0 },
9343
9344 /* Error while trying to find /lost+found */
9345 { PR_3_ERR_FIND_LPF,
9346 N_("Error while trying to find /@l: %m\n"),
9347 PROMPT_NONE, 0 },
9348
9349 /* Error in ext2fs_new_block while creating /lost+found */
9350 { PR_3_ERR_LPF_NEW_BLOCK,
9351 N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
9352 PROMPT_NONE, 0 },
9353
9354 /* Error in ext2fs_new_inode while creating /lost+found */
9355 { PR_3_ERR_LPF_NEW_INODE,
9356 N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
9357 PROMPT_NONE, 0 },
9358
9359 /* Error in ext2fs_new_dir_block while creating /lost+found */
9360 { PR_3_ERR_LPF_NEW_DIR_BLOCK,
9361 N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
9362 PROMPT_NONE, 0 },
9363
9364 /* Error while writing directory block for /lost+found */
9365 { PR_3_ERR_LPF_WRITE_BLOCK,
9366 N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
9367 PROMPT_NONE, 0 },
9368
9369 /* Error while adjusting inode count */
9370 { PR_3_ADJUST_INODE,
9371 N_("Error while adjusting @i count on @i %i\n"),
9372 PROMPT_NONE, 0 },
9373
9374 /* Couldn't fix parent directory -- error */
9375 { PR_3_FIX_PARENT_ERR,
9376 N_("Couldn't fix parent of @i %i: %m\n\n"),
9377 PROMPT_NONE, 0 },
9378
9379 /* Couldn't fix parent directory -- couldn't find it */
9380 { PR_3_FIX_PARENT_NOFIND,
9381 N_("Couldn't fix parent of @i %i: Couldn't find parent @d @e\n\n"),
9382 PROMPT_NONE, 0 },
9383
9384 /* Error allocating inode bitmap */
9385 { PR_3_ALLOCATE_IBITMAP_ERROR,
9386 N_("@A @i @B (%N): %m\n"),
9387 PROMPT_NONE, PR_FATAL },
9388
9389 /* Error creating root directory */
9390 { PR_3_CREATE_ROOT_ERROR,
9391 N_("Error creating root @d (%s): %m\n"),
9392 PROMPT_NONE, PR_FATAL },
9393
9394 /* Error creating lost and found directory */
9395 { PR_3_CREATE_LPF_ERROR,
9396 N_("Error creating /@l @d (%s): %m\n"),
9397 PROMPT_NONE, PR_FATAL },
9398
9399 /* Root inode is not directory; aborting */
9400 { PR_3_ROOT_NOT_DIR_ABORT,
9401 N_("@r is not a @d; aborting.\n"),
9402 PROMPT_NONE, PR_FATAL },
9403
9404 /* Cannot proceed without a root inode. */
9405 { PR_3_NO_ROOT_INODE_ABORT,
9406 N_("Cannot proceed without a @r.\n"),
9407 PROMPT_NONE, PR_FATAL },
9408
9409 /* Internal error: couldn't find dir_info */
9410 { PR_3_NO_DIRINFO,
9411 N_("Internal error: cannot find dir_info for %i.\n"),
9412 PROMPT_NONE, PR_FATAL },
9413
9414 /* Lost+found not a directory */
9415 { PR_3_LPF_NOTDIR,
9416 N_("/@l is not a @d (ino=%i)\n"),
9417 PROMPT_UNLINK, 0 },
9418
9419 /* Pass 3A Directory Optimization */
9420
9421 /* Pass 3A: Optimizing directories */
9422 { PR_3A_PASS_HEADER,
9423 N_("Pass 3A: Optimizing directories\n"),
9424 PROMPT_NONE, PR_PREEN_NOMSG },
9425
9426 /* Error iterating over directories */
9427 { PR_3A_OPTIMIZE_ITER,
9428 N_("Failed to create dirs_to_hash iterator: %m"),
9429 PROMPT_NONE, 0 },
9430
9431 /* Error rehash directory */
9432 { PR_3A_OPTIMIZE_DIR_ERR,
9433 N_("Failed to optimize directory %q (%d): %m"),
9434 PROMPT_NONE, 0 },
9435
9436 /* Rehashing dir header */
9437 { PR_3A_OPTIMIZE_DIR_HEADER,
9438 N_("Optimizing directories: "),
9439 PROMPT_NONE, PR_MSG_ONLY },
9440
9441 /* Rehashing directory %d */
9442 { PR_3A_OPTIMIZE_DIR,
9443 " %d",
9444 PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
9445
9446 /* Rehashing dir end */
9447 { PR_3A_OPTIMIZE_DIR_END,
9448 "\n",
9449 PROMPT_NONE, PR_PREEN_NOHDR },
9450
9451 /* Pass 4 errors */
9452
9453 /* Pass 4: Checking reference counts */
9454 { PR_4_PASS_HEADER,
9455 N_("Pass 4: Checking reference counts\n"),
9456 PROMPT_NONE, 0 },
9457
9458 /* Unattached zero-length inode */
9459 { PR_4_ZERO_LEN_INODE,
9460 N_("@u @z @i %i. "),
9461 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
9462
9463 /* Unattached inode */
9464 { PR_4_UNATTACHED_INODE,
9465 N_("@u @i %i\n"),
9466 PROMPT_CONNECT, 0 },
9467
9468 /* Inode ref count wrong */
9469 { PR_4_BAD_REF_COUNT,
9470 N_("@i %i ref count is %Il, @s %N. "),
9471 PROMPT_FIX, PR_PREEN_OK },
9472
9473 { PR_4_INCONSISTENT_COUNT,
9474 N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
9475 "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
9476 "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
9477 "They @s the same!\n"),
9478 PROMPT_NONE, 0 },
9479
9480 /* Pass 5 errors */
9481
9482 /* Pass 5: Checking group summary information */
9483 { PR_5_PASS_HEADER,
9484 N_("Pass 5: Checking @g summary information\n"),
9485 PROMPT_NONE, 0 },
9486
9487 /* Padding at end of inode bitmap is not set. */
9488 { PR_5_INODE_BMAP_PADDING,
9489 N_("Padding at end of @i @B is not set. "),
9490 PROMPT_FIX, PR_PREEN_OK },
9491
9492 /* Padding at end of block bitmap is not set. */
9493 { PR_5_BLOCK_BMAP_PADDING,
9494 N_("Padding at end of @b @B is not set. "),
9495 PROMPT_FIX, PR_PREEN_OK },
9496
9497 /* Block bitmap differences header */
9498 { PR_5_BLOCK_BITMAP_HEADER,
9499 N_("@b @B differences: "),
9500 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
9501
9502 /* Block not used, but marked in bitmap */
9503 { PR_5_BLOCK_UNUSED,
9504 " -%b",
9505 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9506
9507 /* Block used, but not marked used in bitmap */
9508 { PR_5_BLOCK_USED,
9509 " +%b",
9510 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9511
9512 /* Block bitmap differences end */
9513 { PR_5_BLOCK_BITMAP_END,
9514 "\n",
9515 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9516
9517 /* Inode bitmap differences header */
9518 { PR_5_INODE_BITMAP_HEADER,
9519 N_("@i @B differences: "),
9520 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
9521
9522 /* Inode not used, but marked in bitmap */
9523 { PR_5_INODE_UNUSED,
9524 " -%i",
9525 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9526
9527 /* Inode used, but not marked used in bitmap */
9528 { PR_5_INODE_USED,
9529 " +%i",
9530 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9531
9532 /* Inode bitmap differences end */
9533 { PR_5_INODE_BITMAP_END,
9534 "\n",
9535 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9536
9537 /* Free inodes count for group wrong */
9538 { PR_5_FREE_INODE_COUNT_GROUP,
9539 N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
9540 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9541
9542 /* Directories count for group wrong */
9543 { PR_5_FREE_DIR_COUNT_GROUP,
9544 N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
9545 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9546
9547 /* Free inodes count wrong */
9548 { PR_5_FREE_INODE_COUNT,
9549 N_("Free @is count wrong (%i, counted=%j).\n"),
9550 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9551
9552 /* Free blocks count for group wrong */
9553 { PR_5_FREE_BLOCK_COUNT_GROUP,
9554 N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
9555 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9556
9557 /* Free blocks count wrong */
9558 { PR_5_FREE_BLOCK_COUNT,
9559 N_("Free @bs count wrong (%b, counted=%c).\n"),
9560 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
9561
9562 /* Programming error: bitmap endpoints don't match */
9563 { PR_5_BMAP_ENDPOINTS,
9564 N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
9565 "match calculated @B endpoints (%i, %j)\n"),
9566 PROMPT_NONE, PR_FATAL },
9567
9568 /* Internal error: fudging end of bitmap */
9569 { PR_5_FUDGE_BITMAP_ERROR,
9570 N_("Internal error: fudging end of bitmap (%N)\n"),
9571 PROMPT_NONE, PR_FATAL },
9572
9573 /* Error copying in replacement inode bitmap */
9574 { PR_5_COPY_IBITMAP_ERROR,
9575 N_("Error copying in replacement @i @B: %m\n"),
9576 PROMPT_NONE, PR_FATAL },
9577
9578 /* Error copying in replacement block bitmap */
9579 { PR_5_COPY_BBITMAP_ERROR,
9580 N_("Error copying in replacement @b @B: %m\n"),
9581 PROMPT_NONE, PR_FATAL },
9582
9583 /* Block range not used, but marked in bitmap */
9584 { PR_5_BLOCK_RANGE_UNUSED,
9585 " -(%b--%c)",
9586 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9587
9588 /* Block range used, but not marked used in bitmap */
9589 { PR_5_BLOCK_RANGE_USED,
9590 " +(%b--%c)",
9591 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9592
9593 /* Inode range not used, but marked in bitmap */
9594 { PR_5_INODE_RANGE_UNUSED,
9595 " -(%i--%j)",
9596 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9597
9598 /* Inode range used, but not marked used in bitmap */
9599 { PR_5_INODE_RANGE_USED,
9600 " +(%i--%j)",
9601 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
9602
9603 { 0 }
9604};
9605
9606/*
9607 * This is the latch flags register. It allows several problems to be
9608 * "latched" together. This means that the user has to answer but one
9609 * question for the set of problems, and all of the associated
9610 * problems will be either fixed or not fixed.
9611 */
9612static struct latch_descr pr_latch_info[] = {
9613 { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
9614 { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
9615 { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
9616 { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
9617 { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
9618 { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
9619 { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
9620 { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
9621 { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
9622 { -1, 0, 0 },
9623};
9624
9625static const struct e2fsck_problem *find_problem(problem_t code)
9626{
9627 int i;
9628
9629 for (i=0; problem_table[i].e2p_code; i++) {
9630 if (problem_table[i].e2p_code == code)
9631 return &problem_table[i];
9632 }
9633 return 0;
9634}
9635
9636static struct latch_descr *find_latch(int code)
9637{
9638 int i;
9639
9640 for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
9641 if (pr_latch_info[i].latch_code == code)
9642 return &pr_latch_info[i];
9643 }
9644 return 0;
9645}
9646
9647int end_problem_latch(e2fsck_t ctx, int mask)
9648{
9649 struct latch_descr *ldesc;
9650 struct problem_context pctx;
9651 int answer = -1;
9652
9653 ldesc = find_latch(mask);
9654 if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
9655 clear_problem_context(&pctx);
9656 answer = fix_problem(ctx, ldesc->end_message, &pctx);
9657 }
9658 ldesc->flags &= ~(PRL_VARIABLE);
9659 return answer;
9660}
9661
9662int set_latch_flags(int mask, int setflags, int clearflags)
9663{
9664 struct latch_descr *ldesc;
9665
9666 ldesc = find_latch(mask);
9667 if (!ldesc)
9668 return -1;
9669 ldesc->flags |= setflags;
9670 ldesc->flags &= ~clearflags;
9671 return 0;
9672}
9673
9674void clear_problem_context(struct problem_context *ctx)
9675{
9676 memset(ctx, 0, sizeof(struct problem_context));
9677 ctx->blkcount = -1;
9678 ctx->group = -1;
9679}
9680
9681int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
9682{
9683 ext2_filsys fs = ctx->fs;
9684 const struct e2fsck_problem *ptr;
9685 struct latch_descr *ldesc = 0;
9686 const char *message;
9687 int def_yn, answer, ans;
9688 int print_answer = 0;
9689 int suppress = 0;
9690
9691 ptr = find_problem(code);
9692 if (!ptr) {
9693 printf(_("Unhandled error code (0x%x)!\n"), code);
9694 return 0;
9695 }
9696 def_yn = 1;
9697 if ((ptr->flags & PR_NO_DEFAULT) ||
9698 ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
9699 (ctx->options & E2F_OPT_NO))
9700 def_yn= 0;
9701
9702 /*
9703 * Do special latch processing. This is where we ask the
9704 * latch question, if it exists
9705 */
9706 if (ptr->flags & PR_LATCH_MASK) {
9707 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
9708 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
9709 ans = fix_problem(ctx, ldesc->question, pctx);
9710 if (ans == 1)
9711 ldesc->flags |= PRL_YES;
9712 if (ans == 0)
9713 ldesc->flags |= PRL_NO;
9714 ldesc->flags |= PRL_LATCHED;
9715 }
9716 if (ldesc->flags & PRL_SUPPRESS)
9717 suppress++;
9718 }
9719 if ((ptr->flags & PR_PREEN_NOMSG) &&
9720 (ctx->options & E2F_OPT_PREEN))
9721 suppress++;
9722 if ((ptr->flags & PR_NO_NOMSG) &&
9723 (ctx->options & E2F_OPT_NO))
9724 suppress++;
9725 if (!suppress) {
9726 message = ptr->e2p_description;
9727 if ((ctx->options & E2F_OPT_PREEN) &&
9728 !(ptr->flags & PR_PREEN_NOHDR)) {
9729 printf("%s: ", ctx->device_name ?
9730 ctx->device_name : ctx->filesystem_name);
9731 }
9732 if (*message)
9733 print_e2fsck_message(ctx, _(message), pctx, 1);
9734 }
9735 if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
9736 preenhalt(ctx);
9737
9738 if (ptr->flags & PR_FATAL)
9739 bb_error_msg_and_die(0);
9740
9741 if (ptr->prompt == PROMPT_NONE) {
9742 if (ptr->flags & PR_NOCOLLATE)
9743 answer = -1;
9744 else
9745 answer = def_yn;
9746 } else {
9747 if (ctx->options & E2F_OPT_PREEN) {
9748 answer = def_yn;
9749 if (!(ptr->flags & PR_PREEN_NOMSG))
9750 print_answer = 1;
9751 } else if ((ptr->flags & PR_LATCH_MASK) &&
9752 (ldesc->flags & (PRL_YES | PRL_NO))) {
9753 if (!suppress)
9754 print_answer = 1;
9755 if (ldesc->flags & PRL_YES)
9756 answer = 1;
9757 else
9758 answer = 0;
9759 } else
9760 answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
9761 if (!answer && !(ptr->flags & PR_NO_OK))
9762 ext2fs_unmark_valid(fs);
9763
9764 if (print_answer)
9765 printf("%s.\n", answer ?
9766 _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
9767
9768 }
9769
9770 if ((ptr->prompt == PROMPT_ABORT) && answer)
9771 bb_error_msg_and_die(0);
9772
9773 if (ptr->flags & PR_AFTER_CODE)
9774 answer = fix_problem(ctx, ptr->second_code, pctx);
9775
9776 return answer;
9777}
9778
9779/*
9780 * linux/fs/recovery.c
9781 *
9782 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
9783 */
9784
9785/*
9786 * Maintain information about the progress of the recovery job, so that
9787 * the different passes can carry information between them.
9788 */
9789struct recovery_info
9790{
9791 tid_t start_transaction;
9792 tid_t end_transaction;
9793
9794 int nr_replays;
9795 int nr_revokes;
9796 int nr_revoke_hits;
9797};
9798
9799enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
9800static int do_one_pass(journal_t *journal,
9801 struct recovery_info *info, enum passtype pass);
9802static int scan_revoke_records(journal_t *, struct buffer_head *,
9803 tid_t, struct recovery_info *);
9804
9805/*
9806 * Read a block from the journal
9807 */
9808
9809static int jread(struct buffer_head **bhp, journal_t *journal,
9810 unsigned int offset)
9811{
9812 int err;
9813 unsigned long blocknr;
9814 struct buffer_head *bh;
9815
9816 *bhp = NULL;
9817
9818 err = journal_bmap(journal, offset, &blocknr);
9819
9820 if (err) {
9821 printf("JBD: bad block at offset %u\n", offset);
9822 return err;
9823 }
9824
9825 bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
9826 if (!bh)
9827 return -ENOMEM;
9828
9829 if (!buffer_uptodate(bh)) {
9830 /* If this is a brand new buffer, start readahead.
9831 Otherwise, we assume we are already reading it. */
9832 if (!buffer_req(bh))
9833 do_readahead(journal, offset);
9834 wait_on_buffer(bh);
9835 }
9836
9837 if (!buffer_uptodate(bh)) {
9838 printf("JBD: Failed to read block at offset %u\n", offset);
9839 brelse(bh);
9840 return -EIO;
9841 }
9842
9843 *bhp = bh;
9844 return 0;
9845}
9846
9847
9848/*
9849 * Count the number of in-use tags in a journal descriptor block.
9850 */
9851
9852static int count_tags(struct buffer_head *bh, int size)
9853{
9854 char * tagp;
9855 journal_block_tag_t * tag;
9856 int nr = 0;
9857
9858 tagp = &bh->b_data[sizeof(journal_header_t)];
9859
9860 while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
9861 tag = (journal_block_tag_t *) tagp;
9862
9863 nr++;
9864 tagp += sizeof(journal_block_tag_t);
9865 if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
9866 tagp += 16;
9867
9868 if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
9869 break;
9870 }
9871
9872 return nr;
9873}
9874
9875
9876/* Make sure we wrap around the log correctly! */
9877#define wrap(journal, var) \
9878do { \
9879 if (var >= (journal)->j_last) \
9880 var -= ((journal)->j_last - (journal)->j_first); \
9881} while (0)
9882
9883/**
9884 * int journal_recover(journal_t *journal) - recovers a on-disk journal
9885 * @journal: the journal to recover
9886 *
9887 * The primary function for recovering the log contents when mounting a
9888 * journaled device.
9889 *
9890 * Recovery is done in three passes. In the first pass, we look for the
9891 * end of the log. In the second, we assemble the list of revoke
9892 * blocks. In the third and final pass, we replay any un-revoked blocks
9893 * in the log.
9894 */
9895int journal_recover(journal_t *journal)
9896{
9897 int err;
9898 journal_superblock_t * sb;
9899
9900 struct recovery_info info;
9901
9902 memset(&info, 0, sizeof(info));
9903 sb = journal->j_superblock;
9904
9905 /*
9906 * The journal superblock's s_start field (the current log head)
9907 * is always zero if, and only if, the journal was cleanly
9908 * unmounted.
9909 */
9910
9911 if (!sb->s_start) {
9912 journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
9913 return 0;
9914 }
9915
9916 err = do_one_pass(journal, &info, PASS_SCAN);
9917 if (!err)
9918 err = do_one_pass(journal, &info, PASS_REVOKE);
9919 if (!err)
9920 err = do_one_pass(journal, &info, PASS_REPLAY);
9921
9922 /* Restart the log at the next transaction ID, thus invalidating
9923 * any existing commit records in the log. */
9924 journal->j_transaction_sequence = ++info.end_transaction;
9925
9926 journal_clear_revoke(journal);
9927 sync_blockdev(journal->j_fs_dev);
9928 return err;
9929}
9930
9931static int do_one_pass(journal_t *journal,
9932 struct recovery_info *info, enum passtype pass)
9933{
9934 unsigned int first_commit_ID, next_commit_ID;
9935 unsigned long next_log_block;
9936 int err, success = 0;
9937 journal_superblock_t * sb;
9938 journal_header_t * tmp;
9939 struct buffer_head * bh;
9940 unsigned int sequence;
9941 int blocktype;
9942
9943 /* Precompute the maximum metadata descriptors in a descriptor block */
9944 int MAX_BLOCKS_PER_DESC;
9945 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
9946 / sizeof(journal_block_tag_t));
9947
9948 /*
9949 * First thing is to establish what we expect to find in the log
9950 * (in terms of transaction IDs), and where (in terms of log
9951 * block offsets): query the superblock.
9952 */
9953
9954 sb = journal->j_superblock;
9955 next_commit_ID = ntohl(sb->s_sequence);
9956 next_log_block = ntohl(sb->s_start);
9957
9958 first_commit_ID = next_commit_ID;
9959 if (pass == PASS_SCAN)
9960 info->start_transaction = first_commit_ID;
9961
9962 /*
9963 * Now we walk through the log, transaction by transaction,
9964 * making sure that each transaction has a commit block in the
9965 * expected place. Each complete transaction gets replayed back
9966 * into the main filesystem.
9967 */
9968
9969 while (1) {
9970 int flags;
9971 char * tagp;
9972 journal_block_tag_t * tag;
9973 struct buffer_head * obh;
9974 struct buffer_head * nbh;
9975
9976 /* If we already know where to stop the log traversal,
9977 * check right now that we haven't gone past the end of
9978 * the log. */
9979
9980 if (pass != PASS_SCAN)
9981 if (tid_geq(next_commit_ID, info->end_transaction))
9982 break;
9983
9984 /* Skip over each chunk of the transaction looking
9985 * either the next descriptor block or the final commit
9986 * record. */
9987
9988 err = jread(&bh, journal, next_log_block);
9989 if (err)
9990 goto failed;
9991
9992 next_log_block++;
9993 wrap(journal, next_log_block);
9994
9995 /* What kind of buffer is it?
9996 *
9997 * If it is a descriptor block, check that it has the
9998 * expected sequence number. Otherwise, we're all done
9999 * here. */
10000
10001 tmp = (journal_header_t *)bh->b_data;
10002
10003 if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
10004 brelse(bh);
10005 break;
10006 }
10007
10008 blocktype = ntohl(tmp->h_blocktype);
10009 sequence = ntohl(tmp->h_sequence);
10010
10011 if (sequence != next_commit_ID) {
10012 brelse(bh);
10013 break;
10014 }
10015
10016 /* OK, we have a valid descriptor block which matches
10017 * all of the sequence number checks. What are we going
10018 * to do with it? That depends on the pass... */
10019
10020 switch(blocktype) {
10021 case JFS_DESCRIPTOR_BLOCK:
10022 /* If it is a valid descriptor block, replay it
10023 * in pass REPLAY; otherwise, just skip over the
10024 * blocks it describes. */
10025 if (pass != PASS_REPLAY) {
10026 next_log_block +=
10027 count_tags(bh, journal->j_blocksize);
10028 wrap(journal, next_log_block);
10029 brelse(bh);
10030 continue;
10031 }
10032
10033 /* A descriptor block: we can now write all of
10034 * the data blocks. Yay, useful work is finally
10035 * getting done here! */
10036
10037 tagp = &bh->b_data[sizeof(journal_header_t)];
10038 while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
10039 <= journal->j_blocksize) {
10040 unsigned long io_block;
10041
10042 tag = (journal_block_tag_t *) tagp;
10043 flags = ntohl(tag->t_flags);
10044
10045 io_block = next_log_block++;
10046 wrap(journal, next_log_block);
10047 err = jread(&obh, journal, io_block);
10048 if (err) {
10049 /* Recover what we can, but
10050 * report failure at the end. */
10051 success = err;
10052 printf("JBD: IO error %d recovering "
10053 "block %ld in log\n",
10054 err, io_block);
10055 } else {
10056 unsigned long blocknr;
10057
10058 blocknr = ntohl(tag->t_blocknr);
10059
10060 /* If the block has been
10061 * revoked, then we're all done
10062 * here. */
10063 if (journal_test_revoke
10064 (journal, blocknr,
10065 next_commit_ID)) {
10066 brelse(obh);
10067 ++info->nr_revoke_hits;
10068 goto skip_write;
10069 }
10070
10071 /* Find a buffer for the new
10072 * data being restored */
10073 nbh = getblk(journal->j_fs_dev,
10074 blocknr,
10075 journal->j_blocksize);
10076 if (nbh == NULL) {
10077 printf("JBD: Out of memory "
10078 "during recovery.\n");
10079 err = -ENOMEM;
10080 brelse(bh);
10081 brelse(obh);
10082 goto failed;
10083 }
10084
10085 lock_buffer(nbh);
10086 memcpy(nbh->b_data, obh->b_data,
10087 journal->j_blocksize);
10088 if (flags & JFS_FLAG_ESCAPE) {
10089 *((unsigned int *)bh->b_data) =
10090 htonl(JFS_MAGIC_NUMBER);
10091 }
10092
10093 mark_buffer_uptodate(nbh, 1);
10094 mark_buffer_dirty(nbh);
10095 ++info->nr_replays;
10096 /* ll_rw_block(WRITE, 1, &nbh); */
10097 unlock_buffer(nbh);
10098 brelse(obh);
10099 brelse(nbh);
10100 }
10101
10102 skip_write:
10103 tagp += sizeof(journal_block_tag_t);
10104 if (!(flags & JFS_FLAG_SAME_UUID))
10105 tagp += 16;
10106
10107 if (flags & JFS_FLAG_LAST_TAG)
10108 break;
10109 }
10110
10111 brelse(bh);
10112 continue;
10113
10114 case JFS_COMMIT_BLOCK:
10115 /* Found an expected commit block: not much to
10116 * do other than move on to the next sequence
10117 * number. */
10118 brelse(bh);
10119 next_commit_ID++;
10120 continue;
10121
10122 case JFS_REVOKE_BLOCK:
10123 /* If we aren't in the REVOKE pass, then we can
10124 * just skip over this block. */
10125 if (pass != PASS_REVOKE) {
10126 brelse(bh);
10127 continue;
10128 }
10129
10130 err = scan_revoke_records(journal, bh,
10131 next_commit_ID, info);
10132 brelse(bh);
10133 if (err)
10134 goto failed;
10135 continue;
10136
10137 default:
10138 goto done;
10139 }
10140 }
10141
10142 done:
10143 /*
10144 * We broke out of the log scan loop: either we came to the
10145 * known end of the log or we found an unexpected block in the
10146 * log. If the latter happened, then we know that the "current"
10147 * transaction marks the end of the valid log.
10148 */
10149
10150 if (pass == PASS_SCAN)
10151 info->end_transaction = next_commit_ID;
10152 else {
10153 /* It's really bad news if different passes end up at
10154 * different places (but possible due to IO errors). */
10155 if (info->end_transaction != next_commit_ID) {
10156 printf("JBD: recovery pass %d ended at "
10157 "transaction %u, expected %u\n",
10158 pass, next_commit_ID, info->end_transaction);
10159 if (!success)
10160 success = -EIO;
10161 }
10162 }
10163
10164 return success;
10165
10166 failed:
10167 return err;
10168}
10169
10170
10171/* Scan a revoke record, marking all blocks mentioned as revoked. */
10172
10173static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
10174 tid_t sequence, struct recovery_info *info)
10175{
10176 journal_revoke_header_t *header;
10177 int offset, max;
10178
10179 header = (journal_revoke_header_t *) bh->b_data;
10180 offset = sizeof(journal_revoke_header_t);
10181 max = ntohl(header->r_count);
10182
10183 while (offset < max) {
10184 unsigned long blocknr;
10185 int err;
10186
10187 blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
10188 offset += 4;
10189 err = journal_set_revoke(journal, blocknr, sequence);
10190 if (err)
10191 return err;
10192 ++info->nr_revokes;
10193 }
10194 return 0;
10195}
10196
10197
10198/*
10199 * rehash.c --- rebuild hash tree directories
10200 *
10201 * This algorithm is designed for simplicity of implementation and to
10202 * pack the directory as much as possible. It however requires twice
10203 * as much memory as the size of the directory. The maximum size
10204 * directory supported using a 4k blocksize is roughly a gigabyte, and
10205 * so there may very well be problems with machines that don't have
10206 * virtual memory, and obscenely large directories.
10207 *
10208 * An alternate algorithm which is much more disk intensive could be
10209 * written, and probably will need to be written in the future. The
10210 * design goals of such an algorithm are: (a) use (roughly) constant
10211 * amounts of memory, no matter how large the directory, (b) the
10212 * directory must be safe at all times, even if e2fsck is interrupted
10213 * in the middle, (c) we must use minimal amounts of extra disk
10214 * blocks. This pretty much requires an incremental approach, where
10215 * we are reading from one part of the directory, and inserting into
10216 * the front half. So the algorithm will have to keep track of a
10217 * moving block boundary between the new tree and the old tree, and
10218 * files will need to be moved from the old directory and inserted
10219 * into the new tree. If the new directory requires space which isn't
10220 * yet available, blocks from the beginning part of the old directory
10221 * may need to be moved to the end of the directory to make room for
10222 * the new tree:
10223 *
10224 * --------------------------------------------------------
10225 * | new tree | | old tree |
10226 * --------------------------------------------------------
10227 * ^ ptr ^ptr
10228 * tail new head old
10229 *
10230 * This is going to be a pain in the tuckus to implement, and will
10231 * require a lot more disk accesses. So I'm going to skip it for now;
10232 * it's only really going to be an issue for really, really big
10233 * filesystems (when we reach the level of tens of millions of files
10234 * in a single directory). It will probably be easier to simply
10235 * require that e2fsck use VM first.
10236 */
10237
10238struct fill_dir_struct {
10239 char *buf;
10240 struct ext2_inode *inode;
10241 int err;
10242 e2fsck_t ctx;
10243 struct hash_entry *harray;
10244 int max_array, num_array;
10245 int dir_size;
10246 int compress;
10247 ino_t parent;
10248};
10249
10250struct hash_entry {
10251 ext2_dirhash_t hash;
10252 ext2_dirhash_t minor_hash;
10253 struct ext2_dir_entry *dir;
10254};
10255
10256struct out_dir {
10257 int num;
10258 int max;
10259 char *buf;
10260 ext2_dirhash_t *hashes;
10261};
10262
10263static int fill_dir_block(ext2_filsys fs,
10264 blk_t *block_nr,
10265 e2_blkcnt_t blockcnt,
10266 blk_t ref_block FSCK_ATTR((unused)),
10267 int ref_offset FSCK_ATTR((unused)),
10268 void *priv_data)
10269{
10270 struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
10271 struct hash_entry *new_array, *ent;
10272 struct ext2_dir_entry *dirent;
10273 char *dir;
10274 unsigned int offset, dir_offset;
10275
10276 if (blockcnt < 0)
10277 return 0;
10278
10279 offset = blockcnt * fs->blocksize;
10280 if (offset + fs->blocksize > fd->inode->i_size) {
10281 fd->err = EXT2_ET_DIR_CORRUPTED;
10282 return BLOCK_ABORT;
10283 }
10284 dir = (fd->buf+offset);
10285 if (HOLE_BLKADDR(*block_nr)) {
10286 memset(dir, 0, fs->blocksize);
10287 dirent = (struct ext2_dir_entry *) dir;
10288 dirent->rec_len = fs->blocksize;
10289 } else {
10290 fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
10291 if (fd->err)
10292 return BLOCK_ABORT;
10293 }
10294 /* While the directory block is "hot", index it. */
10295 dir_offset = 0;
10296 while (dir_offset < fs->blocksize) {
10297 dirent = (struct ext2_dir_entry *) (dir + dir_offset);
10298 if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
10299 (dirent->rec_len < 8) ||
10300 ((dirent->rec_len % 4) != 0) ||
10301 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
10302 fd->err = EXT2_ET_DIR_CORRUPTED;
10303 return BLOCK_ABORT;
10304 }
10305 dir_offset += dirent->rec_len;
10306 if (dirent->inode == 0)
10307 continue;
10308 if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
10309 (dirent->name[0] == '.'))
10310 continue;
10311 if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
10312 (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
10313 fd->parent = dirent->inode;
10314 continue;
10315 }
10316 if (fd->num_array >= fd->max_array) {
10317 new_array = realloc(fd->harray,
10318 sizeof(struct hash_entry) * (fd->max_array+500));
10319 if (!new_array) {
10320 fd->err = ENOMEM;
10321 return BLOCK_ABORT;
10322 }
10323 fd->harray = new_array;
10324 fd->max_array += 500;
10325 }
10326 ent = fd->harray + fd->num_array++;
10327 ent->dir = dirent;
10328 fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
10329 if (fd->compress)
10330 ent->hash = ent->minor_hash = 0;
10331 else {
10332 fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
10333 dirent->name,
10334 dirent->name_len & 0xFF,
10335 fs->super->s_hash_seed,
10336 &ent->hash, &ent->minor_hash);
10337 if (fd->err)
10338 return BLOCK_ABORT;
10339 }
10340 }
10341
10342 return 0;
10343}
10344
10345/* Used for sorting the hash entry */
10346static int name_cmp(const void *a, const void *b)
10347{
10348 const struct hash_entry *he_a = (const struct hash_entry *) a;
10349 const struct hash_entry *he_b = (const struct hash_entry *) b;
10350 int ret;
10351 int min_len;
10352
10353 min_len = he_a->dir->name_len;
10354 if (min_len > he_b->dir->name_len)
10355 min_len = he_b->dir->name_len;
10356
10357 ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
10358 if (ret == 0) {
10359 if (he_a->dir->name_len > he_b->dir->name_len)
10360 ret = 1;
10361 else if (he_a->dir->name_len < he_b->dir->name_len)
10362 ret = -1;
10363 else
10364 ret = he_b->dir->inode - he_a->dir->inode;
10365 }
10366 return ret;
10367}
10368
10369/* Used for sorting the hash entry */
10370static int hash_cmp(const void *a, const void *b)
10371{
10372 const struct hash_entry *he_a = (const struct hash_entry *) a;
10373 const struct hash_entry *he_b = (const struct hash_entry *) b;
10374 int ret;
10375
10376 if (he_a->hash > he_b->hash)
10377 ret = 1;
10378 else if (he_a->hash < he_b->hash)
10379 ret = -1;
10380 else {
10381 if (he_a->minor_hash > he_b->minor_hash)
10382 ret = 1;
10383 else if (he_a->minor_hash < he_b->minor_hash)
10384 ret = -1;
10385 else
10386 ret = name_cmp(a, b);
10387 }
10388 return ret;
10389}
10390
10391static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
10392 int blocks)
10393{
10394 void *new_mem;
10395
10396 if (outdir->max) {
10397 new_mem = realloc(outdir->buf, blocks * fs->blocksize);
10398 if (!new_mem)
10399 return ENOMEM;
10400 outdir->buf = new_mem;
10401 new_mem = realloc(outdir->hashes,
10402 blocks * sizeof(ext2_dirhash_t));
10403 if (!new_mem)
10404 return ENOMEM;
10405 outdir->hashes = new_mem;
10406 } else {
10407 outdir->buf = malloc(blocks * fs->blocksize);
10408 outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
10409 outdir->num = 0;
10410 }
10411 outdir->max = blocks;
10412 return 0;
10413}
10414
10415static void free_out_dir(struct out_dir *outdir)
10416{
10417 free(outdir->buf);
10418 free(outdir->hashes);
10419 outdir->max = 0;
10420 outdir->num =0;
10421}
10422
10423static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
10424 char ** ret)
10425{
10426 errcode_t retval;
10427
10428 if (outdir->num >= outdir->max) {
10429 retval = alloc_size_dir(fs, outdir, outdir->max + 50);
10430 if (retval)
10431 return retval;
10432 }
10433 *ret = outdir->buf + (outdir->num++ * fs->blocksize);
10434 memset(*ret, 0, fs->blocksize);
10435 return 0;
10436}
10437
10438/*
10439 * This function is used to make a unique filename. We do this by
10440 * appending ~0, and then incrementing the number. However, we cannot
10441 * expand the length of the filename beyond the padding available in
10442 * the directory entry.
10443 */
10444static void mutate_name(char *str, __u16 *len)
10445{
10446 int i;
10447 __u16 l = *len & 0xFF, h = *len & 0xff00;
10448
10449 /*
10450 * First check to see if it looks the name has been mutated
10451 * already
10452 */
10453 for (i = l-1; i > 0; i--) {
10454 if (!isdigit(str[i]))
10455 break;
10456 }
10457 if ((i == l-1) || (str[i] != '~')) {
10458 if (((l-1) & 3) < 2)
10459 l += 2;
10460 else
10461 l = (l+3) & ~3;
10462 str[l-2] = '~';
10463 str[l-1] = '0';
10464 *len = l | h;
10465 return;
10466 }
10467 for (i = l-1; i >= 0; i--) {
10468 if (isdigit(str[i])) {
10469 if (str[i] == '9')
10470 str[i] = '0';
10471 else {
10472 str[i]++;
10473 return;
10474 }
10475 continue;
10476 }
10477 if (i == 1) {
10478 if (str[0] == 'z')
10479 str[0] = 'A';
10480 else if (str[0] == 'Z') {
10481 str[0] = '~';
10482 str[1] = '0';
10483 } else
10484 str[0]++;
10485 } else if (i > 0) {
10486 str[i] = '1';
10487 str[i-1] = '~';
10488 } else {
10489 if (str[0] == '~')
10490 str[0] = 'a';
10491 else
10492 str[0]++;
10493 }
10494 break;
10495 }
10496}
10497
10498static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
10499 ext2_ino_t ino,
10500 struct fill_dir_struct *fd)
10501{
10502 struct problem_context pctx;
10503 struct hash_entry *ent, *prev;
10504 int i, j;
10505 int fixed = 0;
10506 char new_name[256];
10507 __u16 new_len;
10508
10509 clear_problem_context(&pctx);
10510 pctx.ino = ino;
10511
10512 for (i=1; i < fd->num_array; i++) {
10513 ent = fd->harray + i;
10514 prev = ent - 1;
10515 if (!ent->dir->inode ||
10516 ((ent->dir->name_len & 0xFF) !=
10517 (prev->dir->name_len & 0xFF)) ||
10518 (strncmp(ent->dir->name, prev->dir->name,
10519 ent->dir->name_len & 0xFF)))
10520 continue;
10521 pctx.dirent = ent->dir;
10522 if ((ent->dir->inode == prev->dir->inode) &&
10523 fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
10524 e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
10525 ent->dir->inode = 0;
10526 fixed++;
10527 continue;
10528 }
10529 memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
10530 new_len = ent->dir->name_len;
10531 mutate_name(new_name, &new_len);
10532 for (j=0; j < fd->num_array; j++) {
10533 if ((i==j) ||
10534 ((ent->dir->name_len & 0xFF) !=
10535 (fd->harray[j].dir->name_len & 0xFF)) ||
10536 (strncmp(new_name, fd->harray[j].dir->name,
10537 new_len & 0xFF)))
10538 continue;
10539 mutate_name(new_name, &new_len);
10540
10541 j = -1;
10542 }
10543 new_name[new_len & 0xFF] = 0;
10544 pctx.str = new_name;
10545 if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
10546 memcpy(ent->dir->name, new_name, new_len & 0xFF);
10547 ent->dir->name_len = new_len;
10548 ext2fs_dirhash(fs->super->s_def_hash_version,
10549 ent->dir->name,
10550 ent->dir->name_len & 0xFF,
10551 fs->super->s_hash_seed,
10552 &ent->hash, &ent->minor_hash);
10553 fixed++;
10554 }
10555 }
10556 return fixed;
10557}
10558
10559
10560static errcode_t copy_dir_entries(ext2_filsys fs,
10561 struct fill_dir_struct *fd,
10562 struct out_dir *outdir)
10563{
10564 errcode_t retval;
10565 char *block_start;
10566 struct hash_entry *ent;
10567 struct ext2_dir_entry *dirent;
10568 int i, rec_len, left;
10569 ext2_dirhash_t prev_hash;
10570 int offset;
10571
10572 outdir->max = 0;
10573 retval = alloc_size_dir(fs, outdir,
10574 (fd->dir_size / fs->blocksize) + 2);
10575 if (retval)
10576 return retval;
10577 outdir->num = fd->compress ? 0 : 1;
10578 offset = 0;
10579 outdir->hashes[0] = 0;
10580 prev_hash = 1;
10581 if ((retval = get_next_block(fs, outdir, &block_start)))
10582 return retval;
10583 dirent = (struct ext2_dir_entry *) block_start;
10584 left = fs->blocksize;
10585 for (i=0; i < fd->num_array; i++) {
10586 ent = fd->harray + i;
10587 if (ent->dir->inode == 0)
10588 continue;
10589 rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
10590 if (rec_len > left) {
10591 if (left)
10592 dirent->rec_len += left;
10593 if ((retval = get_next_block(fs, outdir,
10594 &block_start)))
10595 return retval;
10596 offset = 0;
10597 }
10598 left = fs->blocksize - offset;
10599 dirent = (struct ext2_dir_entry *) (block_start + offset);
10600 if (offset == 0) {
10601 if (ent->hash == prev_hash)
10602 outdir->hashes[outdir->num-1] = ent->hash | 1;
10603 else
10604 outdir->hashes[outdir->num-1] = ent->hash;
10605 }
10606 dirent->inode = ent->dir->inode;
10607 dirent->name_len = ent->dir->name_len;
10608 dirent->rec_len = rec_len;
10609 memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
10610 offset += rec_len;
10611 left -= rec_len;
10612 if (left < 12) {
10613 dirent->rec_len += left;
10614 offset += left;
10615 left = 0;
10616 }
10617 prev_hash = ent->hash;
10618 }
10619 if (left)
10620 dirent->rec_len += left;
10621
10622 return 0;
10623}
10624
10625
10626static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
10627 ext2_ino_t ino, ext2_ino_t parent)
10628{
10629 struct ext2_dir_entry *dir;
10630 struct ext2_dx_root_info *root;
10631 struct ext2_dx_countlimit *limits;
10632 int filetype = 0;
10633
10634 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
10635 filetype = EXT2_FT_DIR << 8;
10636
10637 memset(buf, 0, fs->blocksize);
10638 dir = (struct ext2_dir_entry *) buf;
10639 dir->inode = ino;
10640 dir->name[0] = '.';
10641 dir->name_len = 1 | filetype;
10642 dir->rec_len = 12;
10643 dir = (struct ext2_dir_entry *) (buf + 12);
10644 dir->inode = parent;
10645 dir->name[0] = '.';
10646 dir->name[1] = '.';
10647 dir->name_len = 2 | filetype;
10648 dir->rec_len = fs->blocksize - 12;
10649
10650 root = (struct ext2_dx_root_info *) (buf+24);
10651 root->reserved_zero = 0;
10652 root->hash_version = fs->super->s_def_hash_version;
10653 root->info_length = 8;
10654 root->indirect_levels = 0;
10655 root->unused_flags = 0;
10656
10657 limits = (struct ext2_dx_countlimit *) (buf+32);
10658 limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
10659 limits->count = 0;
10660
10661 return root;
10662}
10663
10664
10665static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
10666{
10667 struct ext2_dir_entry *dir;
10668 struct ext2_dx_countlimit *limits;
10669
10670 memset(buf, 0, fs->blocksize);
10671 dir = (struct ext2_dir_entry *) buf;
10672 dir->inode = 0;
10673 dir->rec_len = fs->blocksize;
10674
10675 limits = (struct ext2_dx_countlimit *) (buf+8);
10676 limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
10677 limits->count = 0;
10678
10679 return (struct ext2_dx_entry *) limits;
10680}
10681
10682/*
10683 * This function takes the leaf nodes which have been written in
10684 * outdir, and populates the root node and any necessary interior nodes.
10685 */
10686static errcode_t calculate_tree(ext2_filsys fs,
10687 struct out_dir *outdir,
10688 ext2_ino_t ino,
10689 ext2_ino_t parent)
10690{
10691 struct ext2_dx_root_info *root_info;
10692 struct ext2_dx_entry *root, *dx_ent = 0;
10693 struct ext2_dx_countlimit *root_limit, *limit;
10694 errcode_t retval;
10695 char * block_start;
10696 int i, c1, c2, nblks;
10697 int limit_offset, root_offset;
10698
10699 root_info = set_root_node(fs, outdir->buf, ino, parent);
10700 root_offset = limit_offset = ((char *) root_info - outdir->buf) +
10701 root_info->info_length;
10702 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
10703 c1 = root_limit->limit;
10704 nblks = outdir->num;
10705
10706 /* Write out the pointer blocks */
10707 if (nblks-1 <= c1) {
10708 /* Just write out the root block, and we're done */
10709 root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
10710 for (i=1; i < nblks; i++) {
10711 root->block = ext2fs_cpu_to_le32(i);
10712 if (i != 1)
10713 root->hash =
10714 ext2fs_cpu_to_le32(outdir->hashes[i]);
10715 root++;
10716 c1--;
10717 }
10718 } else {
10719 c2 = 0;
10720 limit = 0;
10721 root_info->indirect_levels = 1;
10722 for (i=1; i < nblks; i++) {
10723 if (c1 == 0)
10724 return ENOSPC;
10725 if (c2 == 0) {
10726 if (limit)
10727 limit->limit = limit->count =
10728 ext2fs_cpu_to_le16(limit->limit);
10729 root = (struct ext2_dx_entry *)
10730 (outdir->buf + root_offset);
10731 root->block = ext2fs_cpu_to_le32(outdir->num);
10732 if (i != 1)
10733 root->hash =
10734 ext2fs_cpu_to_le32(outdir->hashes[i]);
10735 if ((retval = get_next_block(fs, outdir,
10736 &block_start)))
10737 return retval;
10738 dx_ent = set_int_node(fs, block_start);
10739 limit = (struct ext2_dx_countlimit *) dx_ent;
10740 c2 = limit->limit;
10741 root_offset += sizeof(struct ext2_dx_entry);
10742 c1--;
10743 }
10744 dx_ent->block = ext2fs_cpu_to_le32(i);
10745 if (c2 != limit->limit)
10746 dx_ent->hash =
10747 ext2fs_cpu_to_le32(outdir->hashes[i]);
10748 dx_ent++;
10749 c2--;
10750 }
10751 limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
10752 limit->limit = ext2fs_cpu_to_le16(limit->limit);
10753 }
10754 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
10755 root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
10756 root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
10757
10758 return 0;
10759}
10760
10761struct write_dir_struct {
10762 struct out_dir *outdir;
10763 errcode_t err;
10764 e2fsck_t ctx;
10765 int cleared;
10766};
10767
10768/*
10769 * Helper function which writes out a directory block.
10770 */
10771static int write_dir_block(ext2_filsys fs,
10772 blk_t *block_nr,
10773 e2_blkcnt_t blockcnt,
10774 blk_t ref_block FSCK_ATTR((unused)),
10775 int ref_offset FSCK_ATTR((unused)),
10776 void *priv_data)
10777{
10778 struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
10779 blk_t blk;
10780 char *dir;
10781
10782 if (*block_nr == 0)
10783 return 0;
10784 if (blockcnt >= wd->outdir->num) {
10785 e2fsck_read_bitmaps(wd->ctx);
10786 blk = *block_nr;
10787 ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
10788 ext2fs_block_alloc_stats(fs, blk, -1);
10789 *block_nr = 0;
10790 wd->cleared++;
10791 return BLOCK_CHANGED;
10792 }
10793 if (blockcnt < 0)
10794 return 0;
10795
10796 dir = wd->outdir->buf + (blockcnt * fs->blocksize);
10797 wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
10798 if (wd->err)
10799 return BLOCK_ABORT;
10800 return 0;
10801}
10802
10803static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
10804 struct out_dir *outdir,
10805 ext2_ino_t ino, int compress)
10806{
10807 struct write_dir_struct wd;
10808 errcode_t retval;
10809 struct ext2_inode inode;
10810
10811 retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
10812 if (retval)
10813 return retval;
10814
10815 wd.outdir = outdir;
10816 wd.err = 0;
10817 wd.ctx = ctx;
10818 wd.cleared = 0;
10819
10820 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
10821 write_dir_block, &wd);
10822 if (retval)
10823 return retval;
10824 if (wd.err)
10825 return wd.err;
10826
10827 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
10828 if (compress)
10829 inode.i_flags &= ~EXT2_INDEX_FL;
10830 else
10831 inode.i_flags |= EXT2_INDEX_FL;
10832 inode.i_size = outdir->num * fs->blocksize;
10833 inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
10834 e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
10835
10836 return 0;
10837}
10838
10839static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
10840{
10841 ext2_filsys fs = ctx->fs;
10842 errcode_t retval;
10843 struct ext2_inode inode;
10844 char *dir_buf = 0;
10845 struct fill_dir_struct fd;
10846 struct out_dir outdir;
10847
10848 outdir.max = outdir.num = 0;
10849 outdir.buf = 0;
10850 outdir.hashes = 0;
10851 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
10852
10853 retval = ENOMEM;
10854 fd.harray = 0;
10855 dir_buf = malloc(inode.i_size);
10856 if (!dir_buf)
10857 goto errout;
10858
10859 fd.max_array = inode.i_size / 32;
10860 fd.num_array = 0;
10861 fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
10862 if (!fd.harray)
10863 goto errout;
10864
10865 fd.ctx = ctx;
10866 fd.buf = dir_buf;
10867 fd.inode = &inode;
10868 fd.err = 0;
10869 fd.dir_size = 0;
10870 fd.compress = 0;
10871 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
10872 (inode.i_size / fs->blocksize) < 2)
10873 fd.compress = 1;
10874 fd.parent = 0;
10875
10876 /* Read in the entire directory into memory */
10877 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
10878 fill_dir_block, &fd);
10879 if (fd.err) {
10880 retval = fd.err;
10881 goto errout;
10882 }
10883
10884 /* Sort the list */
10885resort:
10886 if (fd.compress)
10887 qsort(fd.harray+2, fd.num_array-2,
10888 sizeof(struct hash_entry), name_cmp);
10889 else
10890 qsort(fd.harray, fd.num_array,
10891 sizeof(struct hash_entry), hash_cmp);
10892
10893 /*
10894 * Look for duplicates
10895 */
10896 if (duplicate_search_and_fix(ctx, fs, ino, &fd))
10897 goto resort;
10898
10899 if (ctx->options & E2F_OPT_NO) {
10900 retval = 0;
10901 goto errout;
10902 }
10903
10904 /*
10905 * Copy the directory entries. In a htree directory these
10906 * will become the leaf nodes.
10907 */
10908 retval = copy_dir_entries(fs, &fd, &outdir);
10909 if (retval)
10910 goto errout;
10911
10912 free(dir_buf); dir_buf = 0;
10913
10914 if (!fd.compress) {
10915 /* Calculate the interior nodes */
10916 retval = calculate_tree(fs, &outdir, ino, fd.parent);
10917 if (retval)
10918 goto errout;
10919 }
10920
10921 retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
10922
10923errout:
10924 free(dir_buf);
10925 free(fd.harray);
10926
10927 free_out_dir(&outdir);
10928 return retval;
10929}
10930
10931void e2fsck_rehash_directories(e2fsck_t ctx)
10932{
10933 struct problem_context pctx;
10934 struct dir_info *dir;
10935 ext2_u32_iterate iter;
10936 ext2_ino_t ino;
10937 errcode_t retval;
10938 int i, cur, max, all_dirs, dir_index, first = 1;
10939
10940 all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
10941
10942 if (!ctx->dirs_to_hash && !all_dirs)
10943 return;
10944
10945 e2fsck_get_lost_and_found(ctx, 0);
10946
10947 clear_problem_context(&pctx);
10948
10949 dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
10950 cur = 0;
10951 if (all_dirs) {
10952 i = 0;
10953 max = e2fsck_get_num_dirinfo(ctx);
10954 } else {
10955 retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
10956 &iter);
10957 if (retval) {
10958 pctx.errcode = retval;
10959 fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
10960 return;
10961 }
10962 max = ext2fs_u32_list_count(ctx->dirs_to_hash);
10963 }
10964 while (1) {
10965 if (all_dirs) {
10966 if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
10967 break;
10968 ino = dir->ino;
10969 } else {
10970 if (!ext2fs_u32_list_iterate(iter, &ino))
10971 break;
10972 }
10973 if (ino == ctx->lost_and_found)
10974 continue;
10975 pctx.dir = ino;
10976 if (first) {
10977 fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
10978 first = 0;
10979 }
10980 pctx.errcode = e2fsck_rehash_dir(ctx, ino);
10981 if (pctx.errcode) {
10982 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
10983 fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
10984 }
10985 if (ctx->progress && !ctx->progress_fd)
10986 e2fsck_simple_progress(ctx, "Rebuilding directory",
10987 100.0 * (float) (++cur) / (float) max, ino);
10988 }
10989 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
10990 if (!all_dirs)
10991 ext2fs_u32_list_iterate_end(iter);
10992
10993 ext2fs_u32_list_free(ctx->dirs_to_hash);
10994 ctx->dirs_to_hash = 0;
10995}
10996
10997/*
10998 * linux/fs/revoke.c
10999 *
11000 * Journal revoke routines for the generic filesystem journaling code;
11001 * part of the ext2fs journaling system.
11002 *
11003 * Revoke is the mechanism used to prevent old log records for deleted
11004 * metadata from being replayed on top of newer data using the same
11005 * blocks. The revoke mechanism is used in two separate places:
11006 *
11007 * + Commit: during commit we write the entire list of the current
11008 * transaction's revoked blocks to the journal
11009 *
11010 * + Recovery: during recovery we record the transaction ID of all
11011 * revoked blocks. If there are multiple revoke records in the log
11012 * for a single block, only the last one counts, and if there is a log
11013 * entry for a block beyond the last revoke, then that log entry still
11014 * gets replayed.
11015 *
11016 * We can get interactions between revokes and new log data within a
11017 * single transaction:
11018 *
11019 * Block is revoked and then journaled:
11020 * The desired end result is the journaling of the new block, so we
11021 * cancel the revoke before the transaction commits.
11022 *
11023 * Block is journaled and then revoked:
11024 * The revoke must take precedence over the write of the block, so we
11025 * need either to cancel the journal entry or to write the revoke
11026 * later in the log than the log block. In this case, we choose the
11027 * latter: journaling a block cancels any revoke record for that block
11028 * in the current transaction, so any revoke for that block in the
11029 * transaction must have happened after the block was journaled and so
11030 * the revoke must take precedence.
11031 *
11032 * Block is revoked and then written as data:
11033 * The data write is allowed to succeed, but the revoke is _not_
11034 * cancelled. We still need to prevent old log records from
11035 * overwriting the new data. We don't even need to clear the revoke
11036 * bit here.
11037 *
11038 * Revoke information on buffers is a tri-state value:
11039 *
11040 * RevokeValid clear: no cached revoke status, need to look it up
11041 * RevokeValid set, Revoked clear:
11042 * buffer has not been revoked, and cancel_revoke
11043 * need do nothing.
11044 * RevokeValid set, Revoked set:
11045 * buffer has been revoked.
11046 */
11047
11048static kmem_cache_t *revoke_record_cache;
11049static kmem_cache_t *revoke_table_cache;
11050
11051/* Each revoke record represents one single revoked block. During
11052 journal replay, this involves recording the transaction ID of the
11053 last transaction to revoke this block. */
11054
11055struct jbd_revoke_record_s
11056{
11057 struct list_head hash;
11058 tid_t sequence; /* Used for recovery only */
11059 unsigned long blocknr;
11060};
11061
11062
11063/* The revoke table is just a simple hash table of revoke records. */
11064struct jbd_revoke_table_s
11065{
11066 /* It is conceivable that we might want a larger hash table
11067 * for recovery. Must be a power of two. */
11068 int hash_size;
11069 int hash_shift;
11070 struct list_head *hash_table;
11071};
11072
11073
11074/* Utility functions to maintain the revoke table */
11075
11076/* Borrowed from buffer.c: this is a tried and tested block hash function */
11077static int hash(journal_t *journal, unsigned long block)
11078{
11079 struct jbd_revoke_table_s *table = journal->j_revoke;
11080 int hash_shift = table->hash_shift;
11081
11082 return ((block << (hash_shift - 6)) ^
11083 (block >> 13) ^
11084 (block << (hash_shift - 12))) & (table->hash_size - 1);
11085}
11086
11087static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
11088 tid_t seq)
11089{
11090 struct list_head *hash_list;
11091 struct jbd_revoke_record_s *record;
11092
11093 record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
11094 if (!record)
11095 goto oom;
11096
11097 record->sequence = seq;
11098 record->blocknr = blocknr;
11099 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
11100 list_add(&record->hash, hash_list);
11101 return 0;
11102
11103oom:
11104 return -ENOMEM;
11105}
11106
11107/* Find a revoke record in the journal's hash table. */
11108
11109static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
11110 unsigned long blocknr)
11111{
11112 struct list_head *hash_list;
11113 struct jbd_revoke_record_s *record;
11114
11115 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
11116
11117 record = (struct jbd_revoke_record_s *) hash_list->next;
11118 while (&(record->hash) != hash_list) {
11119 if (record->blocknr == blocknr)
11120 return record;
11121 record = (struct jbd_revoke_record_s *) record->hash.next;
11122 }
11123 return NULL;
11124}
11125
11126int journal_init_revoke_caches(void)
11127{
11128 revoke_record_cache = do_cache_create(sizeof(struct jbd_revoke_record_s));
11129 if (revoke_record_cache == 0)
11130 return -ENOMEM;
11131
11132 revoke_table_cache = do_cache_create(sizeof(struct jbd_revoke_table_s));
11133 if (revoke_table_cache == 0) {
11134 do_cache_destroy(revoke_record_cache);
11135 revoke_record_cache = NULL;
11136 return -ENOMEM;
11137 }
11138 return 0;
11139}
11140
11141void journal_destroy_revoke_caches(void)
11142{
11143 do_cache_destroy(revoke_record_cache);
11144 revoke_record_cache = 0;
11145 do_cache_destroy(revoke_table_cache);
11146 revoke_table_cache = 0;
11147}
11148
11149/* Initialise the revoke table for a given journal to a given size. */
11150
11151int journal_init_revoke(journal_t *journal, int hash_size)
11152{
11153 int shift, tmp;
11154
11155 journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
11156 if (!journal->j_revoke)
11157 return -ENOMEM;
11158
11159 /* Check that the hash_size is a power of two */
11160 journal->j_revoke->hash_size = hash_size;
11161
11162 shift = 0;
11163 tmp = hash_size;
11164 while((tmp >>= 1UL) != 0UL)
11165 shift++;
11166 journal->j_revoke->hash_shift = shift;
11167
11168 journal->j_revoke->hash_table = malloc(hash_size * sizeof(struct list_head));
11169 if (!journal->j_revoke->hash_table) {
11170 free(journal->j_revoke);
11171 journal->j_revoke = NULL;
11172 return -ENOMEM;
11173 }
11174
11175 for (tmp = 0; tmp < hash_size; tmp++)
11176 INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
11177
11178 return 0;
11179}
11180
11181/* Destoy a journal's revoke table. The table must already be empty! */
11182
11183void journal_destroy_revoke(journal_t *journal)
11184{
11185 struct jbd_revoke_table_s *table;
11186 struct list_head *hash_list;
11187 int i;
11188
11189 table = journal->j_revoke;
11190 if (!table)
11191 return;
11192
11193 for (i=0; i<table->hash_size; i++) {
11194 hash_list = &table->hash_table[i];
11195 }
11196
11197 free(table->hash_table);
11198 free(table);
11199 journal->j_revoke = NULL;
11200}
11201
11202/*
11203 * Revoke support for recovery.
11204 *
11205 * Recovery needs to be able to:
11206 *
11207 * record all revoke records, including the tid of the latest instance
11208 * of each revoke in the journal
11209 *
11210 * check whether a given block in a given transaction should be replayed
11211 * (ie. has not been revoked by a revoke record in that or a subsequent
11212 * transaction)
11213 *
11214 * empty the revoke table after recovery.
11215 */
11216
11217/*
11218 * First, setting revoke records. We create a new revoke record for
11219 * every block ever revoked in the log as we scan it for recovery, and
11220 * we update the existing records if we find multiple revokes for a
11221 * single block.
11222 */
11223
11224int journal_set_revoke(journal_t *journal, unsigned long blocknr,
11225 tid_t sequence)
11226{
11227 struct jbd_revoke_record_s *record;
11228
11229 record = find_revoke_record(journal, blocknr);
11230 if (record) {
11231 /* If we have multiple occurences, only record the
11232 * latest sequence number in the hashed record */
11233 if (tid_gt(sequence, record->sequence))
11234 record->sequence = sequence;
11235 return 0;
11236 }
11237 return insert_revoke_hash(journal, blocknr, sequence);
11238}
11239
11240/*
11241 * Test revoke records. For a given block referenced in the log, has
11242 * that block been revoked? A revoke record with a given transaction
11243 * sequence number revokes all blocks in that transaction and earlier
11244 * ones, but later transactions still need replayed.
11245 */
11246
11247int journal_test_revoke(journal_t *journal, unsigned long blocknr,
11248 tid_t sequence)
11249{
11250 struct jbd_revoke_record_s *record;
11251
11252 record = find_revoke_record(journal, blocknr);
11253 if (!record)
11254 return 0;
11255 if (tid_gt(sequence, record->sequence))
11256 return 0;
11257 return 1;
11258}
11259
11260/*
11261 * Finally, once recovery is over, we need to clear the revoke table so
11262 * that it can be reused by the running filesystem.
11263 */
11264
11265void journal_clear_revoke(journal_t *journal)
11266{
11267 int i;
11268 struct list_head *hash_list;
11269 struct jbd_revoke_record_s *record;
11270 struct jbd_revoke_table_s *revoke_var;
11271
11272 revoke_var = journal->j_revoke;
11273
11274 for (i = 0; i < revoke_var->hash_size; i++) {
11275 hash_list = &revoke_var->hash_table[i];
11276 while (!list_empty(hash_list)) {
11277 record = (struct jbd_revoke_record_s*) hash_list->next;
11278 list_del(&record->hash);
11279 free(record);
11280 }
11281 }
11282}
11283
11284/*
11285 * e2fsck.c - superblock checks
11286 */
11287
11288#define MIN_CHECK 1
11289#define MAX_CHECK 2
11290
11291static void check_super_value(e2fsck_t ctx, const char *descr,
11292 unsigned long value, int flags,
11293 unsigned long min_val, unsigned long max_val)
11294{
11295 struct problem_context pctx;
11296
11297 if (((flags & MIN_CHECK) && (value < min_val)) ||
11298 ((flags & MAX_CHECK) && (value > max_val))) {
11299 clear_problem_context(&pctx);
11300 pctx.num = value;
11301 pctx.str = descr;
11302 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
11303 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
11304 }
11305}
11306
11307/*
11308 * This routine may get stubbed out in special compilations of the
11309 * e2fsck code..
11310 */
11311#ifndef EXT2_SPECIAL_DEVICE_SIZE
11312static errcode_t e2fsck_get_device_size(e2fsck_t ctx)
11313{
11314 return (ext2fs_get_device_size(ctx->filesystem_name,
11315 EXT2_BLOCK_SIZE(ctx->fs->super),
11316 &ctx->num_blocks));
11317}
11318#endif
11319
11320/*
11321 * helper function to release an inode
11322 */
11323struct process_block_struct {
11324 e2fsck_t ctx;
11325 char *buf;
11326 struct problem_context *pctx;
11327 int truncating;
11328 int truncate_offset;
11329 e2_blkcnt_t truncate_block;
11330 int truncated_blocks;
11331 int abort;
11332 errcode_t errcode;
11333};
11334
11335static int release_inode_block(ext2_filsys fs, blk_t *block_nr,
11336 e2_blkcnt_t blockcnt,
11337 blk_t ref_blk FSCK_ATTR((unused)),
11338 int ref_offset FSCK_ATTR((unused)),
11339 void *priv_data)
11340{
11341 struct process_block_struct *pb;
11342 e2fsck_t ctx;
11343 struct problem_context *pctx;
11344 blk_t blk = *block_nr;
11345 int retval = 0;
11346
11347 pb = (struct process_block_struct *) priv_data;
11348 ctx = pb->ctx;
11349 pctx = pb->pctx;
11350
11351 pctx->blk = blk;
11352 pctx->blkcount = blockcnt;
11353
11354 if (HOLE_BLKADDR(blk))
11355 return 0;
11356
11357 if ((blk < fs->super->s_first_data_block) ||
11358 (blk >= fs->super->s_blocks_count)) {
11359 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
11360 return_abort:
11361 pb->abort = 1;
11362 return BLOCK_ABORT;
11363 }
11364
11365 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
11366 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
11367 goto return_abort;
11368 }
11369
11370 /*
11371 * If we are deleting an orphan, then we leave the fields alone.
11372 * If we are truncating an orphan, then update the inode fields
11373 * and clean up any partial block data.
11374 */
11375 if (pb->truncating) {
11376 /*
11377 * We only remove indirect blocks if they are
11378 * completely empty.
11379 */
11380 if (blockcnt < 0) {
11381 int i, limit;
11382 blk_t *bp;
11383
11384 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
11385 pb->buf);
11386 if (pb->errcode)
11387 goto return_abort;
11388
11389 limit = fs->blocksize >> 2;
11390 for (i = 0, bp = (blk_t *) pb->buf;
11391 i < limit; i++, bp++)
11392 if (*bp)
11393 return 0;
11394 }
11395 /*
11396 * We don't remove direct blocks until we've reached
11397 * the truncation block.
11398 */
11399 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
11400 return 0;
11401 /*
11402 * If part of the last block needs truncating, we do
11403 * it here.
11404 */
11405 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
11406 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
11407 pb->buf);
11408 if (pb->errcode)
11409 goto return_abort;
11410 memset(pb->buf + pb->truncate_offset, 0,
11411 fs->blocksize - pb->truncate_offset);
11412 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
11413 pb->buf);
11414 if (pb->errcode)
11415 goto return_abort;
11416 }
11417 pb->truncated_blocks++;
11418 *block_nr = 0;
11419 retval |= BLOCK_CHANGED;
11420 }
11421
11422 ext2fs_block_alloc_stats(fs, blk, -1);
11423 return retval;
11424}
11425
11426/*
11427 * This function releases an inode. Returns 1 if an inconsistency was
11428 * found. If the inode has a link count, then it is being truncated and
11429 * not deleted.
11430 */
11431static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
11432 struct ext2_inode *inode, char *block_buf,
11433 struct problem_context *pctx)
11434{
11435 struct process_block_struct pb;
11436 ext2_filsys fs = ctx->fs;
11437 errcode_t retval;
11438 __u32 count;
11439
11440 if (!ext2fs_inode_has_valid_blocks(inode))
11441 return 0;
11442
11443 pb.buf = block_buf + 3 * ctx->fs->blocksize;
11444 pb.ctx = ctx;
11445 pb.abort = 0;
11446 pb.errcode = 0;
11447 pb.pctx = pctx;
11448 if (inode->i_links_count) {
11449 pb.truncating = 1;
11450 pb.truncate_block = (e2_blkcnt_t)
11451 ((((long long)inode->i_size_high << 32) +
11452 inode->i_size + fs->blocksize - 1) /
11453 fs->blocksize);
11454 pb.truncate_offset = inode->i_size % fs->blocksize;
11455 } else {
11456 pb.truncating = 0;
11457 pb.truncate_block = 0;
11458 pb.truncate_offset = 0;
11459 }
11460 pb.truncated_blocks = 0;
11461 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
11462 block_buf, release_inode_block, &pb);
11463 if (retval) {
11464 bb_error_msg(_("while calling ext2fs_block_iterate for inode %d"),
11465 ino);
11466 return 1;
11467 }
11468 if (pb.abort)
11469 return 1;
11470
11471 /* Refresh the inode since ext2fs_block_iterate may have changed it */
11472 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
11473
11474 if (pb.truncated_blocks)
11475 inode->i_blocks -= pb.truncated_blocks *
11476 (fs->blocksize / 512);
11477
11478 if (inode->i_file_acl) {
11479 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
11480 block_buf, -1, &count);
11481 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
11482 retval = 0;
11483 count = 1;
11484 }
11485 if (retval) {
11486 bb_error_msg(_("while calling ext2fs_adjust_ea_refocunt for inode %d"),
11487 ino);
11488 return 1;
11489 }
11490 if (count == 0)
11491 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
11492 inode->i_file_acl = 0;
11493 }
11494 return 0;
11495}
11496
11497/*
11498 * This function releases all of the orphan inodes. It returns 1 if
11499 * it hit some error, and 0 on success.
11500 */
11501static int release_orphan_inodes(e2fsck_t ctx)
11502{
11503 ext2_filsys fs = ctx->fs;
11504 ext2_ino_t ino, next_ino;
11505 struct ext2_inode inode;
11506 struct problem_context pctx;
11507 char *block_buf;
11508
11509 if ((ino = fs->super->s_last_orphan) == 0)
11510 return 0;
11511
11512 /*
11513 * Win or lose, we won't be using the head of the orphan inode
11514 * list again.
11515 */
11516 fs->super->s_last_orphan = 0;
11517 ext2fs_mark_super_dirty(fs);
11518
11519 /*
11520 * If the filesystem contains errors, don't run the orphan
11521 * list, since the orphan list can't be trusted; and we're
11522 * going to be running a full e2fsck run anyway...
11523 */
11524 if (fs->super->s_state & EXT2_ERROR_FS)
11525 return 0;
11526
11527 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
11528 (ino > fs->super->s_inodes_count)) {
11529 clear_problem_context(&pctx);
11530 pctx.ino = ino;
11531 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
11532 return 1;
11533 }
11534
11535 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
11536 "block iterate buffer");
11537 e2fsck_read_bitmaps(ctx);
11538
11539 while (ino) {
11540 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
11541 clear_problem_context(&pctx);
11542 pctx.ino = ino;
11543 pctx.inode = &inode;
11544 pctx.str = inode.i_links_count ? _("Truncating") :
11545 _("Clearing");
11546
11547 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
11548
11549 next_ino = inode.i_dtime;
11550 if (next_ino &&
11551 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
11552 (next_ino > fs->super->s_inodes_count))) {
11553 pctx.ino = next_ino;
11554 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
11555 goto return_abort;
11556 }
11557
11558 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
11559 goto return_abort;
11560
11561 if (!inode.i_links_count) {
11562 ext2fs_inode_alloc_stats2(fs, ino, -1,
11563 LINUX_S_ISDIR(inode.i_mode));
11564 inode.i_dtime = time(0);
11565 } else {
11566 inode.i_dtime = 0;
11567 }
11568 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
11569 ino = next_ino;
11570 }
11571 ext2fs_free_mem(&block_buf);
11572 return 0;
11573return_abort:
11574 ext2fs_free_mem(&block_buf);
11575 return 1;
11576}
11577
11578/*
11579 * Check the resize inode to make sure it is sane. We check both for
11580 * the case where on-line resizing is not enabled (in which case the
11581 * resize inode should be cleared) as well as the case where on-line
11582 * resizing is enabled.
11583 */
11584static void check_resize_inode(e2fsck_t ctx)
11585{
11586 ext2_filsys fs = ctx->fs;
11587 struct ext2_inode inode;
11588 struct problem_context pctx;
11589 int i, j, gdt_off, ind_off;
11590 blk_t blk, pblk, expect;
11591 __u32 *dind_buf = 0, *ind_buf;
11592 errcode_t retval;
11593
11594 clear_problem_context(&pctx);
11595
11596 /*
11597 * If the resize inode feature isn't set, then
11598 * s_reserved_gdt_blocks must be zero.
11599 */
11600 if (!(fs->super->s_feature_compat &
11601 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
11602 if (fs->super->s_reserved_gdt_blocks) {
11603 pctx.num = fs->super->s_reserved_gdt_blocks;
11604 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
11605 &pctx)) {
11606 fs->super->s_reserved_gdt_blocks = 0;
11607 ext2fs_mark_super_dirty(fs);
11608 }
11609 }
11610 }
11611
11612 /* Read the resize inode */
11613 pctx.ino = EXT2_RESIZE_INO;
11614 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
11615 if (retval) {
11616 if (fs->super->s_feature_compat &
11617 EXT2_FEATURE_COMPAT_RESIZE_INODE)
11618 ctx->flags |= E2F_FLAG_RESIZE_INODE;
11619 return;
11620 }
11621
11622 /*
11623 * If the resize inode feature isn't set, check to make sure
11624 * the resize inode is cleared; then we're done.
11625 */
11626 if (!(fs->super->s_feature_compat &
11627 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
11628 for (i=0; i < EXT2_N_BLOCKS; i++) {
11629 if (inode.i_block[i])
11630 break;
11631 }
11632 if ((i < EXT2_N_BLOCKS) &&
11633 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
11634 memset(&inode, 0, sizeof(inode));
11635 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
11636 "clear_resize");
11637 }
11638 return;
11639 }
11640
11641 /*
11642 * The resize inode feature is enabled; check to make sure the
11643 * only block in use is the double indirect block
11644 */
11645 blk = inode.i_block[EXT2_DIND_BLOCK];
11646 for (i=0; i < EXT2_N_BLOCKS; i++) {
11647 if (i != EXT2_DIND_BLOCK && inode.i_block[i])
11648 break;
11649 }
11650 if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
11651 !(inode.i_mode & LINUX_S_IFREG) ||
11652 (blk < fs->super->s_first_data_block ||
11653 blk >= fs->super->s_blocks_count)) {
11654 resize_inode_invalid:
11655 if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
11656 memset(&inode, 0, sizeof(inode));
11657 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
11658 "clear_resize");
11659 ctx->flags |= E2F_FLAG_RESIZE_INODE;
11660 }
11661 if (!(ctx->options & E2F_OPT_READONLY)) {
11662 fs->super->s_state &= ~EXT2_VALID_FS;
11663 ext2fs_mark_super_dirty(fs);
11664 }
11665 goto cleanup;
11666 }
11667 dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
11668 "resize dind buffer");
11669 ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
11670
11671 retval = ext2fs_read_ind_block(fs, blk, dind_buf);
11672 if (retval)
11673 goto resize_inode_invalid;
11674
11675 gdt_off = fs->desc_blocks;
11676 pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
11677 for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
11678 i++, gdt_off++, pblk++) {
11679 gdt_off %= fs->blocksize/4;
11680 if (dind_buf[gdt_off] != pblk)
11681 goto resize_inode_invalid;
11682 retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
11683 if (retval)
11684 goto resize_inode_invalid;
11685 ind_off = 0;
11686 for (j = 1; j < fs->group_desc_count; j++) {
11687 if (!ext2fs_bg_has_super(fs, j))
11688 continue;
11689 expect = pblk + (j * fs->super->s_blocks_per_group);
11690 if (ind_buf[ind_off] != expect)
11691 goto resize_inode_invalid;
11692 ind_off++;
11693 }
11694 }
11695
11696cleanup:
11697 ext2fs_free_mem(&dind_buf);
11698
11699 }
11700
11701static void check_super_block(e2fsck_t ctx)
11702{
11703 ext2_filsys fs = ctx->fs;
11704 blk_t first_block, last_block;
11705 struct ext2_super_block *sb = fs->super;
11706 struct ext2_group_desc *gd;
11707 blk_t blocks_per_group = fs->super->s_blocks_per_group;
11708 blk_t bpg_max;
11709 int inodes_per_block;
11710 int ipg_max;
11711 int inode_size;
11712 dgrp_t i;
11713 blk_t should_be;
11714 struct problem_context pctx;
11715 __u32 free_blocks = 0, free_inodes = 0;
11716
11717 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
11718 ipg_max = inodes_per_block * (blocks_per_group - 4);
11719 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
11720 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
11721 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
11722 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
11723 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
11724
11725 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
11726 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
11727 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
11728 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
11729 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
11730 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
11731
11732 clear_problem_context(&pctx);
11733
11734 /*
11735 * Verify the super block constants...
11736 */
11737 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
11738 MIN_CHECK, 1, 0);
11739 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
11740 MIN_CHECK, 1, 0);
11741 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
11742 MAX_CHECK, 0, sb->s_blocks_count);
11743 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
11744 MIN_CHECK | MAX_CHECK, 0,
11745 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
11746 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
11747 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
11748 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
11749 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
11750 bpg_max);
11751 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
11752 MIN_CHECK | MAX_CHECK, 8, bpg_max);
11753 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
11754 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
11755 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
11756 MAX_CHECK, 0, sb->s_blocks_count / 2);
11757 check_super_value(ctx, "reserved_gdt_blocks",
11758 sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
11759 fs->blocksize/4);
11760 inode_size = EXT2_INODE_SIZE(sb);
11761 check_super_value(ctx, "inode_size",
11762 inode_size, MIN_CHECK | MAX_CHECK,
11763 EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
11764 if (inode_size & (inode_size - 1)) {
11765 pctx.num = inode_size;
11766 pctx.str = "inode_size";
11767 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
11768 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
11769 return;
11770 }
11771
11772 if (!ctx->num_blocks) {
11773 pctx.errcode = e2fsck_get_device_size(ctx);
11774 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
11775 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
11776 ctx->flags |= E2F_FLAG_ABORT;
11777 return;
11778 }
11779 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
11780 (ctx->num_blocks < sb->s_blocks_count)) {
11781 pctx.blk = sb->s_blocks_count;
11782 pctx.blk2 = ctx->num_blocks;
11783 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
11784 ctx->flags |= E2F_FLAG_ABORT;
11785 return;
11786 }
11787 }
11788 }
11789
11790 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
11791 pctx.blk = EXT2_BLOCK_SIZE(sb);
11792 pctx.blk2 = EXT2_FRAG_SIZE(sb);
11793 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
11794 ctx->flags |= E2F_FLAG_ABORT;
11795 return;
11796 }
11797
11798 should_be = sb->s_frags_per_group >>
11799 (sb->s_log_block_size - sb->s_log_frag_size);
11800 if (sb->s_blocks_per_group != should_be) {
11801 pctx.blk = sb->s_blocks_per_group;
11802 pctx.blk2 = should_be;
11803 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
11804 ctx->flags |= E2F_FLAG_ABORT;
11805 return;
11806 }
11807
11808 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
11809 if (sb->s_first_data_block != should_be) {
11810 pctx.blk = sb->s_first_data_block;
11811 pctx.blk2 = should_be;
11812 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
11813 ctx->flags |= E2F_FLAG_ABORT;
11814 return;
11815 }
11816
11817 should_be = sb->s_inodes_per_group * fs->group_desc_count;
11818 if (sb->s_inodes_count != should_be) {
11819 pctx.ino = sb->s_inodes_count;
11820 pctx.ino2 = should_be;
11821 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
11822 sb->s_inodes_count = should_be;
11823 ext2fs_mark_super_dirty(fs);
11824 }
11825 }
11826
11827 /*
11828 * Verify the group descriptors....
11829 */
11830 first_block = sb->s_first_data_block;
11831 last_block = first_block + blocks_per_group;
11832
11833 for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
11834 pctx.group = i;
11835
11836 if (i == fs->group_desc_count - 1)
11837 last_block = sb->s_blocks_count;
11838 if ((gd->bg_block_bitmap < first_block) ||
11839 (gd->bg_block_bitmap >= last_block)) {
11840 pctx.blk = gd->bg_block_bitmap;
11841 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
11842 gd->bg_block_bitmap = 0;
11843 }
11844 if (gd->bg_block_bitmap == 0) {
11845 ctx->invalid_block_bitmap_flag[i]++;
11846 ctx->invalid_bitmaps++;
11847 }
11848 if ((gd->bg_inode_bitmap < first_block) ||
11849 (gd->bg_inode_bitmap >= last_block)) {
11850 pctx.blk = gd->bg_inode_bitmap;
11851 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
11852 gd->bg_inode_bitmap = 0;
11853 }
11854 if (gd->bg_inode_bitmap == 0) {
11855 ctx->invalid_inode_bitmap_flag[i]++;
11856 ctx->invalid_bitmaps++;
11857 }
11858 if ((gd->bg_inode_table < first_block) ||
11859 ((gd->bg_inode_table +
11860 fs->inode_blocks_per_group - 1) >= last_block)) {
11861 pctx.blk = gd->bg_inode_table;
11862 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
11863 gd->bg_inode_table = 0;
11864 }
11865 if (gd->bg_inode_table == 0) {
11866 ctx->invalid_inode_table_flag[i]++;
11867 ctx->invalid_bitmaps++;
11868 }
11869 free_blocks += gd->bg_free_blocks_count;
11870 free_inodes += gd->bg_free_inodes_count;
11871 first_block += sb->s_blocks_per_group;
11872 last_block += sb->s_blocks_per_group;
11873
11874 if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
11875 (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
11876 (gd->bg_used_dirs_count > sb->s_inodes_per_group))
11877 ext2fs_unmark_valid(fs);
11878
11879 }
11880
11881 /*
11882 * Update the global counts from the block group counts. This
11883 * is needed for an experimental patch which eliminates
11884 * locking the entire filesystem when allocating blocks or
11885 * inodes; if the filesystem is not unmounted cleanly, the
11886 * global counts may not be accurate.
11887 */
11888 if ((free_blocks != sb->s_free_blocks_count) ||
11889 (free_inodes != sb->s_free_inodes_count)) {
11890 if (ctx->options & E2F_OPT_READONLY)
11891 ext2fs_unmark_valid(fs);
11892 else {
11893 sb->s_free_blocks_count = free_blocks;
11894 sb->s_free_inodes_count = free_inodes;
11895 ext2fs_mark_super_dirty(fs);
11896 }
11897 }
11898
11899 if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
11900 (sb->s_free_inodes_count > sb->s_inodes_count))
11901 ext2fs_unmark_valid(fs);
11902
11903
11904 /*
11905 * If we have invalid bitmaps, set the error state of the
11906 * filesystem.
11907 */
11908 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
11909 sb->s_state &= ~EXT2_VALID_FS;
11910 ext2fs_mark_super_dirty(fs);
11911 }
11912
11913 clear_problem_context(&pctx);
11914
11915 /*
11916 * If the UUID field isn't assigned, assign it.
11917 */
11918 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
11919 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
11920 uuid_generate(sb->s_uuid);
11921 ext2fs_mark_super_dirty(fs);
11922 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
11923 }
11924 }
11925
11926 /* FIXME - HURD support?
11927 * For the Hurd, check to see if the filetype option is set,
11928 * since it doesn't support it.
11929 */
11930 if (!(ctx->options & E2F_OPT_READONLY) &&
11931 fs->super->s_creator_os == EXT2_OS_HURD &&
11932 (fs->super->s_feature_incompat &
11933 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
11934 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
11935 fs->super->s_feature_incompat &=
11936 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
11937 ext2fs_mark_super_dirty(fs);
11938
11939 }
11940 }
11941
11942 /*
11943 * If we have any of the compatibility flags set, we need to have a
11944 * revision 1 filesystem. Most kernels will not check the flags on
11945 * a rev 0 filesystem and we may have corruption issues because of
11946 * the incompatible changes to the filesystem.
11947 */
11948 if (!(ctx->options & E2F_OPT_READONLY) &&
11949 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
11950 (fs->super->s_feature_compat ||
11951 fs->super->s_feature_ro_compat ||
11952 fs->super->s_feature_incompat) &&
11953 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
11954 ext2fs_update_dynamic_rev(fs);
11955 ext2fs_mark_super_dirty(fs);
11956 }
11957
11958 check_resize_inode(ctx);
11959
11960 /*
11961 * Clean up any orphan inodes, if present.
11962 */
11963 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
11964 fs->super->s_state &= ~EXT2_VALID_FS;
11965 ext2fs_mark_super_dirty(fs);
11966 }
11967
11968 /*
11969 * Move the ext3 journal file, if necessary.
11970 */
11971 e2fsck_move_ext3_journal(ctx);
11972 return;
11973}
11974
11975/*
11976 * swapfs.c --- byte-swap an ext2 filesystem
11977 */
11978
11979#ifdef ENABLE_SWAPFS
11980
11981struct swap_block_struct {
11982 ext2_ino_t ino;
11983 int isdir;
11984 errcode_t errcode;
11985 char *dir_buf;
11986 struct ext2_inode *inode;
11987};
11988
11989/*
11990 * This is a helper function for block_iterate. We mark all of the
11991 * indirect and direct blocks as changed, so that block_iterate will
11992 * write them out.
11993 */
11994static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
11995 void *priv_data)
11996{
11997 errcode_t retval;
11998
11999 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
12000
12001 if (sb->isdir && (blockcnt >= 0) && *block_nr) {
12002 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
12003 if (retval) {
12004 sb->errcode = retval;
12005 return BLOCK_ABORT;
12006 }
12007 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
12008 if (retval) {
12009 sb->errcode = retval;
12010 return BLOCK_ABORT;
12011 }
12012 }
12013 if (blockcnt >= 0) {
12014 if (blockcnt < EXT2_NDIR_BLOCKS)
12015 return 0;
12016 return BLOCK_CHANGED;
12017 }
12018 if (blockcnt == BLOCK_COUNT_IND) {
12019 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
12020 return 0;
12021 return BLOCK_CHANGED;
12022 }
12023 if (blockcnt == BLOCK_COUNT_DIND) {
12024 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
12025 return 0;
12026 return BLOCK_CHANGED;
12027 }
12028 if (blockcnt == BLOCK_COUNT_TIND) {
12029 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
12030 return 0;
12031 return BLOCK_CHANGED;
12032 }
12033 return BLOCK_CHANGED;
12034}
12035
12036/*
12037 * This function is responsible for byte-swapping all of the indirect,
12038 * block pointers. It is also responsible for byte-swapping directories.
12039 */
12040static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
12041 struct ext2_inode *inode)
12042{
12043 errcode_t retval;
12044 struct swap_block_struct sb;
12045
12046 sb.ino = ino;
12047 sb.inode = inode;
12048 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
12049 sb.errcode = 0;
12050 sb.isdir = 0;
12051 if (LINUX_S_ISDIR(inode->i_mode))
12052 sb.isdir = 1;
12053
12054 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
12055 swap_block, &sb);
12056 if (retval) {
12057 bb_error_msg(_("while calling ext2fs_block_iterate"));
12058 ctx->flags |= E2F_FLAG_ABORT;
12059 return;
12060 }
12061 if (sb.errcode) {
12062 bb_error_msg(_("while calling iterator function"));
12063 ctx->flags |= E2F_FLAG_ABORT;
12064 return;
12065 }
12066}
12067
12068static void swap_inodes(e2fsck_t ctx)
12069{
12070 ext2_filsys fs = ctx->fs;
12071 dgrp_t group;
12072 unsigned int i;
12073 ext2_ino_t ino = 1;
12074 char *buf, *block_buf;
12075 errcode_t retval;
12076 struct ext2_inode * inode;
12077
12078 e2fsck_use_inode_shortcuts(ctx, 1);
12079
12080 retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
12081 &buf);
12082 if (retval) {
12083 bb_error_msg(_("while allocating inode buffer"));
12084 ctx->flags |= E2F_FLAG_ABORT;
12085 return;
12086 }
12087 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
12088 "block interate buffer");
12089 for (group = 0; group < fs->group_desc_count; group++) {
12090 retval = io_channel_read_blk(fs->io,
12091 fs->group_desc[group].bg_inode_table,
12092 fs->inode_blocks_per_group, buf);
12093 if (retval) {
12094 bb_error_msg(_("while reading inode table (group %d)"),
12095 group);
12096 ctx->flags |= E2F_FLAG_ABORT;
12097 return;
12098 }
12099 inode = (struct ext2_inode *) buf;
12100 for (i=0; i < fs->super->s_inodes_per_group;
12101 i++, ino++, inode++) {
12102 ctx->stashed_ino = ino;
12103 ctx->stashed_inode = inode;
12104
12105 if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
12106 ext2fs_swap_inode(fs, inode, inode, 0);
12107
12108 /*
12109 * Skip deleted files.
12110 */
12111 if (inode->i_links_count == 0)
12112 continue;
12113
12114 if (LINUX_S_ISDIR(inode->i_mode) ||
12115 ((inode->i_block[EXT2_IND_BLOCK] ||
12116 inode->i_block[EXT2_DIND_BLOCK] ||
12117 inode->i_block[EXT2_TIND_BLOCK]) &&
12118 ext2fs_inode_has_valid_blocks(inode)))
12119 swap_inode_blocks(ctx, ino, block_buf, inode);
12120
12121 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
12122 return;
12123
12124 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
12125 ext2fs_swap_inode(fs, inode, inode, 1);
12126 }
12127 retval = io_channel_write_blk(fs->io,
12128 fs->group_desc[group].bg_inode_table,
12129 fs->inode_blocks_per_group, buf);
12130 if (retval) {
12131 bb_error_msg(_("while writing inode table (group %d)"),
12132 group);
12133 ctx->flags |= E2F_FLAG_ABORT;
12134 return;
12135 }
12136 }
12137 ext2fs_free_mem(&buf);
12138 ext2fs_free_mem(&block_buf);
12139 e2fsck_use_inode_shortcuts(ctx, 0);
12140 ext2fs_flush_icache(fs);
12141}
12142
12143#if defined(__powerpc__) && BB_BIG_ENDIAN
12144/*
12145 * On the PowerPC, the big-endian variant of the ext2 filesystem
12146 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
12147 * of each word. Thus a bitmap with only bit 0 set would be, as
12148 * a string of bytes, 00 00 00 01 00 ...
12149 * To cope with this, we byte-reverse each word of a bitmap if
12150 * we have a big-endian filesystem, that is, if we are *not*
12151 * byte-swapping other word-sized numbers.
12152 */
12153#define EXT2_BIG_ENDIAN_BITMAPS
12154#endif
12155
12156#ifdef EXT2_BIG_ENDIAN_BITMAPS
12157static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
12158{
12159 __u32 *p = (__u32 *) bmap->bitmap;
12160 int n, nbytes = (bmap->end - bmap->start + 7) / 8;
12161
12162 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
12163 *p = ext2fs_swab32(*p);
12164}
12165#endif
12166
12167
12168#ifdef ENABLE_SWAPFS
12169static void swap_filesys(e2fsck_t ctx)
12170{
12171 ext2_filsys fs = ctx->fs;
12172 if (!(ctx->options & E2F_OPT_PREEN))
12173 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
12174
12175 /* Byte swap */
12176
12177 if (fs->super->s_mnt_count) {
12178 fprintf(stderr, _("%s: the filesystem must be freshly "
12179 "checked using fsck\n"
12180 "and not mounted before trying to "
12181 "byte-swap it.\n"), ctx->device_name);
12182 ctx->flags |= E2F_FLAG_ABORT;
12183 return;
12184 }
12185 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
12186 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
12187 EXT2_FLAG_SWAP_BYTES_WRITE);
12188 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
12189 } else {
12190 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
12191 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
12192 }
12193 swap_inodes(ctx);
12194 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
12195 return;
12196 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
12197 fs->flags |= EXT2_FLAG_SWAP_BYTES;
12198 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
12199 EXT2_FLAG_SWAP_BYTES_WRITE);
12200
12201#ifdef EXT2_BIG_ENDIAN_BITMAPS
12202 e2fsck_read_bitmaps(ctx);
12203 ext2fs_swap_bitmap(fs->inode_map);
12204 ext2fs_swap_bitmap(fs->block_map);
12205 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
12206#endif
12207 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
12208 ext2fs_flush(fs);
12209 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
12210}
12211#endif /* ENABLE_SWAPFS */
12212
12213#endif
12214
12215/*
12216 * util.c --- miscellaneous utilities
12217 */
12218
12219
12220void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
12221 const char *description)
12222{
12223 void *ret;
12224 char buf[256];
12225
12226 ret = malloc(size);
12227 if (!ret) {
12228 sprintf(buf, "Can't allocate %s\n", description);
12229 bb_error_msg_and_die(buf);
12230 }
12231 memset(ret, 0, size);
12232 return ret;
12233}
12234
12235static char *string_copy(const char *str, int len)
12236{
12237 char *ret;
12238
12239 if (!str)
12240 return NULL;
12241 if (!len)
12242 len = strlen(str);
12243 ret = malloc(len+1);
12244 if (ret) {
12245 strncpy(ret, str, len);
12246 ret[len] = 0;
12247 }
12248 return ret;
12249}
12250
12251#ifndef HAVE_CONIO_H
12252static int read_a_char(void)
12253{
12254 char c;
12255 int r;
12256 int fail = 0;
12257
12258 while(1) {
12259 if (e2fsck_global_ctx &&
12260 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
12261 return 3;
12262 }
12263 r = read(0, &c, 1);
12264 if (r == 1)
12265 return c;
12266 if (fail++ > 100)
12267 break;
12268 }
12269 return EOF;
12270}
12271#endif
12272
12273static int ask_yn(const char * string, int def)
12274{
12275 int c;
12276 const char *defstr;
12277 static const char short_yes[] = "yY";
12278 static const char short_no[] = "nN";
12279
12280#ifdef HAVE_TERMIOS_H
12281 struct termios termios, tmp;
12282
12283 tcgetattr (0, &termios);
12284 tmp = termios;
12285 tmp.c_lflag &= ~(ICANON | ECHO);
12286 tmp.c_cc[VMIN] = 1;
12287 tmp.c_cc[VTIME] = 0;
12288 tcsetattr (0, TCSANOW, &tmp);
12289#endif
12290
12291 if (def == 1)
12292 defstr = "<y>";
12293 else if (def == 0)
12294 defstr = "<n>";
12295 else
12296 defstr = " (y/n)";
12297 printf("%s%s? ", string, defstr);
12298 while (1) {
12299 fflush (stdout);
12300 if ((c = read_a_char()) == EOF)
12301 break;
12302 if (c == 3) {
12303#ifdef HAVE_TERMIOS_H
12304 tcsetattr (0, TCSANOW, &termios);
12305#endif
12306 if (e2fsck_global_ctx &&
12307 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
12308 puts("\n");
12309 longjmp(e2fsck_global_ctx->abort_loc, 1);
12310 }
12311 puts(_("cancelled!\n"));
12312 return 0;
12313 }
12314 if (strchr(short_yes, (char) c)) {
12315 def = 1;
12316 break;
12317 }
12318 else if (strchr(short_no, (char) c)) {
12319 def = 0;
12320 break;
12321 }
12322 else if ((c == ' ' || c == '\n') && (def != -1))
12323 break;
12324 }
12325 if (def)
12326 puts("yes\n");
12327 else
12328 puts ("no\n");
12329#ifdef HAVE_TERMIOS_H
12330 tcsetattr (0, TCSANOW, &termios);
12331#endif
12332 return def;
12333}
12334
12335int ask (e2fsck_t ctx, const char * string, int def)
12336{
12337 if (ctx->options & E2F_OPT_NO) {
12338 printf(_("%s? no\n\n"), string);
12339 return 0;
12340 }
12341 if (ctx->options & E2F_OPT_YES) {
12342 printf(_("%s? yes\n\n"), string);
12343 return 1;
12344 }
12345 if (ctx->options & E2F_OPT_PREEN) {
12346 printf("%s? %s\n\n", string, def ? _("yes") : _("no"));
12347 return def;
12348 }
12349 return ask_yn(string, def);
12350}
12351
12352void e2fsck_read_bitmaps(e2fsck_t ctx)
12353{
12354 ext2_filsys fs = ctx->fs;
12355 errcode_t retval;
12356
12357 if (ctx->invalid_bitmaps) {
12358 bb_error_msg(_("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
12359 ctx->device_name);
12360 bb_error_msg_and_die(0);
12361 }
12362
12363 ehandler_operation(_("reading inode and block bitmaps"));
12364 retval = ext2fs_read_bitmaps(fs);
12365 ehandler_operation(0);
12366 if (retval) {
12367 bb_error_msg(_("while retrying to read bitmaps for %s"),
12368 ctx->device_name);
12369 bb_error_msg_and_die(0);
12370 }
12371}
12372
12373static void e2fsck_write_bitmaps(e2fsck_t ctx)
12374{
12375 ext2_filsys fs = ctx->fs;
12376 errcode_t retval;
12377
12378 if (ext2fs_test_bb_dirty(fs)) {
12379 ehandler_operation(_("writing block bitmaps"));
12380 retval = ext2fs_write_block_bitmap(fs);
12381 ehandler_operation(0);
12382 if (retval) {
12383 bb_error_msg(_("while retrying to write block bitmaps for %s"),
12384 ctx->device_name);
12385 bb_error_msg_and_die(0);
12386 }
12387 }
12388
12389 if (ext2fs_test_ib_dirty(fs)) {
12390 ehandler_operation(_("writing inode bitmaps"));
12391 retval = ext2fs_write_inode_bitmap(fs);
12392 ehandler_operation(0);
12393 if (retval) {
12394 bb_error_msg(_("while retrying to write inode bitmaps for %s"),
12395 ctx->device_name);
12396 bb_error_msg_and_die(0);
12397 }
12398 }
12399}
12400
12401void preenhalt(e2fsck_t ctx)
12402{
12403 ext2_filsys fs = ctx->fs;
12404
12405 if (!(ctx->options & E2F_OPT_PREEN))
12406 return;
12407 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
12408 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
12409 ctx->device_name);
12410 if (fs != NULL) {
12411 fs->super->s_state |= EXT2_ERROR_FS;
12412 ext2fs_mark_super_dirty(fs);
12413 ext2fs_close(fs);
12414 }
12415 exit(EXIT_UNCORRECTED);
12416}
12417
12418void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
12419 struct ext2_inode * inode, const char *proc)
12420{
12421 int retval;
12422
12423 retval = ext2fs_read_inode(ctx->fs, ino, inode);
12424 if (retval) {
12425 bb_error_msg(_("while reading inode %ld in %s"), ino, proc);
12426 bb_error_msg_and_die(0);
12427 }
12428}
12429
12430extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
12431 struct ext2_inode * inode, int bufsize,
12432 const char *proc)
12433{
12434 int retval;
12435
12436 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
12437 if (retval) {
12438 bb_error_msg(_("while writing inode %ld in %s"), ino, proc);
12439 bb_error_msg_and_die(0);
12440 }
12441}
12442
12443extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
12444 struct ext2_inode * inode, const char *proc)
12445{
12446 int retval;
12447
12448 retval = ext2fs_write_inode(ctx->fs, ino, inode);
12449 if (retval) {
12450 bb_error_msg(_("while writing inode %ld in %s"), ino, proc);
12451 bb_error_msg_and_die(0);
12452 }
12453}
12454
12455blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
12456 io_manager manager)
12457{
12458 struct ext2_super_block *sb;
12459 io_channel io = NULL;
12460 void *buf = NULL;
12461 int blocksize;
12462 blk_t superblock, ret_sb = 8193;
12463
12464 if (fs && fs->super) {
12465 ret_sb = (fs->super->s_blocks_per_group +
12466 fs->super->s_first_data_block);
12467 if (ctx) {
12468 ctx->superblock = ret_sb;
12469 ctx->blocksize = fs->blocksize;
12470 }
12471 return ret_sb;
12472 }
12473
12474 if (ctx) {
12475 if (ctx->blocksize) {
12476 ret_sb = ctx->blocksize * 8;
12477 if (ctx->blocksize == 1024)
12478 ret_sb++;
12479 ctx->superblock = ret_sb;
12480 return ret_sb;
12481 }
12482 ctx->superblock = ret_sb;
12483 ctx->blocksize = 1024;
12484 }
12485
12486 if (!name || !manager)
12487 goto cleanup;
12488
12489 if (manager->open(name, 0, &io) != 0)
12490 goto cleanup;
12491
12492 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
12493 goto cleanup;
12494 sb = (struct ext2_super_block *) buf;
12495
12496 for (blocksize = EXT2_MIN_BLOCK_SIZE;
12497 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
12498 superblock = blocksize*8;
12499 if (blocksize == 1024)
12500 superblock++;
12501 io_channel_set_blksize(io, blocksize);
12502 if (io_channel_read_blk(io, superblock,
12503 -SUPERBLOCK_SIZE, buf))
12504 continue;
12505#if BB_BIG_ENDIAN
12506 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
12507 ext2fs_swap_super(sb);
12508#endif
12509 if (sb->s_magic == EXT2_SUPER_MAGIC) {
12510 ret_sb = superblock;
12511 if (ctx) {
12512 ctx->superblock = superblock;
12513 ctx->blocksize = blocksize;
12514 }
12515 break;
12516 }
12517 }
12518
12519cleanup:
12520 if (io)
12521 io_channel_close(io);
12522 ext2fs_free_mem(&buf);
12523 return ret_sb;
12524}
12525
12526
12527/*
12528 * This function runs through the e2fsck passes and calls them all,
12529 * returning restart, abort, or cancel as necessary...
12530 */
12531typedef void (*pass_t)(e2fsck_t ctx);
12532
12533static const pass_t e2fsck_passes[] = {
12534 e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
12535 e2fsck_pass5, 0 };
12536
12537#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
12538
12539static int e2fsck_run(e2fsck_t ctx)
12540{
12541 int i;
12542 pass_t e2fsck_pass;
12543
12544 if (setjmp(ctx->abort_loc)) {
12545 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
12546 return (ctx->flags & E2F_FLAG_RUN_RETURN);
12547 }
12548 ctx->flags |= E2F_FLAG_SETJMP_OK;
12549
12550 for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
12551 if (ctx->flags & E2F_FLAG_RUN_RETURN)
12552 break;
12553 e2fsck_pass(ctx);
12554 if (ctx->progress)
12555 (void) (ctx->progress)(ctx, 0, 0, 0);
12556 }
12557 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
12558
12559 if (ctx->flags & E2F_FLAG_RUN_RETURN)
12560 return (ctx->flags & E2F_FLAG_RUN_RETURN);
12561 return 0;
12562}
12563
12564
12565/*
12566 * unix.c - The unix-specific code for e2fsck
12567 */
12568
12569
12570/* Command line options */
12571static int swapfs;
12572#ifdef ENABLE_SWAPFS
12573static int normalize_swapfs;
12574#endif
12575static int cflag; /* check disk */
12576static int show_version_only;
12577static int verbose;
12578
12579#define P_E2(singular, plural, n) n, ((n) == 1 ? singular : plural)
12580
12581static void show_stats(e2fsck_t ctx)
12582{
12583 ext2_filsys fs = ctx->fs;
12584 int inodes, inodes_used, blocks, blocks_used;
12585 int dir_links;
12586 int num_files, num_links;
12587 int frag_percent;
12588
12589 dir_links = 2 * ctx->fs_directory_count - 1;
12590 num_files = ctx->fs_total_count - dir_links;
12591 num_links = ctx->fs_links_count - dir_links;
12592 inodes = fs->super->s_inodes_count;
12593 inodes_used = (fs->super->s_inodes_count -
12594 fs->super->s_free_inodes_count);
12595 blocks = fs->super->s_blocks_count;
12596 blocks_used = (fs->super->s_blocks_count -
12597 fs->super->s_free_blocks_count);
12598
12599 frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
12600 frag_percent = (frag_percent + 5) / 10;
12601
12602 if (!verbose) {
12603 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
12604 ctx->device_name, inodes_used, inodes,
12605 frag_percent / 10, frag_percent % 10,
12606 blocks_used, blocks);
12607 return;
12608 }
12609 printf("\n%8d inode%s used (%d%%)\n", P_E2("", "s", inodes_used),
12610 100 * inodes_used / inodes);
12611 printf("%8d non-contiguous inode%s (%0d.%d%%)\n",
12612 P_E2("", "s", ctx->fs_fragmented),
12613 frag_percent / 10, frag_percent % 10);
12614 printf(_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"),
12615 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
12616 printf("%8d block%s used (%d%%)\n", P_E2("", "s", blocks_used),
12617 (int) ((long long) 100 * blocks_used / blocks));
12618 printf("%8d large file%s\n", P_E2("", "s", ctx->large_files));
12619 printf("\n%8d regular file%s\n", P_E2("", "s", ctx->fs_regular_count));
12620 printf("%8d director%s\n", P_E2("y", "ies", ctx->fs_directory_count));
12621 printf("%8d character device file%s\n", P_E2("", "s", ctx->fs_chardev_count));
12622 printf("%8d block device file%s\n", P_E2("", "s", ctx->fs_blockdev_count));
12623 printf("%8d fifo%s\n", P_E2("", "s", ctx->fs_fifo_count));
12624 printf("%8d link%s\n", P_E2("", "s", ctx->fs_links_count - dir_links));
12625 printf("%8d symbolic link%s", P_E2("", "s", ctx->fs_symlinks_count));
12626 printf(" (%d fast symbolic link%s)\n", P_E2("", "s", ctx->fs_fast_symlinks_count));
12627 printf("%8d socket%s--------\n\n", P_E2("", "s", ctx->fs_sockets_count));
12628 printf("%8d file%s\n", P_E2("", "s", ctx->fs_total_count - dir_links));
12629}
12630
12631static void check_mount(e2fsck_t ctx)
12632{
12633 errcode_t retval;
12634 int cont;
12635
12636 retval = ext2fs_check_if_mounted(ctx->filesystem_name,
12637 &ctx->mount_flags);
12638 if (retval) {
12639 bb_error_msg(_("while determining whether %s is mounted."),
12640 ctx->filesystem_name);
12641 return;
12642 }
12643
12644 /*
12645 * If the filesystem isn't mounted, or it's the root filesystem
12646 * and it's mounted read-only, then everything's fine.
12647 */
12648 if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) ||
12649 ((ctx->mount_flags & EXT2_MF_ISROOT) &&
12650 (ctx->mount_flags & EXT2_MF_READONLY)))
12651 return;
12652
12653 if (ctx->options & E2F_OPT_READONLY) {
12654 printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name);
12655 return;
12656 }
12657
12658 printf(_("%s is mounted. "), ctx->filesystem_name);
12659 if (!ctx->interactive)
12660 bb_error_msg_and_die(_("Cannot continue, aborting."));
12661 printf(_("\n\n\007\007\007\007WARNING!!! "
12662 "Running e2fsck on a mounted filesystem may cause\n"
12663 "SEVERE filesystem damage.\007\007\007\n\n"));
12664 cont = ask_yn(_("Do you really want to continue"), -1);
12665 if (!cont) {
12666 printf(_("check aborted.\n"));
12667 exit (0);
12668 }
12669 return;
12670}
12671
12672static int is_on_batt(void)
12673{
12674 FILE *f;
12675 DIR *d;
12676 char tmp[80], tmp2[80], fname[80];
12677 unsigned int acflag;
12678 struct dirent* de;
12679
12680 f = fopen("/proc/apm", "r");
12681 if (f) {
12682 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
12683 acflag = 1;
12684 fclose(f);
12685 return (acflag != 1);
12686 }
12687 d = opendir("/proc/acpi/ac_adapter");
12688 if (d) {
12689 while ((de=readdir(d)) != NULL) {
12690 if (!strncmp(".", de->d_name, 1))
12691 continue;
12692 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state",
12693 de->d_name);
12694 f = fopen(fname, "r");
12695 if (!f)
12696 continue;
12697 if (fscanf(f, "%s %s", tmp2, tmp) != 2)
12698 tmp[0] = 0;
12699 fclose(f);
12700 if (strncmp(tmp, "off-line", 8) == 0) {
12701 closedir(d);
12702 return 1;
12703 }
12704 }
12705 closedir(d);
12706 }
12707 return 0;
12708}
12709
12710/*
12711 * This routine checks to see if a filesystem can be skipped; if so,
12712 * it will exit with EXIT_OK. Under some conditions it will print a
12713 * message explaining why a check is being forced.
12714 */
12715static void check_if_skip(e2fsck_t ctx)
12716{
12717 ext2_filsys fs = ctx->fs;
12718 const char *reason = NULL;
12719 unsigned int reason_arg = 0;
12720 long next_check;
12721 int batt = is_on_batt();
12722 time_t now = time(0);
12723
12724 if ((ctx->options & E2F_OPT_FORCE) || cflag || swapfs)
12725 return;
12726
12727 if ((fs->super->s_state & EXT2_ERROR_FS) ||
12728 !ext2fs_test_valid(fs))
12729 reason = _(" contains a file system with errors");
12730 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
12731 reason = _(" was not cleanly unmounted");
12732 else if ((fs->super->s_max_mnt_count > 0) &&
12733 (fs->super->s_mnt_count >=
12734 (unsigned) fs->super->s_max_mnt_count)) {
12735 reason = _(" has been mounted %u times without being checked");
12736 reason_arg = fs->super->s_mnt_count;
12737 if (batt && (fs->super->s_mnt_count <
12738 (unsigned) fs->super->s_max_mnt_count*2))
12739 reason = 0;
12740 } else if (fs->super->s_checkinterval &&
12741 ((now - fs->super->s_lastcheck) >=
12742 fs->super->s_checkinterval)) {
12743 reason = _(" has gone %u days without being checked");
12744 reason_arg = (now - fs->super->s_lastcheck)/(3600*24);
12745 if (batt && ((now - fs->super->s_lastcheck) <
12746 fs->super->s_checkinterval*2))
12747 reason = 0;
12748 }
12749 if (reason) {
12750 fputs(ctx->device_name, stdout);
12751 printf(reason, reason_arg);
12752 fputs(_(", check forced.\n"), stdout);
12753 return;
12754 }
12755 printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name,
12756 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
12757 fs->super->s_inodes_count,
12758 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
12759 fs->super->s_blocks_count);
12760 next_check = 100000;
12761 if (fs->super->s_max_mnt_count > 0) {
12762 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count;
12763 if (next_check <= 0)
12764 next_check = 1;
12765 }
12766 if (fs->super->s_checkinterval &&
12767 ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval))
12768 next_check = 1;
12769 if (next_check <= 5) {
12770 if (next_check == 1)
12771 fputs(_(" (check after next mount)"), stdout);
12772 else
12773 printf(_(" (check in %ld mounts)"), next_check);
12774 }
12775 fputc('\n', stdout);
12776 ext2fs_close(fs);
12777 ctx->fs = NULL;
12778 e2fsck_free_context(ctx);
12779 exit(EXIT_OK);
12780}
12781
12782/*
12783 * For completion notice
12784 */
12785struct percent_tbl {
12786 int max_pass;
12787 int table[32];
12788};
12789static const struct percent_tbl e2fsck_tbl = {
12790 5, { 0, 70, 90, 92, 95, 100 }
12791};
12792
12793static char bar[128], spaces[128];
12794
12795static float calc_percent(const struct percent_tbl *tbl, int pass, int curr,
12796 int max)
12797{
12798 float percent;
12799
12800 if (pass <= 0)
12801 return 0.0;
12802 if (pass > tbl->max_pass || max == 0)
12803 return 100.0;
12804 percent = ((float) curr) / ((float) max);
12805 return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
12806 + tbl->table[pass-1]);
12807}
12808
12809void e2fsck_clear_progbar(e2fsck_t ctx)
12810{
12811 if (!(ctx->flags & E2F_FLAG_PROG_BAR))
12812 return;
12813
12814 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80),
12815 ctx->stop_meta);
12816 fflush(stdout);
12817 ctx->flags &= ~E2F_FLAG_PROG_BAR;
12818}
12819
12820int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
12821 unsigned int dpynum)
12822{
12823 static const char spinner[] = "\\|/-";
12824 int i;
12825 unsigned int tick;
12826 struct timeval tv;
12827 int dpywidth;
12828 int fixed_percent;
12829
12830 if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
12831 return 0;
12832
12833 /*
12834 * Calculate the new progress position. If the
12835 * percentage hasn't changed, then we skip out right
12836 * away.
12837 */
12838 fixed_percent = (int) ((10 * percent) + 0.5);
12839 if (ctx->progress_last_percent == fixed_percent)
12840 return 0;
12841 ctx->progress_last_percent = fixed_percent;
12842
12843 /*
12844 * If we've already updated the spinner once within
12845 * the last 1/8th of a second, no point doing it
12846 * again.
12847 */
12848 gettimeofday(&tv, NULL);
12849 tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8));
12850 if ((tick == ctx->progress_last_time) &&
12851 (fixed_percent != 0) && (fixed_percent != 1000))
12852 return 0;
12853 ctx->progress_last_time = tick;
12854
12855 /*
12856 * Advance the spinner, and note that the progress bar
12857 * will be on the screen
12858 */
12859 ctx->progress_pos = (ctx->progress_pos+1) & 3;
12860 ctx->flags |= E2F_FLAG_PROG_BAR;
12861
12862 dpywidth = 66 - strlen(label);
12863 dpywidth = 8 * (dpywidth / 8);
12864 if (dpynum)
12865 dpywidth -= 8;
12866
12867 i = ((percent * dpywidth) + 50) / 100;
12868 printf("%s%s: |%s%s", ctx->start_meta, label,
12869 bar + (sizeof(bar) - (i+1)),
12870 spaces + (sizeof(spaces) - (dpywidth - i + 1)));
12871 if (fixed_percent == 1000)
12872 fputc('|', stdout);
12873 else
12874 fputc(spinner[ctx->progress_pos & 3], stdout);
12875 printf(" %4.1f%% ", percent);
12876 if (dpynum)
12877 printf("%u\r", dpynum);
12878 else
12879 fputs(" \r", stdout);
12880 fputs(ctx->stop_meta, stdout);
12881
12882 if (fixed_percent == 1000)
12883 e2fsck_clear_progbar(ctx);
12884 fflush(stdout);
12885
12886 return 0;
12887}
12888
12889static int e2fsck_update_progress(e2fsck_t ctx, int pass,
12890 unsigned long cur, unsigned long max)
12891{
12892 char buf[80];
12893 float percent;
12894
12895 if (pass == 0)
12896 return 0;
12897
12898 if (ctx->progress_fd) {
12899 sprintf(buf, "%d %lu %lu\n", pass, cur, max);
12900 write(ctx->progress_fd, buf, strlen(buf));
12901 } else {
12902 percent = calc_percent(&e2fsck_tbl, pass, cur, max);
12903 e2fsck_simple_progress(ctx, ctx->device_name,
12904 percent, 0);
12905 }
12906 return 0;
12907}
12908
12909static void reserve_stdio_fds(void)
12910{
12911 int fd;
12912
12913 while (1) {
12914 fd = open(bb_dev_null, O_RDWR);
12915 if (fd > 2)
12916 break;
12917 if (fd < 0) {
12918 fprintf(stderr, _("ERROR: Cannot open "
12919 "/dev/null (%s)\n"),
12920 strerror(errno));
12921 break;
12922 }
12923 }
12924 close(fd);
12925}
12926
12927static void signal_progress_on(int sig FSCK_ATTR((unused)))
12928{
12929 e2fsck_t ctx = e2fsck_global_ctx;
12930
12931 if (!ctx)
12932 return;
12933
12934 ctx->progress = e2fsck_update_progress;
12935 ctx->progress_fd = 0;
12936}
12937
12938static void signal_progress_off(int sig FSCK_ATTR((unused)))
12939{
12940 e2fsck_t ctx = e2fsck_global_ctx;
12941
12942 if (!ctx)
12943 return;
12944
12945 e2fsck_clear_progbar(ctx);
12946 ctx->progress = 0;
12947}
12948
12949static void signal_cancel(int sig FSCK_ATTR((unused)))
12950{
12951 e2fsck_t ctx = e2fsck_global_ctx;
12952
12953 if (!ctx)
12954 exit(FSCK_CANCELED);
12955
12956 ctx->flags |= E2F_FLAG_CANCEL;
12957}
12958
12959static void parse_extended_opts(e2fsck_t ctx, const char *opts)
12960{
12961 char *buf, *token, *next, *p, *arg;
12962 int ea_ver;
12963 int extended_usage = 0;
12964
12965 buf = string_copy(opts, 0);
12966 for (token = buf; token && *token; token = next) {
12967 p = strchr(token, ',');
12968 next = 0;
12969 if (p) {
12970 *p = 0;
12971 next = p+1;
12972 }
12973 arg = strchr(token, '=');
12974 if (arg) {
12975 *arg = 0;
12976 arg++;
12977 }
12978 if (strcmp(token, "ea_ver") == 0) {
12979 if (!arg) {
12980 extended_usage++;
12981 continue;
12982 }
12983 ea_ver = strtoul(arg, &p, 0);
12984 if (*p ||
12985 ((ea_ver != 1) && (ea_ver != 2))) {
12986 fprintf(stderr,
12987 _("Invalid EA version.\n"));
12988 extended_usage++;
12989 continue;
12990 }
12991 ctx->ext_attr_ver = ea_ver;
12992 } else {
12993 fprintf(stderr, _("Unknown extended option: %s\n"),
12994 token);
12995 extended_usage++;
12996 }
12997 }
12998 if (extended_usage) {
12999 bb_error_msg_and_die(
13000 "Extended options are separated by commas, "
13001 "and may take an argument which\n"
13002 "is set off by an equals ('=') sign. "
13003 "Valid extended options are:\n"
13004 "\tea_ver=<ea_version (1 or 2)>\n\n");
13005 }
13006}
13007
13008
13009static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
13010{
13011 int flush = 0;
13012 int c, fd;
13013 e2fsck_t ctx;
13014 errcode_t retval;
13015 struct sigaction sa;
13016 char *extended_opts = 0;
13017
13018 retval = e2fsck_allocate_context(&ctx);
13019 if (retval)
13020 return retval;
13021
13022 *ret_ctx = ctx;
13023
13024 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
13025 setvbuf(stderr, NULL, _IONBF, BUFSIZ);
13026 if (isatty(0) && isatty(1)) {
13027 ctx->interactive = 1;
13028 } else {
13029 ctx->start_meta[0] = '\001';
13030 ctx->stop_meta[0] = '\002';
13031 }
13032 memset(bar, '=', sizeof(bar)-1);
13033 memset(spaces, ' ', sizeof(spaces)-1);
13034 blkid_get_cache(&ctx->blkid, NULL);
13035
13036 if (argc && *argv)
13037 ctx->program_name = *argv;
13038 else
13039 ctx->program_name = "e2fsck";
13040 while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
13041 switch (c) {
13042 case 'C':
13043 ctx->progress = e2fsck_update_progress;
13044 ctx->progress_fd = atoi(optarg);
13045 if (!ctx->progress_fd)
13046 break;
13047 /* Validate the file descriptor to avoid disasters */
13048 fd = dup(ctx->progress_fd);
13049 if (fd < 0) {
13050 fprintf(stderr,
13051 _("Error validating file descriptor %d: %s\n"),
13052 ctx->progress_fd,
13053 error_message(errno));
13054 bb_error_msg_and_die(_("Invalid completion information file descriptor"));
13055 } else
13056 close(fd);
13057 break;
13058 case 'D':
13059 ctx->options |= E2F_OPT_COMPRESS_DIRS;
13060 break;
13061 case 'E':
13062 extended_opts = optarg;
13063 break;
13064 case 'p':
13065 case 'a':
13066 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) {
13067 conflict_opt:
13068 bb_error_msg_and_die(_("Only one the options -p/-a, -n or -y may be specified."));
13069 }
13070 ctx->options |= E2F_OPT_PREEN;
13071 break;
13072 case 'n':
13073 if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
13074 goto conflict_opt;
13075 ctx->options |= E2F_OPT_NO;
13076 break;
13077 case 'y':
13078 if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO))
13079 goto conflict_opt;
13080 ctx->options |= E2F_OPT_YES;
13081 break;
13082 case 't':
13083 /* FIXME - This needs to go away in a future path - will change binary */
13084 fprintf(stderr, _("The -t option is not "
13085 "supported on this version of e2fsck.\n"));
13086 break;
13087 case 'c':
13088 if (cflag++)
13089 ctx->options |= E2F_OPT_WRITECHECK;
13090 ctx->options |= E2F_OPT_CHECKBLOCKS;
13091 break;
13092 case 'r':
13093 /* What we do by default, anyway! */
13094 break;
13095 case 'b':
13096 ctx->use_superblock = atoi(optarg);
13097 ctx->flags |= E2F_FLAG_SB_SPECIFIED;
13098 break;
13099 case 'B':
13100 ctx->blocksize = atoi(optarg);
13101 break;
13102 case 'I':
13103 ctx->inode_buffer_blocks = atoi(optarg);
13104 break;
13105 case 'j':
13106 ctx->journal_name = string_copy(optarg, 0);
13107 break;
13108 case 'P':
13109 ctx->process_inode_size = atoi(optarg);
13110 break;
13111 case 'd':
13112 ctx->options |= E2F_OPT_DEBUG;
13113 break;
13114 case 'f':
13115 ctx->options |= E2F_OPT_FORCE;
13116 break;
13117 case 'F':
13118 flush = 1;
13119 break;
13120 case 'v':
13121 verbose = 1;
13122 break;
13123 case 'V':
13124 show_version_only = 1;
13125 break;
13126 case 'N':
13127 ctx->device_name = optarg;
13128 break;
13129#ifdef ENABLE_SWAPFS
13130 case 's':
13131 normalize_swapfs = 1;
13132 case 'S':
13133 swapfs = 1;
13134 break;
13135#else
13136 case 's':
13137 case 'S':
13138 fprintf(stderr, _("Byte-swapping filesystems "
13139 "not compiled in this version "
13140 "of e2fsck\n"));
13141 exit(1);
13142#endif
13143 default:
13144 bb_show_usage();
13145 }
13146 if (show_version_only)
13147 return 0;
13148 if (optind != argc - 1)
13149 bb_show_usage();
13150 if ((ctx->options & E2F_OPT_NO) &&
13151 !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
13152 ctx->options |= E2F_OPT_READONLY;
13153 ctx->io_options = strchr(argv[optind], '?');
13154 if (ctx->io_options)
13155 *ctx->io_options++ = 0;
13156 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
13157 if (!ctx->filesystem_name) {
13158 bb_error_msg(_("Unable to resolve '%s'"), argv[optind]);
13159 bb_error_msg_and_die(0);
13160 }
13161 if (extended_opts)
13162 parse_extended_opts(ctx, extended_opts);
13163
13164 if (flush) {
13165 fd = open(ctx->filesystem_name, O_RDONLY, 0);
13166 if (fd < 0) {
13167 bb_error_msg(_("while opening %s for flushing"),
13168 ctx->filesystem_name);
13169 bb_error_msg_and_die(0);
13170 }
13171 if ((retval = ext2fs_sync_device(fd, 1))) {
13172 bb_error_msg(_("while trying to flush %s"),
13173 ctx->filesystem_name);
13174 bb_error_msg_and_die(0);
13175 }
13176 close(fd);
13177 }
13178#ifdef ENABLE_SWAPFS
13179 if (swapfs && cflag) {
13180 fprintf(stderr, _("Incompatible options not "
13181 "allowed when byte-swapping.\n"));
13182 exit(EXIT_USAGE);
13183 }
13184#endif
13185 /*
13186 * Set up signal action
13187 */
13188 memset(&sa, 0, sizeof(struct sigaction));
13189 sa.sa_handler = signal_cancel;
13190 sigaction(SIGINT, &sa, 0);
13191 sigaction(SIGTERM, &sa, 0);
13192#ifdef SA_RESTART
13193 sa.sa_flags = SA_RESTART;
13194#endif
13195 e2fsck_global_ctx = ctx;
13196 sa.sa_handler = signal_progress_on;
13197 sigaction(SIGUSR1, &sa, 0);
13198 sa.sa_handler = signal_progress_off;
13199 sigaction(SIGUSR2, &sa, 0);
13200
13201 /* Update our PATH to include /sbin if we need to run badblocks */
13202 if (cflag)
13203 e2fs_set_sbin_path();
13204 return 0;
13205}
13206
13207static const char my_ver_string[] = E2FSPROGS_VERSION;
13208static const char my_ver_date[] = E2FSPROGS_DATE;
13209
13210int e2fsck_main (int argc, char *argv[])
13211{
13212 errcode_t retval;
13213 int exit_value = EXIT_OK;
13214 ext2_filsys fs = 0;
13215 io_manager io_ptr;
13216 struct ext2_super_block *sb;
13217 const char *lib_ver_date;
13218 int my_ver, lib_ver;
13219 e2fsck_t ctx;
13220 struct problem_context pctx;
13221 int flags, run_result;
13222
13223 clear_problem_context(&pctx);
13224
13225 my_ver = ext2fs_parse_version_string(my_ver_string);
13226 lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
13227 if (my_ver > lib_ver) {
13228 fprintf( stderr, _("Error: ext2fs library version "
13229 "out of date!\n"));
13230 show_version_only++;
13231 }
13232
13233 retval = PRS(argc, argv, &ctx);
13234 if (retval) {
13235 bb_error_msg(_("while trying to initialize program"));
13236 exit(EXIT_ERROR);
13237 }
13238 reserve_stdio_fds();
13239
13240 if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
13241 fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string,
13242 my_ver_date);
13243
13244 if (show_version_only) {
13245 fprintf(stderr, _("\tUsing %s, %s\n"),
13246 error_message(EXT2_ET_BASE), lib_ver_date);
13247 exit(EXIT_OK);
13248 }
13249
13250 check_mount(ctx);
13251
13252 if (!(ctx->options & E2F_OPT_PREEN) &&
13253 !(ctx->options & E2F_OPT_NO) &&
13254 !(ctx->options & E2F_OPT_YES)) {
13255 if (!ctx->interactive)
13256 bb_error_msg_and_die(_("need terminal for interactive repairs"));
13257 }
13258 ctx->superblock = ctx->use_superblock;
13259restart:
13260#ifdef CONFIG_TESTIO_DEBUG
13261 io_ptr = test_io_manager;
13262 test_io_backing_manager = unix_io_manager;
13263#else
13264 io_ptr = unix_io_manager;
13265#endif
13266 flags = 0;
13267 if ((ctx->options & E2F_OPT_READONLY) == 0)
13268 flags |= EXT2_FLAG_RW;
13269
13270 if (ctx->superblock && ctx->blocksize) {
13271 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
13272 flags, ctx->superblock, ctx->blocksize,
13273 io_ptr, &fs);
13274 } else if (ctx->superblock) {
13275 int blocksize;
13276 for (blocksize = EXT2_MIN_BLOCK_SIZE;
13277 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
13278 retval = ext2fs_open2(ctx->filesystem_name,
13279 ctx->io_options, flags,
13280 ctx->superblock, blocksize,
13281 io_ptr, &fs);
13282 if (!retval)
13283 break;
13284 }
13285 } else
13286 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
13287 flags, 0, 0, io_ptr, &fs);
13288 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
13289 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
13290 ((retval == EXT2_ET_BAD_MAGIC) ||
13291 ((retval == 0) && ext2fs_check_desc(fs)))) {
13292 if (!fs || (fs->group_desc_count > 1)) {
13293 printf(_("%s trying backup blocks...\n"),
13294 retval ? _("Couldn't find ext2 superblock,") :
13295 _("Group descriptors look bad..."));
13296 get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
13297 if (fs)
13298 ext2fs_close(fs);
13299 goto restart;
13300 }
13301 }
13302 if (retval) {
13303 bb_error_msg(_("while trying to open %s"),
13304 ctx->filesystem_name);
13305 if (retval == EXT2_ET_REV_TOO_HIGH) {
13306 printf(_("The filesystem revision is apparently "
13307 "too high for this version of e2fsck.\n"
13308 "(Or the filesystem superblock "
13309 "is corrupt)\n\n"));
13310 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
13311 } else if (retval == EXT2_ET_SHORT_READ)
13312 printf(_("Could this be a zero-length partition?\n"));
13313 else if ((retval == EPERM) || (retval == EACCES))
13314 printf(_("You must have %s access to the "
13315 "filesystem or be root\n"),
13316 (ctx->options & E2F_OPT_READONLY) ?
13317 "r/o" : "r/w");
13318 else if (retval == ENXIO)
13319 printf(_("Possibly non-existent or swap device?\n"));
13320#ifdef EROFS
13321 else if (retval == EROFS)
13322 printf(_("Disk write-protected; use the -n option "
13323 "to do a read-only\n"
13324 "check of the device.\n"));
13325#endif
13326 else
13327 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
13328 bb_error_msg_and_die(0);
13329 }
13330 ctx->fs = fs;
13331 fs->priv_data = ctx;
13332 sb = fs->super;
13333 if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
13334 bb_error_msg(_("while trying to open %s"),
13335 ctx->filesystem_name);
13336 get_newer:
13337 bb_error_msg_and_die(_("Get a newer version of e2fsck!"));
13338 }
13339
13340 /*
13341 * Set the device name, which is used whenever we print error
13342 * or informational messages to the user.
13343 */
13344 if (ctx->device_name == 0 &&
13345 (sb->s_volume_name[0] != 0)) {
13346 ctx->device_name = string_copy(sb->s_volume_name,
13347 sizeof(sb->s_volume_name));
13348 }
13349 if (ctx->device_name == 0)
13350 ctx->device_name = ctx->filesystem_name;
13351
13352 /*
13353 * Make sure the ext3 superblock fields are consistent.
13354 */
13355 retval = e2fsck_check_ext3_journal(ctx);
13356 if (retval) {
13357 bb_error_msg(_("while checking ext3 journal for %s"),
13358 ctx->device_name);
13359 bb_error_msg_and_die(0);
13360 }
13361
13362 /*
13363 * Check to see if we need to do ext3-style recovery. If so,
13364 * do it, and then restart the fsck.
13365 */
13366 if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
13367 if (ctx->options & E2F_OPT_READONLY) {
13368 printf(_("Warning: skipping journal recovery "
13369 "because doing a read-only filesystem "
13370 "check.\n"));
13371 io_channel_flush(ctx->fs->io);
13372 } else {
13373 if (ctx->flags & E2F_FLAG_RESTARTED) {
13374 /*
13375 * Whoops, we attempted to run the
13376 * journal twice. This should never
13377 * happen, unless the hardware or
13378 * device driver is being bogus.
13379 */
13380 bb_error_msg(_("cannot set superblock flags on %s"), ctx->device_name);
13381 bb_error_msg_and_die(0);
13382 }
13383 retval = e2fsck_run_ext3_journal(ctx);
13384 if (retval) {
13385 bb_error_msg(_("while recovering ext3 journal of %s"),
13386 ctx->device_name);
13387 bb_error_msg_and_die(0);
13388 }
13389 ext2fs_close(ctx->fs);
13390 ctx->fs = 0;
13391 ctx->flags |= E2F_FLAG_RESTARTED;
13392 goto restart;
13393 }
13394 }
13395
13396 /*
13397 * Check for compatibility with the feature sets. We need to
13398 * be more stringent than ext2fs_open().
13399 */
13400 if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
13401 (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
13402 bb_error_msg("(%s)", ctx->device_name);
13403 goto get_newer;
13404 }
13405 if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
13406 bb_error_msg("(%s)", ctx->device_name);
13407 goto get_newer;
13408 }
13409#ifdef ENABLE_COMPRESSION
13410 /* FIXME - do we support this at all? */
13411 if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
13412 bb_error_msg(_("Warning: compression support is experimental."));
13413#endif
13414#ifndef ENABLE_HTREE
13415 if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
13416 bb_error_msg(_("E2fsck not compiled with HTREE support,\n\t"
13417 "but filesystem %s has HTREE directories."),
13418 ctx->device_name);
13419 goto get_newer;
13420 }
13421#endif
13422
13423 /*
13424 * If the user specified a specific superblock, presumably the
13425 * master superblock has been trashed. So we mark the
13426 * superblock as dirty, so it can be written out.
13427 */
13428 if (ctx->superblock &&
13429 !(ctx->options & E2F_OPT_READONLY))
13430 ext2fs_mark_super_dirty(fs);
13431
13432 /*
13433 * We only update the master superblock because (a) paranoia;
13434 * we don't want to corrupt the backup superblocks, and (b) we
13435 * don't need to update the mount count and last checked
13436 * fields in the backup superblock (the kernel doesn't
13437 * update the backup superblocks anyway).
13438 */
13439 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
13440
13441 ehandler_init(fs->io);
13442
13443 if (ctx->superblock)
13444 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
13445 ext2fs_mark_valid(fs);
13446 check_super_block(ctx);
13447 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
13448 bb_error_msg_and_die(0);
13449 check_if_skip(ctx);
13450 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
13451 bb_error_msg_and_die(0);
13452#ifdef ENABLE_SWAPFS
13453
13454#ifdef WORDS_BIGENDIAN
13455#define NATIVE_FLAG EXT2_FLAG_SWAP_BYTES
13456#else
13457#define NATIVE_FLAG 0
13458#endif
13459
13460
13461 if (normalize_swapfs) {
13462 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == NATIVE_FLAG) {
13463 fprintf(stderr, _("%s: Filesystem byte order "
13464 "already normalized.\n"), ctx->device_name);
13465 bb_error_msg_and_die(0);
13466 }
13467 }
13468 if (swapfs) {
13469 swap_filesys(ctx);
13470 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
13471 bb_error_msg_and_die(0);
13472 }
13473#endif
13474
13475 /*
13476 * Mark the system as valid, 'til proven otherwise
13477 */
13478 ext2fs_mark_valid(fs);
13479
13480 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
13481 if (retval) {
13482 bb_error_msg(_("while reading bad blocks inode"));
13483 preenhalt(ctx);
13484 printf(_("This doesn't bode well,"
13485 " but we'll try to go on...\n"));
13486 }
13487
13488 run_result = e2fsck_run(ctx);
13489 e2fsck_clear_progbar(ctx);
13490 if (run_result == E2F_FLAG_RESTART) {
13491 printf(_("Restarting e2fsck from the beginning...\n"));
13492 retval = e2fsck_reset_context(ctx);
13493 if (retval) {
13494 bb_error_msg(_("while resetting context"));
13495 bb_error_msg_and_die(0);
13496 }
13497 ext2fs_close(fs);
13498 goto restart;
13499 }
13500 if (run_result & E2F_FLAG_CANCEL) {
13501 printf(_("%s: e2fsck canceled.\n"), ctx->device_name ?
13502 ctx->device_name : ctx->filesystem_name);
13503 exit_value |= FSCK_CANCELED;
13504 }
13505 if (run_result & E2F_FLAG_ABORT)
13506 bb_error_msg_and_die(_("aborted"));
13507
13508 /* Cleanup */
13509 if (ext2fs_test_changed(fs)) {
13510 exit_value |= EXIT_NONDESTRUCT;
13511 if (!(ctx->options & E2F_OPT_PREEN))
13512 printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
13513 ctx->device_name);
13514 if (ctx->mount_flags & EXT2_MF_ISROOT) {
13515 printf(_("%s: ***** REBOOT LINUX *****\n"),
13516 ctx->device_name);
13517 exit_value |= EXIT_DESTRUCT;
13518 }
13519 }
13520 if (!ext2fs_test_valid(fs)) {
13521 printf(_("\n%s: ********** WARNING: Filesystem still has "
13522 "errors **********\n\n"), ctx->device_name);
13523 exit_value |= EXIT_UNCORRECTED;
13524 exit_value &= ~EXIT_NONDESTRUCT;
13525 }
13526 if (exit_value & FSCK_CANCELED)
13527 exit_value &= ~EXIT_NONDESTRUCT;
13528 else {
13529 show_stats(ctx);
13530 if (!(ctx->options & E2F_OPT_READONLY)) {
13531 if (ext2fs_test_valid(fs)) {
13532 if (!(sb->s_state & EXT2_VALID_FS))
13533 exit_value |= EXIT_NONDESTRUCT;
13534 sb->s_state = EXT2_VALID_FS;
13535 } else
13536 sb->s_state &= ~EXT2_VALID_FS;
13537 sb->s_mnt_count = 0;
13538 sb->s_lastcheck = time(NULL);
13539 ext2fs_mark_super_dirty(fs);
13540 }
13541 }
13542
13543 e2fsck_write_bitmaps(ctx);
13544
13545 ext2fs_close(fs);
13546 ctx->fs = NULL;
13547 free(ctx->filesystem_name);
13548 free(ctx->journal_name);
13549 e2fsck_free_context(ctx);
13550
13551 return exit_value;
13552}
diff --git a/e2fsprogs/old_e2fsprogs/e2fsck.h b/e2fsprogs/old_e2fsprogs/e2fsck.h
new file mode 100644
index 000000000..e520632a0
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2fsck.h
@@ -0,0 +1,640 @@
1/* vi: set sw=4 ts=4: */
2#include <sys/types.h>
3#include <stdio.h>
4#include <string.h>
5#include <unistd.h>
6#include <stdlib.h>
7#include <time.h>
8#include <fcntl.h>
9#include <ctype.h>
10#include <setjmp.h>
11#include <errno.h>
12#include <getopt.h>
13#include <limits.h>
14#include <stddef.h>
15#include <assert.h>
16#include <signal.h>
17#include <sys/stat.h>
18#include <sys/resource.h>
19#include <sys/param.h>
20#include <sys/mount.h>
21#include <sys/ioctl.h>
22#include <termios.h>
23#include <mntent.h>
24#include <dirent.h>
25#include "ext2fs/kernel-list.h"
26#include <sys/types.h>
27#include <linux/types.h>
28
29/*
30 * Now pull in the real linux/jfs.h definitions.
31 */
32#include "ext2fs/kernel-jbd.h"
33
34
35
36#include "fsck.h"
37
38#include "ext2fs/ext2_fs.h"
39#include "blkid/blkid.h"
40#include "ext2fs/ext2_ext_attr.h"
41#include "uuid/uuid.h"
42#include "busybox.h"
43
44#ifdef HAVE_CONIO_H
45#undef HAVE_TERMIOS_H
46#include <conio.h>
47#define read_a_char() getch()
48#else
49#ifdef HAVE_TERMIOS_H
50#include <termios.h>
51#endif
52#endif
53
54
55/*
56 * The last ext2fs revision level that this version of e2fsck is able to
57 * support
58 */
59#define E2FSCK_CURRENT_REV 1
60
61/* Used by the region allocation code */
62typedef __u32 region_addr_t;
63typedef struct region_struct *region_t;
64
65struct dx_dirblock_info {
66 int type;
67 blk_t phys;
68 int flags;
69 blk_t parent;
70 ext2_dirhash_t min_hash;
71 ext2_dirhash_t max_hash;
72 ext2_dirhash_t node_min_hash;
73 ext2_dirhash_t node_max_hash;
74};
75
76/*
77These defines are used in the type field of dx_dirblock_info
78*/
79
80#define DX_DIRBLOCK_ROOT 1
81#define DX_DIRBLOCK_LEAF 2
82#define DX_DIRBLOCK_NODE 3
83
84
85/*
86The following defines are used in the 'flags' field of a dx_dirblock_info
87*/
88#define DX_FLAG_REFERENCED 1
89#define DX_FLAG_DUP_REF 2
90#define DX_FLAG_FIRST 4
91#define DX_FLAG_LAST 8
92
93/*
94 * E2fsck options
95 */
96#define E2F_OPT_READONLY 0x0001
97#define E2F_OPT_PREEN 0x0002
98#define E2F_OPT_YES 0x0004
99#define E2F_OPT_NO 0x0008
100#define E2F_OPT_TIME 0x0010
101#define E2F_OPT_CHECKBLOCKS 0x0040
102#define E2F_OPT_DEBUG 0x0080
103#define E2F_OPT_FORCE 0x0100
104#define E2F_OPT_WRITECHECK 0x0200
105#define E2F_OPT_COMPRESS_DIRS 0x0400
106
107/*
108 * E2fsck flags
109 */
110#define E2F_FLAG_ABORT 0x0001 /* Abort signaled */
111#define E2F_FLAG_CANCEL 0x0002 /* Cancel signaled */
112#define E2F_FLAG_SIGNAL_MASK 0x0003
113#define E2F_FLAG_RESTART 0x0004 /* Restart signaled */
114
115#define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */
116
117#define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */
118#define E2F_FLAG_PROG_SUPPRESS 0x0040 /* Progress suspended */
119#define E2F_FLAG_JOURNAL_INODE 0x0080 /* Create a new ext3 journal inode */
120#define E2F_FLAG_SB_SPECIFIED 0x0100 /* The superblock was explicitly
121 * specified by the user */
122#define E2F_FLAG_RESTARTED 0x0200 /* E2fsck has been restarted */
123#define E2F_FLAG_RESIZE_INODE 0x0400 /* Request to recreate resize inode */
124
125
126/*Don't know where these come from*/
127#define READ 0
128#define WRITE 1
129#define cpu_to_be32(n) htonl(n)
130#define be32_to_cpu(n) ntohl(n)
131
132/*
133 * We define a set of "latch groups"; these are problems which are
134 * handled as a set. The user answers once for a particular latch
135 * group.
136 */
137#define PR_LATCH_MASK 0x0ff0 /* Latch mask */
138#define PR_LATCH_BLOCK 0x0010 /* Latch for illegal blocks (pass 1) */
139#define PR_LATCH_BBLOCK 0x0020 /* Latch for bad block inode blocks (pass 1) */
140#define PR_LATCH_IBITMAP 0x0030 /* Latch for pass 5 inode bitmap proc. */
141#define PR_LATCH_BBITMAP 0x0040 /* Latch for pass 5 inode bitmap proc. */
142#define PR_LATCH_RELOC 0x0050 /* Latch for superblock relocate hint */
143#define PR_LATCH_DBLOCK 0x0060 /* Latch for pass 1b dup block headers */
144#define PR_LATCH_LOW_DTIME 0x0070 /* Latch for pass1 orphaned list refugees */
145#define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */
146#define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */
147
148#define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1)
149
150/*
151 * Latch group descriptor flags
152 */
153#define PRL_YES 0x0001 /* Answer yes */
154#define PRL_NO 0x0002 /* Answer no */
155#define PRL_LATCHED 0x0004 /* The latch group is latched */
156#define PRL_SUPPRESS 0x0008 /* Suppress all latch group questions */
157
158#define PRL_VARIABLE 0x000f /* All the flags that need to be reset */
159
160/*
161 * Pre-Pass 1 errors
162 */
163
164#define PR_0_BB_NOT_GROUP 0x000001 /* Block bitmap not in group */
165#define PR_0_IB_NOT_GROUP 0x000002 /* Inode bitmap not in group */
166#define PR_0_ITABLE_NOT_GROUP 0x000003 /* Inode table not in group */
167#define PR_0_SB_CORRUPT 0x000004 /* Superblock corrupt */
168#define PR_0_FS_SIZE_WRONG 0x000005 /* Filesystem size is wrong */
169#define PR_0_NO_FRAGMENTS 0x000006 /* Fragments not supported */
170#define PR_0_BLOCKS_PER_GROUP 0x000007 /* Bad blocks_per_group */
171#define PR_0_FIRST_DATA_BLOCK 0x000008 /* Bad first_data_block */
172#define PR_0_ADD_UUID 0x000009 /* Adding UUID to filesystem */
173#define PR_0_RELOCATE_HINT 0x00000A /* Relocate hint */
174#define PR_0_MISC_CORRUPT_SUPER 0x00000B /* Miscellaneous superblock corruption */
175#define PR_0_GETSIZE_ERROR 0x00000C /* Error determing physical device size of filesystem */
176#define PR_0_INODE_COUNT_WRONG 0x00000D /* Inode count in the superblock incorrect */
177#define PR_0_HURD_CLEAR_FILETYPE 0x00000E /* The Hurd does not support the filetype feature */
178#define PR_0_JOURNAL_BAD_INODE 0x00000F /* The Hurd does not support the filetype feature */
179#define PR_0_JOURNAL_UNSUPP_MULTIFS 0x000010 /* The external journal has multiple filesystems (which we can't handle yet) */
180#define PR_0_CANT_FIND_JOURNAL 0x000011 /* Can't find external journal */
181#define PR_0_EXT_JOURNAL_BAD_SUPER 0x000012/* External journal has bad superblock */
182#define PR_0_JOURNAL_BAD_UUID 0x000013 /* Superblock has a bad journal UUID */
183#define PR_0_JOURNAL_UNSUPP_SUPER 0x000014 /* Journal has an unknown superblock type */
184#define PR_0_JOURNAL_BAD_SUPER 0x000015 /* Journal superblock is corrupt */
185#define PR_0_JOURNAL_HAS_JOURNAL 0x000016 /* Journal superblock is corrupt */
186#define PR_0_JOURNAL_RECOVER_SET 0x000017 /* Superblock has recovery flag set but no journal */
187#define PR_0_JOURNAL_RECOVERY_CLEAR 0x000018 /* Journal has data, but recovery flag is clear */
188#define PR_0_JOURNAL_RESET_JOURNAL 0x000019 /* Ask if we should clear the journal */
189#define PR_0_FS_REV_LEVEL 0x00001A /* Filesystem revision is 0, but feature flags are set */
190#define PR_0_ORPHAN_CLEAR_INODE 0x000020 /* Clearing orphan inode */
191#define PR_0_ORPHAN_ILLEGAL_BLOCK_NUM 0x000021 /* Illegal block found in orphaned inode */
192#define PR_0_ORPHAN_ALREADY_CLEARED_BLOCK 0x000022 /* Already cleared block found in orphaned inode */
193#define PR_0_ORPHAN_ILLEGAL_HEAD_INODE 0x000023 /* Illegal orphan inode in superblock */
194#define PR_0_ORPHAN_ILLEGAL_INODE 0x000024 /* Illegal inode in orphaned inode list */
195#define PR_0_JOURNAL_UNSUPP_ROCOMPAT 0x000025 /* Journal has unsupported read-only feature - abort */
196#define PR_0_JOURNAL_UNSUPP_INCOMPAT 0x000026 /* Journal has unsupported incompatible feature - abort */
197#define PR_0_JOURNAL_UNSUPP_VERSION 0x000027 /* Journal has unsupported version number */
198#define PR_0_MOVE_JOURNAL 0x000028 /* Moving journal to hidden file */
199#define PR_0_ERR_MOVE_JOURNAL 0x000029 /* Error moving journal */
200#define PR_0_CLEAR_V2_JOURNAL 0x00002A /* Clearing V2 journal superblock */
201#define PR_0_JOURNAL_RUN 0x00002B /* Run journal anyway */
202#define PR_0_JOURNAL_RUN_DEFAULT 0x00002C /* Run journal anyway by default */
203#define PR_0_BACKUP_JNL 0x00002D /* Backup journal inode blocks */
204#define PR_0_NONZERO_RESERVED_GDT_BLOCKS 0x00002E /* Reserved blocks w/o resize_inode */
205#define PR_0_CLEAR_RESIZE_INODE 0x00002F /* Resize_inode not enabled, but resize inode is non-zero */
206#define PR_0_RESIZE_INODE_INVALID 0x000030 /* Resize inode invalid */
207
208/*
209 * Pass 1 errors
210 */
211
212#define PR_1_PASS_HEADER 0x010000 /* Pass 1: Checking inodes, blocks, and sizes */
213#define PR_1_ROOT_NO_DIR 0x010001 /* Root directory is not an inode */
214#define PR_1_ROOT_DTIME 0x010002 /* Root directory has dtime set */
215#define PR_1_RESERVED_BAD_MODE 0x010003 /* Reserved inode has bad mode */
216#define PR_1_ZERO_DTIME 0x010004 /* Deleted inode has zero dtime */
217#define PR_1_SET_DTIME 0x010005 /* Inode in use, but dtime set */
218#define PR_1_ZERO_LENGTH_DIR 0x010006 /* Zero-length directory */
219#define PR_1_BB_CONFLICT 0x010007 /* Block bitmap conflicts with some other fs block */
220#define PR_1_IB_CONFLICT 0x010008 /* Inode bitmap conflicts with some other fs block */
221#define PR_1_ITABLE_CONFLICT 0x010009 /* Inode table conflicts with some other fs block */
222#define PR_1_BB_BAD_BLOCK 0x01000A /* Block bitmap is on a bad block */
223#define PR_1_IB_BAD_BLOCK 0x01000B /* Inode bitmap is on a bad block */
224#define PR_1_BAD_I_SIZE 0x01000C /* Inode has incorrect i_size */
225#define PR_1_BAD_I_BLOCKS 0x01000D /* Inode has incorrect i_blocks */
226#define PR_1_ILLEGAL_BLOCK_NUM 0x01000E /* Illegal block number in inode */
227#define PR_1_BLOCK_OVERLAPS_METADATA 0x01000F /* Block number overlaps fs metadata */
228#define PR_1_INODE_BLOCK_LATCH 0x010010 /* Inode has illegal blocks (latch question) */
229#define PR_1_TOO_MANY_BAD_BLOCKS 0x010011 /* Too many bad blocks in inode */
230#define PR_1_BB_ILLEGAL_BLOCK_NUM 0x010012 /* Illegal block number in bad block inode */
231#define PR_1_INODE_BBLOCK_LATCH 0x010013 /* Bad block inode has illegal blocks (latch question) */
232#define PR_1_DUP_BLOCKS_PREENSTOP 0x010014 /* Duplicate or bad blocks in use! */
233#define PR_1_BBINODE_BAD_METABLOCK 0x010015 /* Bad block used as bad block indirect block */
234#define PR_1_BBINODE_BAD_METABLOCK_PROMPT 0x010016 /* Inconsistency can't be fixed prompt */
235#define PR_1_BAD_PRIMARY_BLOCK 0x010017 /* Bad primary block */
236#define PR_1_BAD_PRIMARY_BLOCK_PROMPT 0x010018 /* Bad primary block prompt */
237#define PR_1_BAD_PRIMARY_SUPERBLOCK 0x010019 /* Bad primary superblock */
238#define PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR 0x01001A /* Bad primary block group descriptors */
239#define PR_1_BAD_SUPERBLOCK 0x01001B /* Bad superblock in group */
240#define PR_1_BAD_GROUP_DESCRIPTORS 0x01001C /* Bad block group descriptors in group */
241#define PR_1_PROGERR_CLAIMED_BLOCK 0x01001D /* Block claimed for no reason */
242#define PR_1_RELOC_BLOCK_ALLOCATE 0x01001E /* Error allocating blocks for relocating metadata */
243#define PR_1_RELOC_MEMORY_ALLOCATE 0x01001F /* Error allocating block buffer during relocation process */
244#define PR_1_RELOC_FROM_TO 0x010020 /* Relocating metadata group information from X to Y */
245#define PR_1_RELOC_TO 0x010021 /* Relocating metatdata group information to X */
246#define PR_1_RELOC_READ_ERR 0x010022 /* Block read error during relocation process */
247#define PR_1_RELOC_WRITE_ERR 0x010023 /* Block write error during relocation process */
248#define PR_1_ALLOCATE_IBITMAP_ERROR 0x010024 /* Error allocating inode bitmap */
249#define PR_1_ALLOCATE_BBITMAP_ERROR 0x010025 /* Error allocating block bitmap */
250#define PR_1_ALLOCATE_ICOUNT 0x010026 /* Error allocating icount structure */
251#define PR_1_ALLOCATE_DBCOUNT 0x010027 /* Error allocating dbcount */
252#define PR_1_ISCAN_ERROR 0x010028 /* Error while scanning inodes */
253#define PR_1_BLOCK_ITERATE 0x010029 /* Error while iterating over blocks */
254#define PR_1_ICOUNT_STORE 0x01002A /* Error while storing inode count information */
255#define PR_1_ADD_DBLOCK 0x01002B /* Error while storing directory block information */
256#define PR_1_READ_INODE 0x01002C /* Error while reading inode (for clearing) */
257#define PR_1_SUPPRESS_MESSAGES 0x01002D /* Suppress messages prompt */
258#define PR_1_SET_IMAGIC 0x01002F /* Imagic flag set on an inode when filesystem doesn't support it */
259#define PR_1_SET_IMMUTABLE 0x010030 /* Immutable flag set on a device or socket inode */
260#define PR_1_COMPR_SET 0x010031 /* Compression flag set on a non-compressed filesystem */
261#define PR_1_SET_NONZSIZE 0x010032 /* Non-zero size on on device, fifo or socket inode */
262#define PR_1_FS_REV_LEVEL 0x010033 /* Filesystem revision is 0, but feature flags are set */
263#define PR_1_JOURNAL_INODE_NOT_CLEAR 0x010034 /* Journal inode not in use, needs clearing */
264#define PR_1_JOURNAL_BAD_MODE 0x010035 /* Journal inode has wrong mode */
265#define PR_1_LOW_DTIME 0x010036 /* Inode that was part of orphan linked list */
266#define PR_1_ORPHAN_LIST_REFUGEES 0x010037 /* Latch question which asks how to deal with low dtime inodes */
267#define PR_1_ALLOCATE_REFCOUNT 0x010038 /* Error allocating refcount structure */
268#define PR_1_READ_EA_BLOCK 0x010039 /* Error reading Extended Attribute block */
269#define PR_1_BAD_EA_BLOCK 0x01003A /* Invalid Extended Attribute block */
270#define PR_1_EXTATTR_READ_ABORT 0x01003B /* Error reading Extended Attribute block while fixing refcount -- abort */
271#define PR_1_EXTATTR_REFCOUNT 0x01003C /* Extended attribute reference count incorrect */
272#define PR_1_EXTATTR_WRITE 0x01003D /* Error writing Extended Attribute block while fixing refcount */
273#define PR_1_EA_MULTI_BLOCK 0x01003E /* Multiple EA blocks not supported */
274#define PR_1_EA_ALLOC_REGION 0x01003F /* Error allocating EA region allocation structure */
275#define PR_1_EA_ALLOC_COLLISION 0x010040 /* Error EA allocation collision */
276#define PR_1_EA_BAD_NAME 0x010041 /* Bad extended attribute name */
277#define PR_1_EA_BAD_VALUE 0x010042 /* Bad extended attribute value */
278#define PR_1_INODE_TOOBIG 0x010043 /* Inode too big (latch question) */
279#define PR_1_TOOBIG_DIR 0x010044 /* Directory too big */
280#define PR_1_TOOBIG_REG 0x010045 /* Regular file too big */
281#define PR_1_TOOBIG_SYMLINK 0x010046 /* Symlink too big */
282#define PR_1_HTREE_SET 0x010047 /* INDEX_FL flag set on a non-HTREE filesystem */
283#define PR_1_HTREE_NODIR 0x010048 /* INDEX_FL flag set on a non-directory */
284#define PR_1_HTREE_BADROOT 0x010049 /* Invalid root node in HTREE directory */
285#define PR_1_HTREE_HASHV 0x01004A /* Unsupported hash version in HTREE directory */
286#define PR_1_HTREE_INCOMPAT 0x01004B /* Incompatible flag in HTREE root node */
287#define PR_1_HTREE_DEPTH 0x01004C /* HTREE too deep */
288#define PR_1_BB_FS_BLOCK 0x01004D /* Bad block has indirect block that conflicts with filesystem block */
289#define PR_1_RESIZE_INODE_CREATE 0x01004E /* Resize inode failed */
290#define PR_1_EXTRA_ISIZE 0x01004F /* inode->i_size is too long */
291#define PR_1_ATTR_NAME_LEN 0x010050 /* attribute name is too long */
292#define PR_1_ATTR_VALUE_OFFSET 0x010051 /* wrong EA value offset */
293#define PR_1_ATTR_VALUE_BLOCK 0x010052 /* wrong EA blocknumber */
294#define PR_1_ATTR_VALUE_SIZE 0x010053 /* wrong EA value size */
295#define PR_1_ATTR_HASH 0x010054 /* wrong EA hash value */
296
297/*
298 * Pass 1b errors
299 */
300
301#define PR_1B_PASS_HEADER 0x011000 /* Pass 1B: Rescan for duplicate/bad blocks */
302#define PR_1B_DUP_BLOCK_HEADER 0x011001 /* Duplicate/bad block(s) header */
303#define PR_1B_DUP_BLOCK 0x011002 /* Duplicate/bad block(s) in inode */
304#define PR_1B_DUP_BLOCK_END 0x011003 /* Duplicate/bad block(s) end */
305#define PR_1B_ISCAN_ERROR 0x011004 /* Error while scanning inodes */
306#define PR_1B_ALLOCATE_IBITMAP_ERROR 0x011005 /* Error allocating inode bitmap */
307#define PR_1B_BLOCK_ITERATE 0x0110006 /* Error while iterating over blocks */
308#define PR_1B_ADJ_EA_REFCOUNT 0x0110007 /* Error adjusting EA refcount */
309#define PR_1C_PASS_HEADER 0x012000 /* Pass 1C: Scan directories for inodes with dup blocks. */
310#define PR_1D_PASS_HEADER 0x013000 /* Pass 1D: Reconciling duplicate blocks */
311#define PR_1D_DUP_FILE 0x013001 /* File has duplicate blocks */
312#define PR_1D_DUP_FILE_LIST 0x013002 /* List of files sharing duplicate blocks */
313#define PR_1D_SHARE_METADATA 0x013003 /* File sharing blocks with filesystem metadata */
314#define PR_1D_NUM_DUP_INODES 0x013004 /* Report of how many duplicate/bad inodes */
315#define PR_1D_DUP_BLOCKS_DEALT 0x013005 /* Duplicated blocks already reassigned or cloned. */
316#define PR_1D_CLONE_QUESTION 0x013006 /* Clone duplicate/bad blocks? */
317#define PR_1D_DELETE_QUESTION 0x013007 /* Delete file? */
318#define PR_1D_CLONE_ERROR 0x013008 /* Couldn't clone file (error) */
319
320/*
321 * Pass 2 errors
322 */
323
324#define PR_2_PASS_HEADER 0x020000 /* Pass 2: Checking directory structure */
325#define PR_2_BAD_INODE_DOT 0x020001 /* Bad inode number for '.' */
326#define PR_2_BAD_INO 0x020002 /* Directory entry has bad inode number */
327#define PR_2_UNUSED_INODE 0x020003 /* Directory entry has deleted or unused inode */
328#define PR_2_LINK_DOT 0x020004 /* Directry entry is link to '.' */
329#define PR_2_BB_INODE 0x020005 /* Directory entry points to inode now located in a bad block */
330#define PR_2_LINK_DIR 0x020006 /* Directory entry contains a link to a directory */
331#define PR_2_LINK_ROOT 0x020007 /* Directory entry contains a link to the root directry */
332#define PR_2_BAD_NAME 0x020008 /* Directory entry has illegal characters in its name */
333#define PR_2_MISSING_DOT 0x020009 /* Missing '.' in directory inode */
334#define PR_2_MISSING_DOT_DOT 0x02000A /* Missing '..' in directory inode */
335#define PR_2_1ST_NOT_DOT 0x02000B /* First entry in directory inode doesn't contain '.' */
336#define PR_2_2ND_NOT_DOT_DOT 0x02000C /* Second entry in directory inode doesn't contain '..' */
337#define PR_2_FADDR_ZERO 0x02000D /* i_faddr should be zero */
338#define PR_2_FILE_ACL_ZERO 0x02000E /* i_file_acl should be zero */
339#define PR_2_DIR_ACL_ZERO 0x02000F /* i_dir_acl should be zero */
340#define PR_2_FRAG_ZERO 0x020010 /* i_frag should be zero */
341#define PR_2_FSIZE_ZERO 0x020011 /* i_fsize should be zero */
342#define PR_2_BAD_MODE 0x020012 /* inode has bad mode */
343#define PR_2_DIR_CORRUPTED 0x020013 /* directory corrupted */
344#define PR_2_FILENAME_LONG 0x020014 /* filename too long */
345#define PR_2_DIRECTORY_HOLE 0x020015 /* Directory inode has a missing block (hole) */
346#define PR_2_DOT_NULL_TERM 0x020016 /* '.' is not NULL terminated */
347#define PR_2_DOT_DOT_NULL_TERM 0x020017 /* '..' is not NULL terminated */
348#define PR_2_BAD_CHAR_DEV 0x020018 /* Illegal character device in inode */
349#define PR_2_BAD_BLOCK_DEV 0x020019 /* Illegal block device in inode */
350#define PR_2_DUP_DOT 0x02001A /* Duplicate '.' entry */
351#define PR_2_DUP_DOT_DOT 0x02001B /* Duplicate '..' entry */
352#define PR_2_NO_DIRINFO 0x02001C /* Internal error: couldn't find dir_info */
353#define PR_2_FINAL_RECLEN 0x02001D /* Final rec_len is wrong */
354#define PR_2_ALLOCATE_ICOUNT 0x02001E /* Error allocating icount structure */
355#define PR_2_DBLIST_ITERATE 0x02001F /* Error iterating over directory blocks */
356#define PR_2_READ_DIRBLOCK 0x020020 /* Error reading directory block */
357#define PR_2_WRITE_DIRBLOCK 0x020021 /* Error writing directory block */
358#define PR_2_ALLOC_DIRBOCK 0x020022 /* Error allocating new directory block */
359#define PR_2_DEALLOC_INODE 0x020023 /* Error deallocating inode */
360#define PR_2_SPLIT_DOT 0x020024 /* Directory entry for '.' is big. Split? */
361#define PR_2_BAD_FIFO 0x020025 /* Illegal FIFO */
362#define PR_2_BAD_SOCKET 0x020026 /* Illegal socket */
363#define PR_2_SET_FILETYPE 0x020027 /* Directory filetype not set */
364#define PR_2_BAD_FILETYPE 0x020028 /* Directory filetype incorrect */
365#define PR_2_CLEAR_FILETYPE 0x020029 /* Directory filetype set when it shouldn't be */
366#define PR_2_NULL_NAME 0x020030 /* Directory filename can't be zero-length */
367#define PR_2_INVALID_SYMLINK 0x020031 /* Invalid symlink */
368#define PR_2_FILE_ACL_BAD 0x020032 /* i_file_acl (extended attribute) is bad */
369#define PR_2_FEATURE_LARGE_FILES 0x020033 /* Filesystem contains large files, but has no such flag in sb */
370#define PR_2_HTREE_NOTREF 0x020034 /* Node in HTREE directory not referenced */
371#define PR_2_HTREE_DUPREF 0x020035 /* Node in HTREE directory referenced twice */
372#define PR_2_HTREE_MIN_HASH 0x020036 /* Node in HTREE directory has bad min hash */
373#define PR_2_HTREE_MAX_HASH 0x020037 /* Node in HTREE directory has bad max hash */
374#define PR_2_HTREE_CLEAR 0x020038 /* Clear invalid HTREE directory */
375#define PR_2_HTREE_BADBLK 0x02003A /* Bad block in htree interior node */
376#define PR_2_ADJ_EA_REFCOUNT 0x02003B /* Error adjusting EA refcount */
377#define PR_2_HTREE_BAD_ROOT 0x02003C /* Invalid HTREE root node */
378#define PR_2_HTREE_BAD_LIMIT 0x02003D /* Invalid HTREE limit */
379#define PR_2_HTREE_BAD_COUNT 0x02003E /* Invalid HTREE count */
380#define PR_2_HTREE_HASH_ORDER 0x02003F /* HTREE interior node has out-of-order hashes in table */
381#define PR_2_HTREE_BAD_DEPTH 0x020040 /* Node in HTREE directory has bad depth */
382#define PR_2_DUPLICATE_DIRENT 0x020041 /* Duplicate directory entry found */
383#define PR_2_NON_UNIQUE_FILE 0x020042 /* Non-unique filename found */
384#define PR_2_REPORT_DUP_DIRENT 0x020043 /* Duplicate directory entry found */
385
386/*
387 * Pass 3 errors
388 */
389
390#define PR_3_PASS_HEADER 0x030000 /* Pass 3: Checking directory connectivity */
391#define PR_3_NO_ROOT_INODE 0x030001 /* Root inode not allocated */
392#define PR_3_EXPAND_LF_DIR 0x030002 /* No room in lost+found */
393#define PR_3_UNCONNECTED_DIR 0x030003 /* Unconnected directory inode */
394#define PR_3_NO_LF_DIR 0x030004 /* /lost+found not found */
395#define PR_3_BAD_DOT_DOT 0x030005 /* .. entry is incorrect */
396#define PR_3_NO_LPF 0x030006 /* Bad or non-existent /lost+found. Cannot reconnect */
397#define PR_3_CANT_EXPAND_LPF 0x030007 /* Could not expand /lost+found */
398#define PR_3_CANT_RECONNECT 0x030008 /* Could not reconnect inode */
399#define PR_3_ERR_FIND_LPF 0x030009 /* Error while trying to find /lost+found */
400#define PR_3_ERR_LPF_NEW_BLOCK 0x03000A /* Error in ext2fs_new_block while creating /lost+found */
401#define PR_3_ERR_LPF_NEW_INODE 0x03000B /* Error in ext2fs_new_inode while creating /lost+found */
402#define PR_3_ERR_LPF_NEW_DIR_BLOCK 0x03000C /* Error in ext2fs_new_dir_block while creating /lost+found */
403#define PR_3_ERR_LPF_WRITE_BLOCK 0x03000D /* Error while writing directory block for /lost+found */
404#define PR_3_ADJUST_INODE 0x03000E /* Error while adjusting inode count */
405#define PR_3_FIX_PARENT_ERR 0x03000F /* Couldn't fix parent directory -- error */
406#define PR_3_FIX_PARENT_NOFIND 0x030010 /* Couldn't fix parent directory -- couldn't find it */
407#define PR_3_ALLOCATE_IBITMAP_ERROR 0x030011 /* Error allocating inode bitmap */
408#define PR_3_CREATE_ROOT_ERROR 0x030012 /* Error creating root directory */
409#define PR_3_CREATE_LPF_ERROR 0x030013 /* Error creating lost and found directory */
410#define PR_3_ROOT_NOT_DIR_ABORT 0x030014 /* Root inode is not directory; aborting */
411#define PR_3_NO_ROOT_INODE_ABORT 0x030015 /* Cannot proceed without a root inode. */
412#define PR_3_NO_DIRINFO 0x030016 /* Internal error: couldn't find dir_info */
413#define PR_3_LPF_NOTDIR 0x030017 /* Lost+found is not a directory */
414
415/*
416 * Pass 3a --- rehashing diretories
417 */
418#define PR_3A_PASS_HEADER 0x031000 /* Pass 3a: Reindexing directories */
419#define PR_3A_OPTIMIZE_ITER 0x031001 /* Error iterating over directories */
420#define PR_3A_OPTIMIZE_DIR_ERR 0x031002 /* Error rehash directory */
421#define PR_3A_OPTIMIZE_DIR_HEADER 0x031003 /* Rehashing dir header */
422#define PR_3A_OPTIMIZE_DIR 0x031004 /* Rehashing directory %d */
423#define PR_3A_OPTIMIZE_DIR_END 0x031005 /* Rehashing dir end */
424
425/*
426 * Pass 4 errors
427 */
428
429#define PR_4_PASS_HEADER 0x040000 /* Pass 4: Checking reference counts */
430#define PR_4_ZERO_LEN_INODE 0x040001 /* Unattached zero-length inode */
431#define PR_4_UNATTACHED_INODE 0x040002 /* Unattached inode */
432#define PR_4_BAD_REF_COUNT 0x040003 /* Inode ref count wrong */
433#define PR_4_INCONSISTENT_COUNT 0x040004 /* Inconsistent inode count information cached */
434
435/*
436 * Pass 5 errors
437 */
438
439#define PR_5_PASS_HEADER 0x050000 /* Pass 5: Checking group summary information */
440#define PR_5_INODE_BMAP_PADDING 0x050001 /* Padding at end of inode bitmap is not set. */
441#define PR_5_BLOCK_BMAP_PADDING 0x050002 /* Padding at end of block bitmap is not set. */
442#define PR_5_BLOCK_BITMAP_HEADER 0x050003 /* Block bitmap differences header */
443#define PR_5_BLOCK_UNUSED 0x050004 /* Block not used, but marked in bitmap */
444#define PR_5_BLOCK_USED 0x050005 /* Block used, but not marked used in bitmap */
445#define PR_5_BLOCK_BITMAP_END 0x050006 /* Block bitmap differences end */
446#define PR_5_INODE_BITMAP_HEADER 0x050007 /* Inode bitmap differences header */
447#define PR_5_INODE_UNUSED 0x050008 /* Inode not used, but marked in bitmap */
448#define PR_5_INODE_USED 0x050009 /* Inode used, but not marked used in bitmap */
449#define PR_5_INODE_BITMAP_END 0x05000A /* Inode bitmap differences end */
450#define PR_5_FREE_INODE_COUNT_GROUP 0x05000B /* Free inodes count for group wrong */
451#define PR_5_FREE_DIR_COUNT_GROUP 0x05000C /* Directories count for group wrong */
452#define PR_5_FREE_INODE_COUNT 0x05000D /* Free inodes count wrong */
453#define PR_5_FREE_BLOCK_COUNT_GROUP 0x05000E /* Free blocks count for group wrong */
454#define PR_5_FREE_BLOCK_COUNT 0x05000F /* Free blocks count wrong */
455#define PR_5_BMAP_ENDPOINTS 0x050010 /* Programming error: bitmap endpoints don't match */
456#define PR_5_FUDGE_BITMAP_ERROR 0x050011 /* Internal error: fudging end of bitmap */
457#define PR_5_COPY_IBITMAP_ERROR 0x050012 /* Error copying in replacement inode bitmap */
458#define PR_5_COPY_BBITMAP_ERROR 0x050013 /* Error copying in replacement block bitmap */
459#define PR_5_BLOCK_RANGE_UNUSED 0x050014 /* Block range not used, but marked in bitmap */
460#define PR_5_BLOCK_RANGE_USED 0x050015 /* Block range used, but not marked used in bitmap */
461#define PR_5_INODE_RANGE_UNUSED 0x050016 /* Inode range not used, but marked in bitmap */
462#define PR_5_INODE_RANGE_USED 0x050017 /* Inode rangeused, but not marked used in bitmap */
463
464
465/*
466 * The directory information structure; stores directory information
467 * collected in earlier passes, to avoid disk i/o in fetching the
468 * directory information.
469 */
470struct dir_info {
471 ext2_ino_t ino; /* Inode number */
472 ext2_ino_t dotdot; /* Parent according to '..' */
473 ext2_ino_t parent; /* Parent according to treewalk */
474};
475
476
477
478/*
479 * The indexed directory information structure; stores information for
480 * directories which contain a hash tree index.
481 */
482struct dx_dir_info {
483 ext2_ino_t ino; /* Inode number */
484 int numblocks; /* number of blocks */
485 int hashversion;
486 short depth; /* depth of tree */
487 struct dx_dirblock_info *dx_block; /* Array of size numblocks */
488};
489
490/*
491 * Define the extended attribute refcount structure
492 */
493typedef struct ea_refcount *ext2_refcount_t;
494
495struct e2fsck_struct {
496 ext2_filsys fs;
497 const char *program_name;
498 char *filesystem_name;
499 char *device_name;
500 char *io_options;
501 int flags; /* E2fsck internal flags */
502 int options;
503 blk_t use_superblock; /* sb requested by user */
504 blk_t superblock; /* sb used to open fs */
505 int blocksize; /* blocksize */
506 blk_t num_blocks; /* Total number of blocks */
507 int mount_flags;
508 blkid_cache blkid; /* blkid cache */
509
510 jmp_buf abort_loc;
511
512 unsigned long abort_code;
513
514 int (*progress)(e2fsck_t ctx, int pass, unsigned long cur,
515 unsigned long max);
516
517 ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */
518 ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
519 ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
520 ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
521 ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
522
523 ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
524 ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */
525 ext2fs_block_bitmap block_ea_map; /* Blocks which are used by EA's */
526
527 /*
528 * Inode count arrays
529 */
530 ext2_icount_t inode_count;
531 ext2_icount_t inode_link_info;
532
533 ext2_refcount_t refcount;
534 ext2_refcount_t refcount_extra;
535
536 /*
537 * Array of flags indicating whether an inode bitmap, block
538 * bitmap, or inode table is invalid
539 */
540 int *invalid_inode_bitmap_flag;
541 int *invalid_block_bitmap_flag;
542 int *invalid_inode_table_flag;
543 int invalid_bitmaps; /* There are invalid bitmaps/itable */
544
545 /*
546 * Block buffer
547 */
548 char *block_buf;
549
550 /*
551 * For pass1_check_directory and pass1_get_blocks
552 */
553 ext2_ino_t stashed_ino;
554 struct ext2_inode *stashed_inode;
555
556 /*
557 * Location of the lost and found directory
558 */
559 ext2_ino_t lost_and_found;
560 int bad_lost_and_found;
561
562 /*
563 * Directory information
564 */
565 int dir_info_count;
566 int dir_info_size;
567 struct dir_info *dir_info;
568
569 /*
570 * Indexed directory information
571 */
572 int dx_dir_info_count;
573 int dx_dir_info_size;
574 struct dx_dir_info *dx_dir_info;
575
576 /*
577 * Directories to hash
578 */
579 ext2_u32_list dirs_to_hash;
580
581 /*
582 * Tuning parameters
583 */
584 int process_inode_size;
585 int inode_buffer_blocks;
586
587 /*
588 * ext3 journal support
589 */
590 io_channel journal_io;
591 char *journal_name;
592
593 /*
594 * How we display the progress update (for unix)
595 */
596 int progress_fd;
597 int progress_pos;
598 int progress_last_percent;
599 unsigned int progress_last_time;
600 int interactive; /* Are we connected directly to a tty? */
601 char start_meta[2], stop_meta[2];
602
603 /* File counts */
604 int fs_directory_count;
605 int fs_regular_count;
606 int fs_blockdev_count;
607 int fs_chardev_count;
608 int fs_links_count;
609 int fs_symlinks_count;
610 int fs_fast_symlinks_count;
611 int fs_fifo_count;
612 int fs_total_count;
613 int fs_sockets_count;
614 int fs_ind_count;
615 int fs_dind_count;
616 int fs_tind_count;
617 int fs_fragmented;
618 int large_files;
619 int fs_ext_attr_inodes;
620 int fs_ext_attr_blocks;
621
622 int ext_attr_ver;
623
624 /*
625 * For the use of callers of the e2fsck functions; not used by
626 * e2fsck functions themselves.
627 */
628 void *priv_data;
629};
630
631
632#define tid_gt(x, y) ((x - y) > 0)
633
634static inline int tid_geq(tid_t x, tid_t y)
635{
636 int difference = (x - y);
637 return (difference >= 0);
638}
639
640
diff --git a/e2fsprogs/old_e2fsprogs/e2p/Kbuild b/e2fsprogs/old_e2fsprogs/e2p/Kbuild
new file mode 100644
index 000000000..c0ff824e3
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/Kbuild
@@ -0,0 +1,15 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7NEEDED-$(CONFIG_CHATTR) = y
8NEEDED-$(CONFIG_LSATTR) = y
9NEEDED-$(CONFIG_MKE2FS) = y
10NEEDED-$(CONFIG_TUNE2FS) = y
11
12lib-y:=
13lib-$(NEEDED-y) += fgetsetflags.o fgetsetversion.o pf.o iod.o mntopts.o \
14 feature.o ls.o uuid.o pe.o ostype.o ps.o hashstr.o \
15 parse_num.o
diff --git a/e2fsprogs/old_e2fsprogs/e2p/e2p.h b/e2fsprogs/old_e2fsprogs/e2p/e2p.h
new file mode 100644
index 000000000..2a2367b9f
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/e2p.h
@@ -0,0 +1,64 @@
1/* vi: set sw=4 ts=4: */
2#include "busybox.h"
3#include <sys/types.h> /* Needed by dirent.h on netbsd */
4#include <stdio.h>
5#include <dirent.h>
6
7#include "../ext2fs/ext2_fs.h"
8
9#define E2P_FEATURE_COMPAT 0
10#define E2P_FEATURE_INCOMPAT 1
11#define E2P_FEATURE_RO_INCOMPAT 2
12#ifndef EXT3_FEATURE_INCOMPAT_EXTENTS
13#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
14#endif
15
16/* `options' for print_flags() */
17
18#define PFOPT_LONG 1 /* Must be 1 for compatibility with `int long_format'. */
19
20/*int fgetversion (const char * name, unsigned long * version);*/
21/*int fsetversion (const char * name, unsigned long version);*/
22int fgetsetversion(const char * name, unsigned long * get_version, unsigned long set_version);
23#define fgetversion(name, version) fgetsetversion(name, version, 0)
24#define fsetversion(name, version) fgetsetversion(name, NULL, version)
25
26/*int fgetflags (const char * name, unsigned long * flags);*/
27/*int fsetflags (const char * name, unsigned long flags);*/
28int fgetsetflags(const char * name, unsigned long * get_flags, unsigned long set_flags);
29#define fgetflags(name, flags) fgetsetflags(name, flags, 0)
30#define fsetflags(name, flags) fgetsetflags(name, NULL, flags)
31
32int getflags (int fd, unsigned long * flags);
33int getversion (int fd, unsigned long * version);
34int iterate_on_dir (const char * dir_name,
35 int (*func) (const char *, struct dirent *, void *),
36 void * private);
37/*void list_super(struct ext2_super_block * s);*/
38void list_super2(struct ext2_super_block * s, FILE *f);
39#define list_super(s) list_super2(s, stdout)
40void print_fs_errors (FILE * f, unsigned short errors);
41void print_flags (FILE * f, unsigned long flags, unsigned options);
42void print_fs_state (FILE * f, unsigned short state);
43int setflags (int fd, unsigned long flags);
44int setversion (int fd, unsigned long version);
45
46const char *e2p_feature2string(int compat, unsigned int mask);
47int e2p_string2feature(char *string, int *compat, unsigned int *mask);
48int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array);
49
50int e2p_is_null_uuid(void *uu);
51void e2p_uuid_to_str(void *uu, char *out);
52const char *e2p_uuid2str(void *uu);
53
54const char *e2p_hash2string(int num);
55int e2p_string2hash(char *string);
56
57const char *e2p_mntopt2string(unsigned int mask);
58int e2p_string2mntopt(char *string, unsigned int *mask);
59int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok);
60
61unsigned long parse_num_blocks(const char *arg, int log_block_size);
62
63char *e2p_os2string(int os_type);
64int e2p_string2os(char *str);
diff --git a/e2fsprogs/old_e2fsprogs/e2p/feature.c b/e2fsprogs/old_e2fsprogs/e2p/feature.c
new file mode 100644
index 000000000..b45754f97
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/feature.c
@@ -0,0 +1,187 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * feature.c --- convert between features and strings
4 *
5 * Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
6 *
7 * This file can be redistributed under the terms of the GNU Library General
8 * Public License
9 *
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <ctype.h>
16#include <errno.h>
17
18#include "e2p.h"
19
20struct feature {
21 int compat;
22 unsigned int mask;
23 const char *string;
24};
25
26static const struct feature feature_list[] = {
27 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,
28 "dir_prealloc" },
29 { E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,
30 "has_journal" },
31 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,
32 "imagic_inodes" },
33 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,
34 "ext_attr" },
35 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,
36 "dir_index" },
37 { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
38 "resize_inode" },
39 { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
40 "sparse_super" },
41 { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
42 "large_file" },
43 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
44 "compression" },
45 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
46 "filetype" },
47 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,
48 "needs_recovery" },
49 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
50 "journal_dev" },
51 { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
52 "extents" },
53 { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
54 "meta_bg" },
55 { 0, 0, 0 },
56};
57
58const char *e2p_feature2string(int compat, unsigned int mask)
59{
60 const struct feature *f;
61 static char buf[20];
62 char fchar;
63 int fnum;
64
65 for (f = feature_list; f->string; f++) {
66 if ((compat == f->compat) &&
67 (mask == f->mask))
68 return f->string;
69 }
70 switch (compat) {
71 case E2P_FEATURE_COMPAT:
72 fchar = 'C';
73 break;
74 case E2P_FEATURE_INCOMPAT:
75 fchar = 'I';
76 break;
77 case E2P_FEATURE_RO_INCOMPAT:
78 fchar = 'R';
79 break;
80 default:
81 fchar = '?';
82 break;
83 }
84 for (fnum = 0; mask >>= 1; fnum++);
85 sprintf(buf, "FEATURE_%c%d", fchar, fnum);
86 return buf;
87}
88
89int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
90{
91 const struct feature *f;
92 char *eptr;
93 int num;
94
95 for (f = feature_list; f->string; f++) {
96 if (!strcasecmp(string, f->string)) {
97 *compat_type = f->compat;
98 *mask = f->mask;
99 return 0;
100 }
101 }
102 if (strncasecmp(string, "FEATURE_", 8))
103 return 1;
104
105 switch (string[8]) {
106 case 'c':
107 case 'C':
108 *compat_type = E2P_FEATURE_COMPAT;
109 break;
110 case 'i':
111 case 'I':
112 *compat_type = E2P_FEATURE_INCOMPAT;
113 break;
114 case 'r':
115 case 'R':
116 *compat_type = E2P_FEATURE_RO_INCOMPAT;
117 break;
118 default:
119 return 1;
120 }
121 if (string[9] == 0)
122 return 1;
123 num = strtol(string+9, &eptr, 10);
124 if (num > 32 || num < 0)
125 return 1;
126 if (*eptr)
127 return 1;
128 *mask = 1 << num;
129 return 0;
130}
131
132static inline char *skip_over_blanks(char *cp)
133{
134 while (*cp && isspace(*cp))
135 cp++;
136 return cp;
137}
138
139static inline char *skip_over_word(char *cp)
140{
141 while (*cp && !isspace(*cp) && *cp != ',')
142 cp++;
143 return cp;
144}
145
146/*
147 * Edit a feature set array as requested by the user. The ok_array,
148 * if set, allows the application to limit what features the user is
149 * allowed to set or clear using this function.
150 */
151int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
152{
153 char *cp, *buf, *next;
154 int neg;
155 unsigned int mask;
156 int compat_type;
157
158 buf = xstrdup(str);
159 cp = buf;
160 while (cp && *cp) {
161 neg = 0;
162 cp = skip_over_blanks(cp);
163 next = skip_over_word(cp);
164 if (*next == 0)
165 next = 0;
166 else
167 *next = 0;
168 switch (*cp) {
169 case '-':
170 case '^':
171 neg++;
172 case '+':
173 cp++;
174 break;
175 }
176 if (e2p_string2feature(cp, &compat_type, &mask))
177 return 1;
178 if (ok_array && !(ok_array[compat_type] & mask))
179 return 1;
180 if (neg)
181 compat_array[compat_type] &= ~mask;
182 else
183 compat_array[compat_type] |= mask;
184 cp = next ? next+1 : 0;
185 }
186 return 0;
187}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/fgetsetflags.c b/e2fsprogs/old_e2fsprogs/e2p/fgetsetflags.c
new file mode 100644
index 000000000..008b79850
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/fgetsetflags.c
@@ -0,0 +1,70 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fgetflags.c - Get a file flags on an ext2 file system
4 * fsetflags.c - Set a file flags on an ext2 file system
5 *
6 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
7 * Laboratoire MASI, Institut Blaise Pascal
8 * Universite Pierre et Marie Curie (Paris VI)
9 *
10 * This file can be redistributed under the terms of the GNU Library General
11 * Public License
12 */
13
14/*
15 * History:
16 * 93/10/30 - Creation
17 */
18
19#ifdef HAVE_ERRNO_H
20#include <errno.h>
21#endif
22#ifdef HAVE_UNISTD_H
23#include <unistd.h>
24#endif
25#include <sys/types.h>
26#include <sys/stat.h>
27#ifdef HAVE_EXT2_IOCTLS
28#include <fcntl.h>
29#include <sys/ioctl.h>
30#endif
31
32#include "e2p.h"
33
34#ifdef O_LARGEFILE
35#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE)
36#else
37#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK)
38#endif
39
40int fgetsetflags (const char * name, unsigned long * get_flags, unsigned long set_flags)
41{
42#ifdef HAVE_EXT2_IOCTLS
43 struct stat buf;
44 int fd, r, f, save_errno = 0;
45
46 if (!stat(name, &buf) &&
47 !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) {
48 goto notsupp;
49 }
50 fd = open (name, OPEN_FLAGS);
51 if (fd == -1)
52 return -1;
53 if (!get_flags) {
54 f = (int) set_flags;
55 r = ioctl (fd, EXT2_IOC_SETFLAGS, &f);
56 } else {
57 r = ioctl (fd, EXT2_IOC_GETFLAGS, &f);
58 *get_flags = f;
59 }
60 if (r == -1)
61 save_errno = errno;
62 close (fd);
63 if (save_errno)
64 errno = save_errno;
65 return r;
66notsupp:
67#endif /* HAVE_EXT2_IOCTLS */
68 errno = EOPNOTSUPP;
69 return -1;
70}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/fgetsetversion.c b/e2fsprogs/old_e2fsprogs/e2p/fgetsetversion.c
new file mode 100644
index 000000000..8d79054d6
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/fgetsetversion.c
@@ -0,0 +1,70 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fgetversion.c - Get a file version on an ext2 file system
4 * fsetversion.c - Set a file version on an ext2 file system
5 *
6 *
7 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
8 * Laboratoire MASI, Institut Blaise Pascal
9 * Universite Pierre et Marie Curie (Paris VI)
10 *
11 * This file can be redistributed under the terms of the GNU Library General
12 * Public License
13 */
14
15/*
16 * History:
17 * 93/10/30 - Creation
18 */
19
20#ifdef HAVE_ERRNO_H
21#include <errno.h>
22#endif
23#ifdef HAVE_UNISTD_H
24#include <unistd.h>
25#endif
26#include <fcntl.h>
27#include <sys/ioctl.h>
28
29#include "e2p.h"
30
31#ifdef O_LARGEFILE
32#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE)
33#else
34#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK)
35#endif
36
37/*
38 To do fsetversion: unsigned long *ptr_version must be set to NULL.
39 and unsigned long version must be set to a value
40 To do fgetversion: unsigned long *ptr_version must NOT be set to NULL
41 and unsigned long version is ignored.
42 TITO.
43*/
44
45int fgetsetversion (const char * name, unsigned long * get_version, unsigned long set_version)
46{
47#ifdef HAVE_EXT2_IOCTLS
48 int fd, r, ver, save_errno = 0;
49
50 fd = open (name, OPEN_FLAGS);
51 if (fd == -1)
52 return -1;
53 if (!get_version) {
54 ver = (int) set_version;
55 r = ioctl (fd, EXT2_IOC_SETVERSION, &ver);
56 } else {
57 r = ioctl (fd, EXT2_IOC_GETVERSION, &ver);
58 *get_version = ver;
59 }
60 if (r == -1)
61 save_errno = errno;
62 close (fd);
63 if (save_errno)
64 errno = save_errno;
65 return r;
66#else /* ! HAVE_EXT2_IOCTLS */
67 errno = EOPNOTSUPP;
68 return -1;
69#endif /* ! HAVE_EXT2_IOCTLS */
70}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/hashstr.c b/e2fsprogs/old_e2fsprogs/e2p/hashstr.c
new file mode 100644
index 000000000..697ffadc3
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/hashstr.c
@@ -0,0 +1,70 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * feature.c --- convert between features and strings
4 *
5 * Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu>
6 *
7 * This file can be redistributed under the terms of the GNU Library General
8 * Public License
9 *
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <ctype.h>
16#include <errno.h>
17
18#include "e2p.h"
19
20struct hash {
21 int num;
22 const char *string;
23};
24
25static const struct hash hash_list[] = {
26 { EXT2_HASH_LEGACY, "legacy" },
27 { EXT2_HASH_HALF_MD4, "half_md4" },
28 { EXT2_HASH_TEA, "tea" },
29 { 0, 0 },
30};
31
32const char *e2p_hash2string(int num)
33{
34 const struct hash *p;
35 static char buf[20];
36
37 for (p = hash_list; p->string; p++) {
38 if (num == p->num)
39 return p->string;
40 }
41 sprintf(buf, "HASHALG_%d", num);
42 return buf;
43}
44
45/*
46 * Returns the hash algorithm, or -1 on error
47 */
48int e2p_string2hash(char *string)
49{
50 const struct hash *p;
51 char *eptr;
52 int num;
53
54 for (p = hash_list; p->string; p++) {
55 if (!strcasecmp(string, p->string)) {
56 return p->num;
57 }
58 }
59 if (strncasecmp(string, "HASHALG_", 8))
60 return -1;
61
62 if (string[8] == 0)
63 return -1;
64 num = strtol(string+8, &eptr, 10);
65 if (num > 255 || num < 0)
66 return -1;
67 if (*eptr)
68 return -1;
69 return num;
70}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/iod.c b/e2fsprogs/old_e2fsprogs/e2p/iod.c
new file mode 100644
index 000000000..23ab8d5b5
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/iod.c
@@ -0,0 +1,52 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * iod.c - Iterate a function on each entry of a directory
4 *
5 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * This file can be redistributed under the terms of the GNU Library General
10 * Public License
11 */
12
13/*
14 * History:
15 * 93/10/30 - Creation
16 */
17
18#include "e2p.h"
19#include <unistd.h>
20#include <stdlib.h>
21#include <string.h>
22
23int iterate_on_dir (const char * dir_name,
24 int (*func) (const char *, struct dirent *, void *),
25 void * private)
26{
27 DIR * dir;
28 struct dirent *de, *dep;
29 int max_len, len;
30
31 max_len = PATH_MAX + sizeof(struct dirent);
32 de = xmalloc(max_len+1);
33 memset(de, 0, max_len+1);
34
35 dir = opendir (dir_name);
36 if (dir == NULL) {
37 free(de);
38 return -1;
39 }
40 while ((dep = readdir (dir))) {
41 len = sizeof(struct dirent);
42 if (len < dep->d_reclen)
43 len = dep->d_reclen;
44 if (len > max_len)
45 len = max_len;
46 memcpy(de, dep, len);
47 (*func) (dir_name, de, private);
48 }
49 free(de);
50 closedir(dir);
51 return 0;
52}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/ls.c b/e2fsprogs/old_e2fsprogs/e2p/ls.c
new file mode 100644
index 000000000..9d29db6af
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/ls.c
@@ -0,0 +1,273 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ls.c - List the contents of an ext2fs superblock
4 *
5 * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * Copyright (C) 1995, 1996, 1997 Theodore Ts'o <tytso@mit.edu>
10 *
11 * This file can be redistributed under the terms of the GNU Library General
12 * Public License
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <sys/types.h>
18#include <string.h>
19#include <grp.h>
20#include <pwd.h>
21#include <time.h>
22
23#include "e2p.h"
24
25static void print_user(unsigned short uid, FILE *f)
26{
27 struct passwd *pw = getpwuid(uid);
28 fprintf(f, "%u (user %s)\n", uid,
29 (pw == NULL ? "unknown" : pw->pw_name));
30}
31
32static void print_group(unsigned short gid, FILE *f)
33{
34 struct group *gr = getgrgid(gid);
35 fprintf(f, "%u (group %s)\n", gid,
36 (gr == NULL ? "unknown" : gr->gr_name));
37}
38
39#define MONTH_INT (86400 * 30)
40#define WEEK_INT (86400 * 7)
41#define DAY_INT (86400)
42#define HOUR_INT (60 * 60)
43#define MINUTE_INT (60)
44
45static const char *interval_string(unsigned int secs)
46{
47 static char buf[256], tmp[80];
48 int hr, min, num;
49
50 buf[0] = 0;
51
52 if (secs == 0)
53 return "<none>";
54
55 if (secs >= MONTH_INT) {
56 num = secs / MONTH_INT;
57 secs -= num*MONTH_INT;
58 sprintf(buf, "%d month%s", num, (num>1) ? "s" : "");
59 }
60 if (secs >= WEEK_INT) {
61 num = secs / WEEK_INT;
62 secs -= num*WEEK_INT;
63 sprintf(tmp, "%s%d week%s", buf[0] ? ", " : "",
64 num, (num>1) ? "s" : "");
65 strcat(buf, tmp);
66 }
67 if (secs >= DAY_INT) {
68 num = secs / DAY_INT;
69 secs -= num*DAY_INT;
70 sprintf(tmp, "%s%d day%s", buf[0] ? ", " : "",
71 num, (num>1) ? "s" : "");
72 strcat(buf, tmp);
73 }
74 if (secs > 0) {
75 hr = secs / HOUR_INT;
76 secs -= hr*HOUR_INT;
77 min = secs / MINUTE_INT;
78 secs -= min*MINUTE_INT;
79 sprintf(tmp, "%s%d:%02d:%02d", buf[0] ? ", " : "",
80 hr, min, secs);
81 strcat(buf, tmp);
82 }
83 return buf;
84}
85
86static void print_features(struct ext2_super_block * s, FILE *f)
87{
88#ifdef EXT2_DYNAMIC_REV
89 int i, j, printed=0;
90 __u32 *mask = &s->s_feature_compat, m;
91
92 fprintf(f, "Filesystem features: ");
93 for (i=0; i <3; i++,mask++) {
94 for (j=0,m=1; j < 32; j++, m<<=1) {
95 if (*mask & m) {
96 fprintf(f, " %s", e2p_feature2string(i, m));
97 printed++;
98 }
99 }
100 }
101 if (printed == 0)
102 fprintf(f, " (none)");
103 fprintf(f, "\n");
104#endif
105}
106
107static void print_mntopts(struct ext2_super_block * s, FILE *f)
108{
109#ifdef EXT2_DYNAMIC_REV
110 int i, printed=0;
111 __u32 mask = s->s_default_mount_opts, m;
112
113 fprintf(f, "Default mount options: ");
114 if (mask & EXT3_DEFM_JMODE) {
115 fprintf(f, " %s", e2p_mntopt2string(mask & EXT3_DEFM_JMODE));
116 printed++;
117 }
118 for (i=0,m=1; i < 32; i++, m<<=1) {
119 if (m & EXT3_DEFM_JMODE)
120 continue;
121 if (mask & m) {
122 fprintf(f, " %s", e2p_mntopt2string(m));
123 printed++;
124 }
125 }
126 if (printed == 0)
127 fprintf(f, " (none)");
128 fprintf(f, "\n");
129#endif
130}
131
132
133#ifndef EXT2_INODE_SIZE
134#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode)
135#endif
136
137#ifndef EXT2_GOOD_OLD_REV
138#define EXT2_GOOD_OLD_REV 0
139#endif
140
141void list_super2(struct ext2_super_block * sb, FILE *f)
142{
143 int inode_blocks_per_group;
144 char buf[80], *str;
145 time_t tm;
146
147 inode_blocks_per_group = (((sb->s_inodes_per_group *
148 EXT2_INODE_SIZE(sb)) +
149 EXT2_BLOCK_SIZE(sb) - 1) /
150 EXT2_BLOCK_SIZE(sb));
151 if (sb->s_volume_name[0]) {
152 memset(buf, 0, sizeof(buf));
153 strncpy(buf, sb->s_volume_name, sizeof(sb->s_volume_name));
154 } else
155 strcpy(buf, "<none>");
156 fprintf(f, "Filesystem volume name: %s\n", buf);
157 if (sb->s_last_mounted[0]) {
158 memset(buf, 0, sizeof(buf));
159 strncpy(buf, sb->s_last_mounted, sizeof(sb->s_last_mounted));
160 } else
161 strcpy(buf, "<not available>");
162 fprintf(f,
163 "Last mounted on: %s\n"
164 "Filesystem UUID: %s\n"
165 "Filesystem magic number: 0x%04X\n"
166 "Filesystem revision #: %d",
167 buf, e2p_uuid2str(sb->s_uuid), sb->s_magic, sb->s_rev_level);
168 if (sb->s_rev_level == EXT2_GOOD_OLD_REV) {
169 fprintf(f, " (original)\n");
170#ifdef EXT2_DYNAMIC_REV
171 } else if (sb->s_rev_level == EXT2_DYNAMIC_REV) {
172 fprintf(f, " (dynamic)\n");
173#endif
174 } else
175 fprintf(f, " (unknown)\n");
176 print_features(sb, f);
177 print_mntopts(sb, f);
178 fprintf(f, "Filesystem state: ");
179 print_fs_state (f, sb->s_state);
180 fprintf(f, "\nErrors behavior: ");
181 print_fs_errors(f, sb->s_errors);
182 str = e2p_os2string(sb->s_creator_os);
183 fprintf(f,
184 "\n"
185 "Filesystem OS type: %s\n"
186 "Inode count: %u\n"
187 "Block count: %u\n"
188 "Reserved block count: %u\n"
189 "Free blocks: %u\n"
190 "Free inodes: %u\n"
191 "First block: %u\n"
192 "Block size: %u\n"
193 "Fragment size: %u\n",
194 str, sb->s_inodes_count, sb->s_blocks_count, sb->s_r_blocks_count,
195 sb->s_free_blocks_count, sb->s_free_inodes_count,
196 sb->s_first_data_block, EXT2_BLOCK_SIZE(sb), EXT2_FRAG_SIZE(sb));
197 free(str);
198 if (sb->s_reserved_gdt_blocks)
199 fprintf(f, "Reserved GDT blocks: %u\n",
200 sb->s_reserved_gdt_blocks);
201 fprintf(f,
202 "Blocks per group: %u\n"
203 "Fragments per group: %u\n"
204 "Inodes per group: %u\n"
205 "Inode blocks per group: %u\n",
206 sb->s_blocks_per_group, sb->s_frags_per_group,
207 sb->s_inodes_per_group, inode_blocks_per_group);
208 if (sb->s_first_meta_bg)
209 fprintf(f, "First meta block group: %u\n",
210 sb->s_first_meta_bg);
211 if (sb->s_mkfs_time) {
212 tm = sb->s_mkfs_time;
213 fprintf(f, "Filesystem created: %s", ctime(&tm));
214 }
215 tm = sb->s_mtime;
216 fprintf(f, "Last mount time: %s",
217 sb->s_mtime ? ctime(&tm) : "n/a\n");
218 tm = sb->s_wtime;
219 fprintf(f,
220 "Last write time: %s"
221 "Mount count: %u\n"
222 "Maximum mount count: %d\n",
223 ctime(&tm), sb->s_mnt_count, sb->s_max_mnt_count);
224 tm = sb->s_lastcheck;
225 fprintf(f,
226 "Last checked: %s"
227 "Check interval: %u (%s)\n",
228 ctime(&tm),
229 sb->s_checkinterval, interval_string(sb->s_checkinterval));
230 if (sb->s_checkinterval)
231 {
232 time_t next;
233
234 next = sb->s_lastcheck + sb->s_checkinterval;
235 fprintf(f, "Next check after: %s", ctime(&next));
236 }
237 fprintf(f, "Reserved blocks uid: ");
238 print_user(sb->s_def_resuid, f);
239 fprintf(f, "Reserved blocks gid: ");
240 print_group(sb->s_def_resgid, f);
241 if (sb->s_rev_level >= EXT2_DYNAMIC_REV) {
242 fprintf(f,
243 "First inode: %d\n"
244 "Inode size: %d\n",
245 sb->s_first_ino, sb->s_inode_size);
246 }
247 if (!e2p_is_null_uuid(sb->s_journal_uuid))
248 fprintf(f, "Journal UUID: %s\n",
249 e2p_uuid2str(sb->s_journal_uuid));
250 if (sb->s_journal_inum)
251 fprintf(f, "Journal inode: %u\n",
252 sb->s_journal_inum);
253 if (sb->s_journal_dev)
254 fprintf(f, "Journal device: 0x%04x\n",
255 sb->s_journal_dev);
256 if (sb->s_last_orphan)
257 fprintf(f, "First orphan inode: %u\n",
258 sb->s_last_orphan);
259 if ((sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
260 sb->s_def_hash_version)
261 fprintf(f, "Default directory hash: %s\n",
262 e2p_hash2string(sb->s_def_hash_version));
263 if (!e2p_is_null_uuid(sb->s_hash_seed))
264 fprintf(f, "Directory Hash Seed: %s\n",
265 e2p_uuid2str(sb->s_hash_seed));
266 if (sb->s_jnl_backup_type) {
267 fprintf(f, "Journal backup: ");
268 if (sb->s_jnl_backup_type == 1)
269 fprintf(f, "inode blocks\n");
270 else
271 fprintf(f, "type %u\n", sb->s_jnl_backup_type);
272 }
273}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/mntopts.c b/e2fsprogs/old_e2fsprogs/e2p/mntopts.c
new file mode 100644
index 000000000..17c26c480
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/mntopts.c
@@ -0,0 +1,134 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mountopts.c --- convert between default mount options and strings
4 *
5 * Copyright (C) 2002 Theodore Ts'o <tytso@mit.edu>
6 *
7 * This file can be redistributed under the terms of the GNU Library General
8 * Public License
9 *
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <ctype.h>
16#include <errno.h>
17
18#include "e2p.h"
19
20struct mntopt {
21 unsigned int mask;
22 const char *string;
23};
24
25static const struct mntopt mntopt_list[] = {
26 { EXT2_DEFM_DEBUG, "debug" },
27 { EXT2_DEFM_BSDGROUPS, "bsdgroups" },
28 { EXT2_DEFM_XATTR_USER, "user_xattr" },
29 { EXT2_DEFM_ACL, "acl" },
30 { EXT2_DEFM_UID16, "uid16" },
31 { EXT3_DEFM_JMODE_DATA, "journal_data" },
32 { EXT3_DEFM_JMODE_ORDERED, "journal_data_ordered" },
33 { EXT3_DEFM_JMODE_WBACK, "journal_data_writeback" },
34 { 0, 0 },
35};
36
37const char *e2p_mntopt2string(unsigned int mask)
38{
39 const struct mntopt *f;
40 static char buf[20];
41 int fnum;
42
43 for (f = mntopt_list; f->string; f++) {
44 if (mask == f->mask)
45 return f->string;
46 }
47 for (fnum = 0; mask >>= 1; fnum++);
48 sprintf(buf, "MNTOPT_%d", fnum);
49 return buf;
50}
51
52int e2p_string2mntopt(char *string, unsigned int *mask)
53{
54 const struct mntopt *f;
55 char *eptr;
56 int num;
57
58 for (f = mntopt_list; f->string; f++) {
59 if (!strcasecmp(string, f->string)) {
60 *mask = f->mask;
61 return 0;
62 }
63 }
64 if (strncasecmp(string, "MNTOPT_", 8))
65 return 1;
66
67 if (string[8] == 0)
68 return 1;
69 num = strtol(string+8, &eptr, 10);
70 if (num > 32 || num < 0)
71 return 1;
72 if (*eptr)
73 return 1;
74 *mask = 1 << num;
75 return 0;
76}
77
78static char *skip_over_blanks(char *cp)
79{
80 while (*cp && isspace(*cp))
81 cp++;
82 return cp;
83}
84
85static char *skip_over_word(char *cp)
86{
87 while (*cp && !isspace(*cp) && *cp != ',')
88 cp++;
89 return cp;
90}
91
92/*
93 * Edit a mntopt set array as requested by the user. The ok
94 * parameter, if non-zero, allows the application to limit what
95 * mntopts the user is allowed to set or clear using this function.
96 */
97int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok)
98{
99 char *cp, *buf, *next;
100 int neg;
101 unsigned int mask;
102
103 buf = xstrdup(str);
104 cp = buf;
105 while (cp && *cp) {
106 neg = 0;
107 cp = skip_over_blanks(cp);
108 next = skip_over_word(cp);
109 if (*next == 0)
110 next = 0;
111 else
112 *next = 0;
113 switch (*cp) {
114 case '-':
115 case '^':
116 neg++;
117 case '+':
118 cp++;
119 break;
120 }
121 if (e2p_string2mntopt(cp, &mask))
122 return 1;
123 if (ok && !(ok & mask))
124 return 1;
125 if (mask & EXT3_DEFM_JMODE)
126 *mntopts &= ~EXT3_DEFM_JMODE;
127 if (neg)
128 *mntopts &= ~mask;
129 else
130 *mntopts |= mask;
131 cp = next ? next+1 : 0;
132 }
133 return 0;
134}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/ostype.c b/e2fsprogs/old_e2fsprogs/e2p/ostype.c
new file mode 100644
index 000000000..0e111d408
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/ostype.c
@@ -0,0 +1,74 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * getostype.c - Get the Filesystem OS type
4 *
5 * Copyright (C) 2004,2005 Theodore Ts'o <tytso@mit.edu>
6 *
7 * This file can be redistributed under the terms of the GNU Library General
8 * Public License
9 */
10
11#include "e2p.h"
12#include <string.h>
13#include <stdlib.h>
14
15static const char * const os_tab[] =
16 { "Linux",
17 "Hurd",
18 "Masix",
19 "FreeBSD",
20 "Lites",
21 0 };
22
23/*
24 * Convert an os_type to a string
25 */
26char *e2p_os2string(int os_type)
27{
28 const char *os;
29 char *ret;
30
31 if (os_type <= EXT2_OS_LITES)
32 os = os_tab[os_type];
33 else
34 os = "(unknown os)";
35
36 ret = xstrdup(os);
37 return ret;
38}
39
40/*
41 * Convert an os_type to a string
42 */
43int e2p_string2os(char *str)
44{
45 const char * const *cpp;
46 int i = 0;
47
48 for (cpp = os_tab; *cpp; cpp++, i++) {
49 if (!strcasecmp(str, *cpp))
50 return i;
51 }
52 return -1;
53}
54
55#ifdef TEST_PROGRAM
56int main(int argc, char **argv)
57{
58 char *s;
59 int i, os;
60
61 for (i=0; i <= EXT2_OS_LITES; i++) {
62 s = e2p_os2string(i);
63 os = e2p_string2os(s);
64 printf("%d: %s (%d)\n", i, s, os);
65 if (i != os) {
66 fprintf(stderr, "Failure!\n");
67 exit(1);
68 }
69 }
70 exit(0);
71}
72#endif
73
74
diff --git a/e2fsprogs/old_e2fsprogs/e2p/parse_num.c b/e2fsprogs/old_e2fsprogs/e2p/parse_num.c
new file mode 100644
index 000000000..6db076f9c
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/parse_num.c
@@ -0,0 +1,65 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * parse_num.c - Parse the number of blocks
4 *
5 * Copyright (C) 2004,2005 Theodore Ts'o <tytso@mit.edu>
6 *
7 * This file can be redistributed under the terms of the GNU Library General
8 * Public License
9 */
10
11#include "e2p.h"
12
13#include <stdlib.h>
14
15unsigned long parse_num_blocks(const char *arg, int log_block_size)
16{
17 char *p;
18 unsigned long long num;
19
20 num = strtoull(arg, &p, 0);
21
22 if (p[0] && p[1])
23 return 0;
24
25 switch (*p) { /* Using fall-through logic */
26 case 'T': case 't':
27 num <<= 10;
28 case 'G': case 'g':
29 num <<= 10;
30 case 'M': case 'm':
31 num <<= 10;
32 case 'K': case 'k':
33 num >>= log_block_size;
34 break;
35 case 's':
36 num >>= 1;
37 break;
38 case '\0':
39 break;
40 default:
41 return 0;
42 }
43 return num;
44}
45
46#ifdef DEBUG
47#include <unistd.h>
48#include <stdio.h>
49
50main(int argc, char **argv)
51{
52 unsigned long num;
53 int log_block_size = 0;
54
55 if (argc != 2) {
56 fprintf(stderr, "Usage: %s arg\n", argv[0]);
57 exit(1);
58 }
59
60 num = parse_num_blocks(argv[1], log_block_size);
61
62 printf("Parsed number: %lu\n", num);
63 exit(0);
64}
65#endif
diff --git a/e2fsprogs/old_e2fsprogs/e2p/pe.c b/e2fsprogs/old_e2fsprogs/e2p/pe.c
new file mode 100644
index 000000000..835274b54
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/pe.c
@@ -0,0 +1,32 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * pe.c - Print a second extended filesystem errors behavior
4 *
5 * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * This file can be redistributed under the terms of the GNU Library General
10 * Public License
11 */
12
13/*
14 * History:
15 * 94/01/09 - Creation
16 */
17
18#include <stdio.h>
19
20#include "e2p.h"
21
22void print_fs_errors(FILE *f, unsigned short errors)
23{
24 char *disp = NULL;
25 switch (errors) {
26 case EXT2_ERRORS_CONTINUE: disp = "Continue"; break;
27 case EXT2_ERRORS_RO: disp = "Remount read-only"; break;
28 case EXT2_ERRORS_PANIC: disp = "Panic"; break;
29 default: disp = "Unknown (continue)";
30 }
31 fprintf(f, disp);
32}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/pf.c b/e2fsprogs/old_e2fsprogs/e2p/pf.c
new file mode 100644
index 000000000..55d4bc487
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/pf.c
@@ -0,0 +1,74 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * pf.c - Print file attributes on an ext2 file system
4 *
5 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * This file can be redistributed under the terms of the GNU Library General
10 * Public License
11 */
12
13/*
14 * History:
15 * 93/10/30 - Creation
16 */
17
18#include <stdio.h>
19
20#include "e2p.h"
21
22struct flags_name {
23 unsigned long flag;
24 const char *short_name;
25 const char *long_name;
26};
27
28static const struct flags_name flags_array[] = {
29 { EXT2_SECRM_FL, "s", "Secure_Deletion" },
30 { EXT2_UNRM_FL, "u" , "Undelete" },
31 { EXT2_SYNC_FL, "S", "Synchronous_Updates" },
32 { EXT2_DIRSYNC_FL, "D", "Synchronous_Directory_Updates" },
33 { EXT2_IMMUTABLE_FL, "i", "Immutable" },
34 { EXT2_APPEND_FL, "a", "Append_Only" },
35 { EXT2_NODUMP_FL, "d", "No_Dump" },
36 { EXT2_NOATIME_FL, "A", "No_Atime" },
37 { EXT2_COMPR_FL, "c", "Compression_Requested" },
38#ifdef ENABLE_COMPRESSION
39 { EXT2_COMPRBLK_FL, "B", "Compressed_File" },
40 { EXT2_DIRTY_FL, "Z", "Compressed_Dirty_File" },
41 { EXT2_NOCOMPR_FL, "X", "Compression_Raw_Access" },
42 { EXT2_ECOMPR_FL, "E", "Compression_Error" },
43#endif
44 { EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" },
45 { EXT2_INDEX_FL, "I", "Indexed_direcctory" },
46 { EXT2_NOTAIL_FL, "t", "No_Tailmerging" },
47 { EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" },
48 { 0, NULL, NULL }
49};
50
51void print_flags (FILE * f, unsigned long flags, unsigned options)
52{
53 int long_opt = (options & PFOPT_LONG);
54 const struct flags_name *fp;
55 int first = 1;
56
57 for (fp = flags_array; fp->flag != 0; fp++) {
58 if (flags & fp->flag) {
59 if (long_opt) {
60 if (first)
61 first = 0;
62 else
63 fputs(", ", f);
64 fputs(fp->long_name, f);
65 } else
66 fputs(fp->short_name, f);
67 } else {
68 if (!long_opt)
69 fputs("-", f);
70 }
71 }
72 if (long_opt && first)
73 fputs("---", f);
74}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/ps.c b/e2fsprogs/old_e2fsprogs/e2p/ps.c
new file mode 100644
index 000000000..a6b4099db
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/ps.c
@@ -0,0 +1,27 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ps.c - Print filesystem state
4 *
5 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * This file can be redistributed under the terms of the GNU Library General
10 * Public License
11 */
12
13/*
14 * History:
15 * 93/12/22 - Creation
16 */
17
18#include <stdio.h>
19
20#include "e2p.h"
21
22void print_fs_state(FILE *f, unsigned short state)
23{
24 fprintf(f, (state & EXT2_VALID_FS ? " clean" : " not clean"));
25 if (state & EXT2_ERROR_FS)
26 fprintf(f, " with errors");
27}
diff --git a/e2fsprogs/old_e2fsprogs/e2p/uuid.c b/e2fsprogs/old_e2fsprogs/e2p/uuid.c
new file mode 100644
index 000000000..474d64a5a
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/e2p/uuid.c
@@ -0,0 +1,78 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * uuid.c -- utility routines for manipulating UUID's.
4 */
5
6#include <stdio.h>
7#include <string.h>
8#include "../ext2fs/ext2_types.h"
9
10#include "e2p.h"
11
12struct uuid {
13 __u32 time_low;
14 __u16 time_mid;
15 __u16 time_hi_and_version;
16 __u16 clock_seq;
17 __u8 node[6];
18};
19
20/* Returns 1 if the uuid is the NULL uuid */
21int e2p_is_null_uuid(void *uu)
22{
23 __u8 *cp;
24 int i;
25
26 for (i=0, cp = uu; i < 16; i++)
27 if (*cp)
28 return 0;
29 return 1;
30}
31
32static void e2p_unpack_uuid(void *in, struct uuid *uu)
33{
34 __u8 *ptr = in;
35 __u32 tmp;
36
37 tmp = *ptr++;
38 tmp = (tmp << 8) | *ptr++;
39 tmp = (tmp << 8) | *ptr++;
40 tmp = (tmp << 8) | *ptr++;
41 uu->time_low = tmp;
42
43 tmp = *ptr++;
44 tmp = (tmp << 8) | *ptr++;
45 uu->time_mid = tmp;
46
47 tmp = *ptr++;
48 tmp = (tmp << 8) | *ptr++;
49 uu->time_hi_and_version = tmp;
50
51 tmp = *ptr++;
52 tmp = (tmp << 8) | *ptr++;
53 uu->clock_seq = tmp;
54
55 memcpy(uu->node, ptr, 6);
56}
57
58void e2p_uuid_to_str(void *uu, char *out)
59{
60 struct uuid uuid;
61
62 e2p_unpack_uuid(uu, &uuid);
63 sprintf(out,
64 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
65 uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
66 uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
67 uuid.node[0], uuid.node[1], uuid.node[2],
68 uuid.node[3], uuid.node[4], uuid.node[5]);
69}
70
71const char *e2p_uuid2str(void *uu)
72{
73 static char buf[80];
74 if (e2p_is_null_uuid(uu))
75 return "<none>";
76 e2p_uuid_to_str(uu, buf);
77 return buf;
78}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild b/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild
new file mode 100644
index 000000000..185887a44
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild
@@ -0,0 +1,23 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7NEEDED-$(CONFIG_E2FSCK) = y
8NEEDED-$(CONFIG_FSCK) = y
9NEEDED-$(CONFIG_MKE2FS) = y
10NEEDED-$(CONFIG_TUNE2FS) = y
11
12lib-y:=
13lib-$(NEEDED-y) += gen_bitmap.o bitops.o ismounted.o mkjournal.o unix_io.o \
14 rw_bitmaps.o initialize.o bitmaps.o block.o \
15 ind_block.o inode.o freefs.o alloc_stats.o closefs.o \
16 openfs.o io_manager.o finddev.o read_bb.o alloc.o badblocks.o \
17 getsize.o getsectsize.o alloc_tables.o read_bb_file.o mkdir.o \
18 bb_inode.o newdir.o alloc_sb.o lookup.o dirblock.o expanddir.o \
19 dir_iterate.o link.o res_gdt.o icount.o get_pathname.o dblist.o \
20 dirhash.o version.o flushb.o unlink.o check_desc.o valid_blk.o \
21 ext_attr.o bmap.o dblist_dir.o ext2fs_inline.o swapfs.o
22
23CFLAGS += -include $(srctree)/e2fsprogs/e2fsbb.h
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c b/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c
new file mode 100644
index 000000000..590f23a7e
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c
@@ -0,0 +1,174 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * alloc.c --- allocate new inodes, blocks for ext2fs
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 *
12 */
13
14#include <stdio.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <time.h>
19#include <string.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29
30/*
31 * Right now, just search forward from the parent directory's block
32 * group to find the next free inode.
33 *
34 * Should have a special policy for directories.
35 */
36errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
37 int mode EXT2FS_ATTR((unused)),
38 ext2fs_inode_bitmap map, ext2_ino_t *ret)
39{
40 ext2_ino_t dir_group = 0;
41 ext2_ino_t i;
42 ext2_ino_t start_inode;
43
44 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
45
46 if (!map)
47 map = fs->inode_map;
48 if (!map)
49 return EXT2_ET_NO_INODE_BITMAP;
50
51 if (dir > 0)
52 dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
53
54 start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
55 if (start_inode < EXT2_FIRST_INODE(fs->super))
56 start_inode = EXT2_FIRST_INODE(fs->super);
57 i = start_inode;
58
59 do {
60 if (!ext2fs_fast_test_inode_bitmap(map, i))
61 break;
62 i++;
63 if (i > fs->super->s_inodes_count)
64 i = EXT2_FIRST_INODE(fs->super);
65 } while (i != start_inode);
66
67 if (ext2fs_test_inode_bitmap(map, i))
68 return EXT2_ET_INODE_ALLOC_FAIL;
69 *ret = i;
70 return 0;
71}
72
73/*
74 * Stupid algorithm --- we now just search forward starting from the
75 * goal. Should put in a smarter one someday....
76 */
77errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
78 ext2fs_block_bitmap map, blk_t *ret)
79{
80 blk_t i;
81
82 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
83
84 if (!map)
85 map = fs->block_map;
86 if (!map)
87 return EXT2_ET_NO_BLOCK_BITMAP;
88 if (!goal || (goal >= fs->super->s_blocks_count))
89 goal = fs->super->s_first_data_block;
90 i = goal;
91 do {
92 if (!ext2fs_fast_test_block_bitmap(map, i)) {
93 *ret = i;
94 return 0;
95 }
96 i++;
97 if (i >= fs->super->s_blocks_count)
98 i = fs->super->s_first_data_block;
99 } while (i != goal);
100 return EXT2_ET_BLOCK_ALLOC_FAIL;
101}
102
103/*
104 * This function zeros out the allocated block, and updates all of the
105 * appropriate filesystem records.
106 */
107errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
108 char *block_buf, blk_t *ret)
109{
110 errcode_t retval;
111 blk_t block;
112 char *buf = 0;
113
114 if (!block_buf) {
115 retval = ext2fs_get_mem(fs->blocksize, &buf);
116 if (retval)
117 return retval;
118 block_buf = buf;
119 }
120 memset(block_buf, 0, fs->blocksize);
121
122 if (!fs->block_map) {
123 retval = ext2fs_read_block_bitmap(fs);
124 if (retval)
125 goto fail;
126 }
127
128 retval = ext2fs_new_block(fs, goal, 0, &block);
129 if (retval)
130 goto fail;
131
132 retval = io_channel_write_blk(fs->io, block, 1, block_buf);
133 if (retval)
134 goto fail;
135
136 ext2fs_block_alloc_stats(fs, block, +1);
137 *ret = block;
138 return 0;
139
140fail:
141 if (buf)
142 ext2fs_free_mem(&buf);
143 return retval;
144}
145
146errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
147 int num, ext2fs_block_bitmap map, blk_t *ret)
148{
149 blk_t b = start;
150
151 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
152
153 if (!map)
154 map = fs->block_map;
155 if (!map)
156 return EXT2_ET_NO_BLOCK_BITMAP;
157 if (!b)
158 b = fs->super->s_first_data_block;
159 if (!finish)
160 finish = start;
161 if (!num)
162 num = 1;
163 do {
164 if (b+num-1 > fs->super->s_blocks_count)
165 b = fs->super->s_first_data_block;
166 if (ext2fs_fast_test_block_bitmap_range(map, b, num)) {
167 *ret = b;
168 return 0;
169 }
170 b++;
171 } while (b != finish);
172 return EXT2_ET_BLOCK_ALLOC_FAIL;
173}
174
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/alloc_sb.c b/e2fsprogs/old_e2fsprogs/ext2fs/alloc_sb.c
new file mode 100644
index 000000000..a7437c96f
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/alloc_sb.c
@@ -0,0 +1,58 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * alloc_sb.c --- Allocate the superblock and block group descriptors for a
4 * newly initialized filesystem. Used by mke2fs when initializing a filesystem
5 *
6 * Copyright (C) 1994, 1995, 1996, 2003 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#include <fcntl.h>
20#include <time.h>
21#if HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#if HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27
28#include "ext2_fs.h"
29#include "ext2fs.h"
30
31int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
32 dgrp_t group,
33 ext2fs_block_bitmap bmap)
34{
35 blk_t super_blk, old_desc_blk, new_desc_blk;
36 int j, old_desc_blocks, num_blocks;
37
38 num_blocks = ext2fs_super_and_bgd_loc(fs, group, &super_blk,
39 &old_desc_blk, &new_desc_blk, 0);
40
41 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
42 old_desc_blocks = fs->super->s_first_meta_bg;
43 else
44 old_desc_blocks =
45 fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
46
47 if (super_blk || (group == 0))
48 ext2fs_mark_block_bitmap(bmap, super_blk);
49
50 if (old_desc_blk) {
51 for (j=0; j < old_desc_blocks; j++)
52 ext2fs_mark_block_bitmap(bmap, old_desc_blk + j);
53 }
54 if (new_desc_blk)
55 ext2fs_mark_block_bitmap(bmap, new_desc_blk);
56
57 return num_blocks;
58}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/alloc_stats.c b/e2fsprogs/old_e2fsprogs/ext2fs/alloc_stats.c
new file mode 100644
index 000000000..f3ab06a23
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/alloc_stats.c
@@ -0,0 +1,53 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * alloc_stats.c --- Update allocation statistics for ext2fs
4 *
5 * Copyright (C) 2001 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 *
12 */
13
14#include <stdio.h>
15
16#include "ext2_fs.h"
17#include "ext2fs.h"
18
19void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
20 int inuse, int isdir)
21{
22 int group = ext2fs_group_of_ino(fs, ino);
23
24 if (inuse > 0)
25 ext2fs_mark_inode_bitmap(fs->inode_map, ino);
26 else
27 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
28 fs->group_desc[group].bg_free_inodes_count -= inuse;
29 if (isdir)
30 fs->group_desc[group].bg_used_dirs_count += inuse;
31 fs->super->s_free_inodes_count -= inuse;
32 ext2fs_mark_super_dirty(fs);
33 ext2fs_mark_ib_dirty(fs);
34}
35
36void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse)
37{
38 ext2fs_inode_alloc_stats2(fs, ino, inuse, 0);
39}
40
41void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
42{
43 int group = ext2fs_group_of_blk(fs, blk);
44
45 if (inuse > 0)
46 ext2fs_mark_block_bitmap(fs->block_map, blk);
47 else
48 ext2fs_unmark_block_bitmap(fs->block_map, blk);
49 fs->group_desc[group].bg_free_blocks_count -= inuse;
50 fs->super->s_free_blocks_count -= inuse;
51 ext2fs_mark_super_dirty(fs);
52 ext2fs_mark_bb_dirty(fs);
53}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c b/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c
new file mode 100644
index 000000000..b2d786ed8
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c
@@ -0,0 +1,118 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * alloc_tables.c --- Allocate tables for a newly initialized
4 * filesystem. Used by mke2fs when initializing a filesystem
5 *
6 * Copyright (C) 1996 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#include <fcntl.h>
20#include <time.h>
21#if HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#if HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27
28#include "ext2_fs.h"
29#include "ext2fs.h"
30
31errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
32 ext2fs_block_bitmap bmap)
33{
34 errcode_t retval;
35 blk_t group_blk, start_blk, last_blk, new_blk, blk;
36 int j;
37
38 group_blk = fs->super->s_first_data_block +
39 (group * fs->super->s_blocks_per_group);
40
41 last_blk = group_blk + fs->super->s_blocks_per_group;
42 if (last_blk >= fs->super->s_blocks_count)
43 last_blk = fs->super->s_blocks_count - 1;
44
45 if (!bmap)
46 bmap = fs->block_map;
47
48 /*
49 * Allocate the block and inode bitmaps, if necessary
50 */
51 if (fs->stride) {
52 start_blk = group_blk + fs->inode_blocks_per_group;
53 start_blk += ((fs->stride * group) %
54 (last_blk - start_blk));
55 if (start_blk > last_blk)
56 start_blk = group_blk;
57 } else
58 start_blk = group_blk;
59
60 if (!fs->group_desc[group].bg_block_bitmap) {
61 retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
62 1, bmap, &new_blk);
63 if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
64 retval = ext2fs_get_free_blocks(fs, group_blk,
65 last_blk, 1, bmap, &new_blk);
66 if (retval)
67 return retval;
68 ext2fs_mark_block_bitmap(bmap, new_blk);
69 fs->group_desc[group].bg_block_bitmap = new_blk;
70 }
71
72 if (!fs->group_desc[group].bg_inode_bitmap) {
73 retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
74 1, bmap, &new_blk);
75 if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
76 retval = ext2fs_get_free_blocks(fs, group_blk,
77 last_blk, 1, bmap, &new_blk);
78 if (retval)
79 return retval;
80 ext2fs_mark_block_bitmap(bmap, new_blk);
81 fs->group_desc[group].bg_inode_bitmap = new_blk;
82 }
83
84 /*
85 * Allocate the inode table
86 */
87 if (!fs->group_desc[group].bg_inode_table) {
88 retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
89 fs->inode_blocks_per_group,
90 bmap, &new_blk);
91 if (retval)
92 return retval;
93 for (j=0, blk = new_blk;
94 j < fs->inode_blocks_per_group;
95 j++, blk++)
96 ext2fs_mark_block_bitmap(bmap, blk);
97 fs->group_desc[group].bg_inode_table = new_blk;
98 }
99
100
101 return 0;
102}
103
104
105
106errcode_t ext2fs_allocate_tables(ext2_filsys fs)
107{
108 errcode_t retval;
109 dgrp_t i;
110
111 for (i = 0; i < fs->group_desc_count; i++) {
112 retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
113 if (retval)
114 return retval;
115 }
116 return 0;
117}
118
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/badblocks.c b/e2fsprogs/old_e2fsprogs/ext2fs/badblocks.c
new file mode 100644
index 000000000..7804396d7
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/badblocks.c
@@ -0,0 +1,328 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * badblocks.c --- routines to manipulate the bad block structure
4 *
5 * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fsP.h"
29
30/*
31 * Helper function for making a badblocks list
32 */
33static errcode_t make_u32_list(int size, int num, __u32 *list,
34 ext2_u32_list *ret)
35{
36 ext2_u32_list bb;
37 errcode_t retval;
38
39 retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb);
40 if (retval)
41 return retval;
42 memset(bb, 0, sizeof(struct ext2_struct_u32_list));
43 bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
44 bb->size = size ? size : 10;
45 bb->num = num;
46 retval = ext2fs_get_mem(bb->size * sizeof(blk_t), &bb->list);
47 if (!bb->list) {
48 ext2fs_free_mem(&bb);
49 return retval;
50 }
51 if (list)
52 memcpy(bb->list, list, bb->size * sizeof(blk_t));
53 else
54 memset(bb->list, 0, bb->size * sizeof(blk_t));
55 *ret = bb;
56 return 0;
57}
58
59
60/*
61 * This procedure creates an empty u32 list.
62 */
63errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
64{
65 return make_u32_list(size, 0, 0, ret);
66}
67
68/*
69 * This procedure creates an empty badblocks list.
70 */
71errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
72{
73 return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
74}
75
76
77/*
78 * This procedure copies a badblocks list
79 */
80errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
81{
82 errcode_t retval;
83
84 retval = make_u32_list(src->size, src->num, src->list, dest);
85 if (retval)
86 return retval;
87 (*dest)->badblocks_flags = src->badblocks_flags;
88 return 0;
89}
90
91errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
92 ext2_badblocks_list *dest)
93{
94 return ext2fs_u32_copy((ext2_u32_list) src,
95 (ext2_u32_list *) dest);
96}
97
98/*
99 * This procedure frees a badblocks list.
100 *
101 * (note: moved to closefs.c)
102 */
103
104
105/*
106 * This procedure adds a block to a badblocks list.
107 */
108errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
109{
110 errcode_t retval;
111 int i, j;
112 unsigned long old_size;
113
114 EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
115
116 if (bb->num >= bb->size) {
117 old_size = bb->size * sizeof(__u32);
118 bb->size += 100;
119 retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
120 &bb->list);
121 if (retval) {
122 bb->size -= 100;
123 return retval;
124 }
125 }
126
127 /*
128 * Add special case code for appending to the end of the list
129 */
130 i = bb->num-1;
131 if ((bb->num != 0) && (bb->list[i] == blk))
132 return 0;
133 if ((bb->num == 0) || (bb->list[i] < blk)) {
134 bb->list[bb->num++] = blk;
135 return 0;
136 }
137
138 j = bb->num;
139 for (i=0; i < bb->num; i++) {
140 if (bb->list[i] == blk)
141 return 0;
142 if (bb->list[i] > blk) {
143 j = i;
144 break;
145 }
146 }
147 for (i=bb->num; i > j; i--)
148 bb->list[i] = bb->list[i-1];
149 bb->list[j] = blk;
150 bb->num++;
151 return 0;
152}
153
154errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
155{
156 return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
157}
158
159/*
160 * This procedure finds a particular block is on a badblocks
161 * list.
162 */
163int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
164{
165 int low, high, mid;
166
167 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
168 return -1;
169
170 if (bb->num == 0)
171 return -1;
172
173 low = 0;
174 high = bb->num-1;
175 if (blk == bb->list[low])
176 return low;
177 if (blk == bb->list[high])
178 return high;
179
180 while (low < high) {
181 mid = (low+high)/2;
182 if (mid == low || mid == high)
183 break;
184 if (blk == bb->list[mid])
185 return mid;
186 if (blk < bb->list[mid])
187 high = mid;
188 else
189 low = mid;
190 }
191 return -1;
192}
193
194/*
195 * This procedure tests to see if a particular block is on a badblocks
196 * list.
197 */
198int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
199{
200 if (ext2fs_u32_list_find(bb, blk) < 0)
201 return 0;
202 else
203 return 1;
204}
205
206int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
207{
208 return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
209}
210
211
212/*
213 * Remove a block from the badblock list
214 */
215int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
216{
217 int remloc, i;
218
219 if (bb->num == 0)
220 return -1;
221
222 remloc = ext2fs_u32_list_find(bb, blk);
223 if (remloc < 0)
224 return -1;
225
226 for (i = remloc ; i < bb->num-1; i++)
227 bb->list[i] = bb->list[i+1];
228 bb->num--;
229 return 0;
230}
231
232void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
233{
234 ext2fs_u32_list_del(bb, blk);
235}
236
237errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
238 ext2_u32_iterate *ret)
239{
240 ext2_u32_iterate iter;
241 errcode_t retval;
242
243 EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
244
245 retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter);
246 if (retval)
247 return retval;
248
249 iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
250 iter->bb = bb;
251 iter->ptr = 0;
252 *ret = iter;
253 return 0;
254}
255
256errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
257 ext2_badblocks_iterate *ret)
258{
259 return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
260 (ext2_u32_iterate *) ret);
261}
262
263
264int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
265{
266 ext2_u32_list bb;
267
268 if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
269 return 0;
270
271 bb = iter->bb;
272
273 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
274 return 0;
275
276 if (iter->ptr < bb->num) {
277 *blk = bb->list[iter->ptr++];
278 return 1;
279 }
280 *blk = 0;
281 return 0;
282}
283
284int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
285{
286 return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
287 (__u32 *) blk);
288}
289
290
291void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
292{
293 if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
294 return;
295
296 iter->bb = 0;
297 ext2fs_free_mem(&iter);
298}
299
300void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
301{
302 ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
303}
304
305
306int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
307{
308 EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
309 EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
310
311 if (bb1->num != bb2->num)
312 return 0;
313
314 if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
315 return 0;
316 return 1;
317}
318
319int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
320{
321 return ext2fs_u32_list_equal((ext2_u32_list) bb1,
322 (ext2_u32_list) bb2);
323}
324
325int ext2fs_u32_list_count(ext2_u32_list bb)
326{
327 return bb->num;
328}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bb_compat.c b/e2fsprogs/old_e2fsprogs/ext2fs/bb_compat.c
new file mode 100644
index 000000000..419ac7785
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/bb_compat.c
@@ -0,0 +1,64 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bb_compat.c --- compatibility badblocks routines
4 *
5 * Copyright (C) 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fsP.h"
29
30errcode_t badblocks_list_create(badblocks_list *ret, int size)
31{
32 return ext2fs_badblocks_list_create(ret, size);
33}
34
35void badblocks_list_free(badblocks_list bb)
36{
37 ext2fs_badblocks_list_free(bb);
38}
39
40errcode_t badblocks_list_add(badblocks_list bb, blk_t blk)
41{
42 return ext2fs_badblocks_list_add(bb, blk);
43}
44
45int badblocks_list_test(badblocks_list bb, blk_t blk)
46{
47 return ext2fs_badblocks_list_test(bb, blk);
48}
49
50errcode_t badblocks_list_iterate_begin(badblocks_list bb,
51 badblocks_iterate *ret)
52{
53 return ext2fs_badblocks_list_iterate_begin(bb, ret);
54}
55
56int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk)
57{
58 return ext2fs_badblocks_list_iterate(iter, blk);
59}
60
61void badblocks_list_iterate_end(badblocks_iterate iter)
62{
63 ext2fs_badblocks_list_iterate_end(iter);
64}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c b/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c
new file mode 100644
index 000000000..855f86eac
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c
@@ -0,0 +1,268 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bb_inode.c --- routines to update the bad block inode.
4 *
5 * WARNING: This routine modifies a lot of state in the filesystem; if
6 * this routine returns an error, the bad block inode may be in an
7 * inconsistent state.
8 *
9 * Copyright (C) 1994, 1995 Theodore Ts'o.
10 *
11 * %Begin-Header%
12 * This file may be redistributed under the terms of the GNU Public
13 * License.
14 * %End-Header%
15 */
16
17#include <stdio.h>
18#include <string.h>
19#if HAVE_UNISTD_H
20#include <unistd.h>
21#endif
22#include <fcntl.h>
23#include <time.h>
24#if HAVE_SYS_STAT_H
25#include <sys/stat.h>
26#endif
27#if HAVE_SYS_TYPES_H
28#include <sys/types.h>
29#endif
30
31#include "ext2_fs.h"
32#include "ext2fs.h"
33
34struct set_badblock_record {
35 ext2_badblocks_iterate bb_iter;
36 int bad_block_count;
37 blk_t *ind_blocks;
38 int max_ind_blocks;
39 int ind_blocks_size;
40 int ind_blocks_ptr;
41 char *block_buf;
42 errcode_t err;
43};
44
45static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
46 e2_blkcnt_t blockcnt,
47 blk_t ref_block, int ref_offset,
48 void *priv_data);
49static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
50 e2_blkcnt_t blockcnt,
51 blk_t ref_block, int ref_offset,
52 void *priv_data);
53
54/*
55 * Given a bad blocks bitmap, update the bad blocks inode to reflect
56 * the map.
57 */
58errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
59{
60 errcode_t retval;
61 struct set_badblock_record rec;
62 struct ext2_inode inode;
63
64 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
65
66 if (!fs->block_map)
67 return EXT2_ET_NO_BLOCK_BITMAP;
68
69 rec.bad_block_count = 0;
70 rec.ind_blocks_size = rec.ind_blocks_ptr = 0;
71 rec.max_ind_blocks = 10;
72 retval = ext2fs_get_mem(rec.max_ind_blocks * sizeof(blk_t),
73 &rec.ind_blocks);
74 if (retval)
75 return retval;
76 memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
77 retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf);
78 if (retval)
79 goto cleanup;
80 memset(rec.block_buf, 0, fs->blocksize);
81 rec.err = 0;
82
83 /*
84 * First clear the old bad blocks (while saving the indirect blocks)
85 */
86 retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
87 BLOCK_FLAG_DEPTH_TRAVERSE, 0,
88 clear_bad_block_proc, &rec);
89 if (retval)
90 goto cleanup;
91 if (rec.err) {
92 retval = rec.err;
93 goto cleanup;
94 }
95
96 /*
97 * Now set the bad blocks!
98 *
99 * First, mark the bad blocks as used. This prevents a bad
100 * block from being used as an indirecto block for the bad
101 * block inode (!).
102 */
103 if (bb_list) {
104 retval = ext2fs_badblocks_list_iterate_begin(bb_list,
105 &rec.bb_iter);
106 if (retval)
107 goto cleanup;
108 retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
109 BLOCK_FLAG_APPEND, 0,
110 set_bad_block_proc, &rec);
111 ext2fs_badblocks_list_iterate_end(rec.bb_iter);
112 if (retval)
113 goto cleanup;
114 if (rec.err) {
115 retval = rec.err;
116 goto cleanup;
117 }
118 }
119
120 /*
121 * Update the bad block inode's mod time and block count
122 * field.
123 */
124 retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
125 if (retval)
126 goto cleanup;
127
128 inode.i_atime = inode.i_mtime = time(0);
129 if (!inode.i_ctime)
130 inode.i_ctime = time(0);
131 inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512);
132 inode.i_size = rec.bad_block_count * fs->blocksize;
133
134 retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
135 if (retval)
136 goto cleanup;
137
138cleanup:
139 ext2fs_free_mem(&rec.ind_blocks);
140 ext2fs_free_mem(&rec.block_buf);
141 return retval;
142}
143
144/*
145 * Helper function for update_bb_inode()
146 *
147 * Clear the bad blocks in the bad block inode, while saving the
148 * indirect blocks.
149 */
150#ifdef __TURBOC__
151# pragma argsused
152#endif
153static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
154 e2_blkcnt_t blockcnt,
155 blk_t ref_block EXT2FS_ATTR((unused)),
156 int ref_offset EXT2FS_ATTR((unused)),
157 void *priv_data)
158{
159 struct set_badblock_record *rec = (struct set_badblock_record *)
160 priv_data;
161 errcode_t retval;
162 unsigned long old_size;
163
164 if (!*block_nr)
165 return 0;
166
167 /*
168 * If the block number is outrageous, clear it and ignore it.
169 */
170 if (*block_nr >= fs->super->s_blocks_count ||
171 *block_nr < fs->super->s_first_data_block) {
172 *block_nr = 0;
173 return BLOCK_CHANGED;
174 }
175
176 if (blockcnt < 0) {
177 if (rec->ind_blocks_size >= rec->max_ind_blocks) {
178 old_size = rec->max_ind_blocks * sizeof(blk_t);
179 rec->max_ind_blocks += 10;
180 retval = ext2fs_resize_mem(old_size,
181 rec->max_ind_blocks * sizeof(blk_t),
182 &rec->ind_blocks);
183 if (retval) {
184 rec->max_ind_blocks -= 10;
185 rec->err = retval;
186 return BLOCK_ABORT;
187 }
188 }
189 rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
190 }
191
192 /*
193 * Mark the block as unused, and update accounting information
194 */
195 ext2fs_block_alloc_stats(fs, *block_nr, -1);
196
197 *block_nr = 0;
198 return BLOCK_CHANGED;
199}
200
201
202/*
203 * Helper function for update_bb_inode()
204 *
205 * Set the block list in the bad block inode, using the supplied bitmap.
206 */
207#ifdef __TURBOC__
208 #pragma argsused
209#endif
210static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
211 e2_blkcnt_t blockcnt,
212 blk_t ref_block EXT2FS_ATTR((unused)),
213 int ref_offset EXT2FS_ATTR((unused)),
214 void *priv_data)
215{
216 struct set_badblock_record *rec = (struct set_badblock_record *)
217 priv_data;
218 errcode_t retval;
219 blk_t blk;
220
221 if (blockcnt >= 0) {
222 /*
223 * Get the next bad block.
224 */
225 if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk))
226 return BLOCK_ABORT;
227 rec->bad_block_count++;
228 } else {
229 /*
230 * An indirect block; fetch a block from the
231 * previously used indirect block list. The block
232 * most be not marked as used; if so, get another one.
233 * If we run out of reserved indirect blocks, allocate
234 * a new one.
235 */
236 retry:
237 if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
238 blk = rec->ind_blocks[rec->ind_blocks_ptr++];
239 if (ext2fs_test_block_bitmap(fs->block_map, blk))
240 goto retry;
241 } else {
242 retval = ext2fs_new_block(fs, 0, 0, &blk);
243 if (retval) {
244 rec->err = retval;
245 return BLOCK_ABORT;
246 }
247 }
248 retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf);
249 if (retval) {
250 rec->err = retval;
251 return BLOCK_ABORT;
252 }
253 }
254
255 /*
256 * Update block counts
257 */
258 ext2fs_block_alloc_stats(fs, blk, +1);
259
260 *block_nr = blk;
261 return BLOCK_CHANGED;
262}
263
264
265
266
267
268
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bitmaps.c b/e2fsprogs/old_e2fsprogs/ext2fs/bitmaps.c
new file mode 100644
index 000000000..712a4a9b1
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/bitmaps.c
@@ -0,0 +1,213 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bitmaps.c --- routines to read, write, and manipulate the inode and
4 * block bitmaps.
5 *
6 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#include <fcntl.h>
20#include <time.h>
21#if HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#if HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27
28#include "ext2_fs.h"
29#include "ext2fs.h"
30
31static errcode_t make_bitmap(__u32 start, __u32 end, __u32 real_end,
32 const char *descr, char *init_map,
33 ext2fs_generic_bitmap *ret)
34{
35 ext2fs_generic_bitmap bitmap;
36 errcode_t retval;
37 size_t size;
38
39 retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
40 &bitmap);
41 if (retval)
42 return retval;
43
44 bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
45 bitmap->fs = NULL;
46 bitmap->start = start;
47 bitmap->end = end;
48 bitmap->real_end = real_end;
49 bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
50 if (descr) {
51 retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
52 if (retval) {
53 ext2fs_free_mem(&bitmap);
54 return retval;
55 }
56 strcpy(bitmap->description, descr);
57 } else
58 bitmap->description = 0;
59
60 size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
61 retval = ext2fs_get_mem(size, &bitmap->bitmap);
62 if (retval) {
63 ext2fs_free_mem(&bitmap->description);
64 ext2fs_free_mem(&bitmap);
65 return retval;
66 }
67
68 if (init_map)
69 memcpy(bitmap->bitmap, init_map, size);
70 else
71 memset(bitmap->bitmap, 0, size);
72 *ret = bitmap;
73 return 0;
74}
75
76errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
77 __u32 end,
78 __u32 real_end,
79 const char *descr,
80 ext2fs_generic_bitmap *ret)
81{
82 return make_bitmap(start, end, real_end, descr, 0, ret);
83}
84
85errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
86 ext2fs_generic_bitmap *dest)
87{
88 errcode_t retval;
89 ext2fs_generic_bitmap new_map;
90
91 retval = make_bitmap(src->start, src->end, src->real_end,
92 src->description, src->bitmap, &new_map);
93 if (retval)
94 return retval;
95 new_map->magic = src->magic;
96 new_map->fs = src->fs;
97 new_map->base_error_code = src->base_error_code;
98 *dest = new_map;
99 return 0;
100}
101
102void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
103{
104 __u32 i, j;
105
106 for (i=map->end+1, j = i - map->start; i <= map->real_end; i++, j++)
107 ext2fs_set_bit(j, map->bitmap);
108
109 return;
110}
111
112errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
113 const char *descr,
114 ext2fs_inode_bitmap *ret)
115{
116 ext2fs_inode_bitmap bitmap;
117 errcode_t retval;
118 __u32 start, end, real_end;
119
120 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
121
122 fs->write_bitmaps = ext2fs_write_bitmaps;
123
124 start = 1;
125 end = fs->super->s_inodes_count;
126 real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count);
127
128 retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
129 descr, &bitmap);
130 if (retval)
131 return retval;
132
133 bitmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
134 bitmap->fs = fs;
135 bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
136
137 *ret = bitmap;
138 return 0;
139}
140
141errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
142 const char *descr,
143 ext2fs_block_bitmap *ret)
144{
145 ext2fs_block_bitmap bitmap;
146 errcode_t retval;
147 __u32 start, end, real_end;
148
149 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
150
151 fs->write_bitmaps = ext2fs_write_bitmaps;
152
153 start = fs->super->s_first_data_block;
154 end = fs->super->s_blocks_count-1;
155 real_end = (EXT2_BLOCKS_PER_GROUP(fs->super)
156 * fs->group_desc_count)-1 + start;
157
158 retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
159 descr, &bitmap);
160 if (retval)
161 return retval;
162
163 bitmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
164 bitmap->fs = fs;
165 bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
166
167 *ret = bitmap;
168 return 0;
169}
170
171errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
172 ext2_ino_t end, ext2_ino_t *oend)
173{
174 EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
175
176 if (end > bitmap->real_end)
177 return EXT2_ET_FUDGE_INODE_BITMAP_END;
178 if (oend)
179 *oend = bitmap->end;
180 bitmap->end = end;
181 return 0;
182}
183
184errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
185 blk_t end, blk_t *oend)
186{
187 EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
188
189 if (end > bitmap->real_end)
190 return EXT2_ET_FUDGE_BLOCK_BITMAP_END;
191 if (oend)
192 *oend = bitmap->end;
193 bitmap->end = end;
194 return 0;
195}
196
197void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap)
198{
199 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
200 return;
201
202 memset(bitmap->bitmap, 0,
203 (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
204}
205
206void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap)
207{
208 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
209 return;
210
211 memset(bitmap->bitmap, 0,
212 (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
213}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c b/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c
new file mode 100644
index 000000000..987061130
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c
@@ -0,0 +1,91 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bitops.c --- Bitmap frobbing code. See bitops.h for the inlined
4 * routines.
5 *
6 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#if HAVE_SYS_TYPES_H
16#include <sys/types.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22#ifndef _EXT2_HAVE_ASM_BITOPS_
23
24/*
25 * For the benefit of those who are trying to port Linux to another
26 * architecture, here are some C-language equivalents. You should
27 * recode these in the native assmebly language, if at all possible.
28 *
29 * C language equivalents written by Theodore Ts'o, 9/26/92.
30 * Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian
31 * systems, as well as non-32 bit systems.
32 */
33
34int ext2fs_set_bit(unsigned int nr,void * addr)
35{
36 int mask, retval;
37 unsigned char *ADDR = (unsigned char *) addr;
38
39 ADDR += nr >> 3;
40 mask = 1 << (nr & 0x07);
41 retval = mask & *ADDR;
42 *ADDR |= mask;
43 return retval;
44}
45
46int ext2fs_clear_bit(unsigned int nr, void * addr)
47{
48 int mask, retval;
49 unsigned char *ADDR = (unsigned char *) addr;
50
51 ADDR += nr >> 3;
52 mask = 1 << (nr & 0x07);
53 retval = mask & *ADDR;
54 *ADDR &= ~mask;
55 return retval;
56}
57
58int ext2fs_test_bit(unsigned int nr, const void * addr)
59{
60 int mask;
61 const unsigned char *ADDR = (const unsigned char *) addr;
62
63 ADDR += nr >> 3;
64 mask = 1 << (nr & 0x07);
65 return (mask & *ADDR);
66}
67
68#endif /* !_EXT2_HAVE_ASM_BITOPS_ */
69
70void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
71 const char *description)
72{
73#ifndef OMIT_COM_ERR
74 if (description)
75 bb_error_msg("#%lu for %s", arg, description);
76 else
77 bb_error_msg("#%lu", arg);
78#endif
79}
80
81void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
82 int code, unsigned long arg)
83{
84#ifndef OMIT_COM_ERR
85 if (bitmap->description)
86 bb_error_msg("#%lu for %s", arg, bitmap->description);
87 else
88 bb_error_msg("#%lu", arg);
89#endif
90}
91
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bitops.h b/e2fsprogs/old_e2fsprogs/ext2fs/bitops.h
new file mode 100644
index 000000000..6dd30862b
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/bitops.h
@@ -0,0 +1,107 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bitops.h --- Bitmap frobbing code. The byte swapping routines are
4 * also included here.
5 *
6 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 *
13 * i386 bitops operations taken from <asm/bitops.h>, Copyright 1992,
14 * Linus Torvalds.
15 */
16
17#include <string.h>
18#include <strings.h>
19
20extern int ext2fs_set_bit(unsigned int nr,void * addr);
21extern int ext2fs_clear_bit(unsigned int nr, void * addr);
22extern int ext2fs_test_bit(unsigned int nr, const void * addr);
23extern __u16 ext2fs_swab16(__u16 val);
24extern __u32 ext2fs_swab32(__u32 val);
25
26#ifdef WORDS_BIGENDIAN
27#define ext2fs_cpu_to_le32(x) ext2fs_swab32((x))
28#define ext2fs_le32_to_cpu(x) ext2fs_swab32((x))
29#define ext2fs_cpu_to_le16(x) ext2fs_swab16((x))
30#define ext2fs_le16_to_cpu(x) ext2fs_swab16((x))
31#define ext2fs_cpu_to_be32(x) ((__u32)(x))
32#define ext2fs_be32_to_cpu(x) ((__u32)(x))
33#define ext2fs_cpu_to_be16(x) ((__u16)(x))
34#define ext2fs_be16_to_cpu(x) ((__u16)(x))
35#else
36#define ext2fs_cpu_to_le32(x) ((__u32)(x))
37#define ext2fs_le32_to_cpu(x) ((__u32)(x))
38#define ext2fs_cpu_to_le16(x) ((__u16)(x))
39#define ext2fs_le16_to_cpu(x) ((__u16)(x))
40#define ext2fs_cpu_to_be32(x) ext2fs_swab32((x))
41#define ext2fs_be32_to_cpu(x) ext2fs_swab32((x))
42#define ext2fs_cpu_to_be16(x) ext2fs_swab16((x))
43#define ext2fs_be16_to_cpu(x) ext2fs_swab16((x))
44#endif
45
46/*
47 * EXT2FS bitmap manipulation routines.
48 */
49
50/* Support for sending warning messages from the inline subroutines */
51extern const char *ext2fs_block_string;
52extern const char *ext2fs_inode_string;
53extern const char *ext2fs_mark_string;
54extern const char *ext2fs_unmark_string;
55extern const char *ext2fs_test_string;
56extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
57 const char *description);
58extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
59 int code, unsigned long arg);
60
61extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
62extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
63 blk_t block);
64extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
65
66extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
67extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
68 ext2_ino_t inode);
69extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
70
71extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
72 blk_t block);
73extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
74 blk_t block);
75extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
76 blk_t block);
77
78extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
79 ext2_ino_t inode);
80extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
81 ext2_ino_t inode);
82extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
83 ext2_ino_t inode);
84extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap);
85extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap);
86extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap);
87extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap);
88
89extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
90 blk_t block, int num);
91extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
92 blk_t block, int num);
93extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
94 blk_t block, int num);
95extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
96 blk_t block, int num);
97extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
98 blk_t block, int num);
99extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
100 blk_t block, int num);
101extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map);
102
103/* These two routines moved to gen_bitmap.c */
104extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
105 __u32 bitno);
106extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
107 blk_t bitno);
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/block.c b/e2fsprogs/old_e2fsprogs/ext2fs/block.c
new file mode 100644
index 000000000..0a757b201
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/block.c
@@ -0,0 +1,438 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * block.c --- iterate over all blocks in an inode
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22struct block_context {
23 ext2_filsys fs;
24 int (*func)(ext2_filsys fs,
25 blk_t *blocknr,
26 e2_blkcnt_t bcount,
27 blk_t ref_blk,
28 int ref_offset,
29 void *priv_data);
30 e2_blkcnt_t bcount;
31 int bsize;
32 int flags;
33 errcode_t errcode;
34 char *ind_buf;
35 char *dind_buf;
36 char *tind_buf;
37 void *priv_data;
38};
39
40static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
41 int ref_offset, struct block_context *ctx)
42{
43 int ret = 0, changed = 0;
44 int i, flags, limit, offset;
45 blk_t *block_nr;
46
47 limit = ctx->fs->blocksize >> 2;
48 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
49 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
50 ret = (*ctx->func)(ctx->fs, ind_block,
51 BLOCK_COUNT_IND, ref_block,
52 ref_offset, ctx->priv_data);
53 if (!*ind_block || (ret & BLOCK_ABORT)) {
54 ctx->bcount += limit;
55 return ret;
56 }
57 if (*ind_block >= ctx->fs->super->s_blocks_count ||
58 *ind_block < ctx->fs->super->s_first_data_block) {
59 ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
60 ret |= BLOCK_ERROR;
61 return ret;
62 }
63 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
64 ctx->ind_buf);
65 if (ctx->errcode) {
66 ret |= BLOCK_ERROR;
67 return ret;
68 }
69
70 block_nr = (blk_t *) ctx->ind_buf;
71 offset = 0;
72 if (ctx->flags & BLOCK_FLAG_APPEND) {
73 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
74 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
75 *ind_block, offset,
76 ctx->priv_data);
77 changed |= flags;
78 if (flags & BLOCK_ABORT) {
79 ret |= BLOCK_ABORT;
80 break;
81 }
82 offset += sizeof(blk_t);
83 }
84 } else {
85 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
86 if (*block_nr == 0)
87 continue;
88 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
89 *ind_block, offset,
90 ctx->priv_data);
91 changed |= flags;
92 if (flags & BLOCK_ABORT) {
93 ret |= BLOCK_ABORT;
94 break;
95 }
96 offset += sizeof(blk_t);
97 }
98 }
99 if (changed & BLOCK_CHANGED) {
100 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
101 ctx->ind_buf);
102 if (ctx->errcode)
103 ret |= BLOCK_ERROR | BLOCK_ABORT;
104 }
105 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
106 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
107 !(ret & BLOCK_ABORT))
108 ret |= (*ctx->func)(ctx->fs, ind_block,
109 BLOCK_COUNT_IND, ref_block,
110 ref_offset, ctx->priv_data);
111 return ret;
112}
113
114static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
115 int ref_offset, struct block_context *ctx)
116{
117 int ret = 0, changed = 0;
118 int i, flags, limit, offset;
119 blk_t *block_nr;
120
121 limit = ctx->fs->blocksize >> 2;
122 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
123 BLOCK_FLAG_DATA_ONLY)))
124 ret = (*ctx->func)(ctx->fs, dind_block,
125 BLOCK_COUNT_DIND, ref_block,
126 ref_offset, ctx->priv_data);
127 if (!*dind_block || (ret & BLOCK_ABORT)) {
128 ctx->bcount += limit*limit;
129 return ret;
130 }
131 if (*dind_block >= ctx->fs->super->s_blocks_count ||
132 *dind_block < ctx->fs->super->s_first_data_block) {
133 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
134 ret |= BLOCK_ERROR;
135 return ret;
136 }
137 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
138 ctx->dind_buf);
139 if (ctx->errcode) {
140 ret |= BLOCK_ERROR;
141 return ret;
142 }
143
144 block_nr = (blk_t *) ctx->dind_buf;
145 offset = 0;
146 if (ctx->flags & BLOCK_FLAG_APPEND) {
147 for (i = 0; i < limit; i++, block_nr++) {
148 flags = block_iterate_ind(block_nr,
149 *dind_block, offset,
150 ctx);
151 changed |= flags;
152 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
153 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
154 break;
155 }
156 offset += sizeof(blk_t);
157 }
158 } else {
159 for (i = 0; i < limit; i++, block_nr++) {
160 if (*block_nr == 0) {
161 ctx->bcount += limit;
162 continue;
163 }
164 flags = block_iterate_ind(block_nr,
165 *dind_block, offset,
166 ctx);
167 changed |= flags;
168 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
169 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
170 break;
171 }
172 offset += sizeof(blk_t);
173 }
174 }
175 if (changed & BLOCK_CHANGED) {
176 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
177 ctx->dind_buf);
178 if (ctx->errcode)
179 ret |= BLOCK_ERROR | BLOCK_ABORT;
180 }
181 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
182 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
183 !(ret & BLOCK_ABORT))
184 ret |= (*ctx->func)(ctx->fs, dind_block,
185 BLOCK_COUNT_DIND, ref_block,
186 ref_offset, ctx->priv_data);
187 return ret;
188}
189
190static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
191 int ref_offset, struct block_context *ctx)
192{
193 int ret = 0, changed = 0;
194 int i, flags, limit, offset;
195 blk_t *block_nr;
196
197 limit = ctx->fs->blocksize >> 2;
198 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
199 BLOCK_FLAG_DATA_ONLY)))
200 ret = (*ctx->func)(ctx->fs, tind_block,
201 BLOCK_COUNT_TIND, ref_block,
202 ref_offset, ctx->priv_data);
203 if (!*tind_block || (ret & BLOCK_ABORT)) {
204 ctx->bcount += limit*limit*limit;
205 return ret;
206 }
207 if (*tind_block >= ctx->fs->super->s_blocks_count ||
208 *tind_block < ctx->fs->super->s_first_data_block) {
209 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
210 ret |= BLOCK_ERROR;
211 return ret;
212 }
213 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
214 ctx->tind_buf);
215 if (ctx->errcode) {
216 ret |= BLOCK_ERROR;
217 return ret;
218 }
219
220 block_nr = (blk_t *) ctx->tind_buf;
221 offset = 0;
222 if (ctx->flags & BLOCK_FLAG_APPEND) {
223 for (i = 0; i < limit; i++, block_nr++) {
224 flags = block_iterate_dind(block_nr,
225 *tind_block,
226 offset, ctx);
227 changed |= flags;
228 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
229 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
230 break;
231 }
232 offset += sizeof(blk_t);
233 }
234 } else {
235 for (i = 0; i < limit; i++, block_nr++) {
236 if (*block_nr == 0) {
237 ctx->bcount += limit*limit;
238 continue;
239 }
240 flags = block_iterate_dind(block_nr,
241 *tind_block,
242 offset, ctx);
243 changed |= flags;
244 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
245 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
246 break;
247 }
248 offset += sizeof(blk_t);
249 }
250 }
251 if (changed & BLOCK_CHANGED) {
252 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
253 ctx->tind_buf);
254 if (ctx->errcode)
255 ret |= BLOCK_ERROR | BLOCK_ABORT;
256 }
257 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
258 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
259 !(ret & BLOCK_ABORT))
260 ret |= (*ctx->func)(ctx->fs, tind_block,
261 BLOCK_COUNT_TIND, ref_block,
262 ref_offset, ctx->priv_data);
263
264 return ret;
265}
266
267errcode_t ext2fs_block_iterate2(ext2_filsys fs,
268 ext2_ino_t ino,
269 int flags,
270 char *block_buf,
271 int (*func)(ext2_filsys fs,
272 blk_t *blocknr,
273 e2_blkcnt_t blockcnt,
274 blk_t ref_blk,
275 int ref_offset,
276 void *priv_data),
277 void *priv_data)
278{
279 int i;
280 int got_inode = 0;
281 int ret = 0;
282 blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
283 struct ext2_inode inode;
284 errcode_t retval;
285 struct block_context ctx;
286 int limit;
287
288 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
289
290 /*
291 * Check to see if we need to limit large files
292 */
293 if (flags & BLOCK_FLAG_NO_LARGE) {
294 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
295 if (ctx.errcode)
296 return ctx.errcode;
297 got_inode = 1;
298 if (!LINUX_S_ISDIR(inode.i_mode) &&
299 (inode.i_size_high != 0))
300 return EXT2_ET_FILE_TOO_BIG;
301 }
302
303 retval = ext2fs_get_blocks(fs, ino, blocks);
304 if (retval)
305 return retval;
306
307 limit = fs->blocksize >> 2;
308
309 ctx.fs = fs;
310 ctx.func = func;
311 ctx.priv_data = priv_data;
312 ctx.flags = flags;
313 ctx.bcount = 0;
314 if (block_buf) {
315 ctx.ind_buf = block_buf;
316 } else {
317 retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf);
318 if (retval)
319 return retval;
320 }
321 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
322 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
323
324 /*
325 * Iterate over the HURD translator block (if present)
326 */
327 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
328 !(flags & BLOCK_FLAG_DATA_ONLY)) {
329 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
330 if (ctx.errcode)
331 goto abort_exit;
332 got_inode = 1;
333 if (inode.osd1.hurd1.h_i_translator) {
334 ret |= (*ctx.func)(fs,
335 &inode.osd1.hurd1.h_i_translator,
336 BLOCK_COUNT_TRANSLATOR,
337 0, 0, priv_data);
338 if (ret & BLOCK_ABORT)
339 goto abort_exit;
340 }
341 }
342
343 /*
344 * Iterate over normal data blocks
345 */
346 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
347 if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
348 ret |= (*ctx.func)(fs, &blocks[i],
349 ctx.bcount, 0, i, priv_data);
350 if (ret & BLOCK_ABORT)
351 goto abort_exit;
352 }
353 }
354 if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
355 ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
356 0, EXT2_IND_BLOCK, &ctx);
357 if (ret & BLOCK_ABORT)
358 goto abort_exit;
359 } else
360 ctx.bcount += limit;
361 if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
362 ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
363 0, EXT2_DIND_BLOCK, &ctx);
364 if (ret & BLOCK_ABORT)
365 goto abort_exit;
366 } else
367 ctx.bcount += limit * limit;
368 if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
369 ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
370 0, EXT2_TIND_BLOCK, &ctx);
371 if (ret & BLOCK_ABORT)
372 goto abort_exit;
373 }
374
375abort_exit:
376 if (ret & BLOCK_CHANGED) {
377 if (!got_inode) {
378 retval = ext2fs_read_inode(fs, ino, &inode);
379 if (retval)
380 return retval;
381 }
382 for (i=0; i < EXT2_N_BLOCKS; i++)
383 inode.i_block[i] = blocks[i];
384 retval = ext2fs_write_inode(fs, ino, &inode);
385 if (retval)
386 return retval;
387 }
388
389 if (!block_buf)
390 ext2fs_free_mem(&ctx.ind_buf);
391
392 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
393}
394
395/*
396 * Emulate the old ext2fs_block_iterate function!
397 */
398
399struct xlate {
400 int (*func)(ext2_filsys fs,
401 blk_t *blocknr,
402 int bcount,
403 void *priv_data);
404 void *real_private;
405};
406
407#ifdef __TURBOC__
408# pragma argsused
409#endif
410static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
411 blk_t ref_block EXT2FS_ATTR((unused)),
412 int ref_offset EXT2FS_ATTR((unused)),
413 void *priv_data)
414{
415 struct xlate *xl = (struct xlate *) priv_data;
416
417 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
418}
419
420errcode_t ext2fs_block_iterate(ext2_filsys fs,
421 ext2_ino_t ino,
422 int flags,
423 char *block_buf,
424 int (*func)(ext2_filsys fs,
425 blk_t *blocknr,
426 int blockcnt,
427 void *priv_data),
428 void *priv_data)
429{
430 struct xlate xl;
431
432 xl.real_private = priv_data;
433 xl.func = func;
434
435 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
436 block_buf, xlate_func, &xl);
437}
438
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c b/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c
new file mode 100644
index 000000000..b22fe3dbf
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c
@@ -0,0 +1,264 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bmap.c --- logical to physical block mapping
4 *
5 * Copyright (C) 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
23 struct ext2_inode *inode,
24 char *block_buf, int bmap_flags,
25 blk_t block, blk_t *phys_blk);
26
27#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
28
29static errcode_t block_ind_bmap(ext2_filsys fs, int flags,
30 blk_t ind, char *block_buf,
31 int *blocks_alloc,
32 blk_t nr, blk_t *ret_blk)
33{
34 errcode_t retval;
35 blk_t b;
36
37 if (!ind) {
38 if (flags & BMAP_SET)
39 return EXT2_ET_SET_BMAP_NO_IND;
40 *ret_blk = 0;
41 return 0;
42 }
43 retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
44 if (retval)
45 return retval;
46
47 if (flags & BMAP_SET) {
48 b = *ret_blk;
49#if BB_BIG_ENDIAN
50 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
51 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
52 b = ext2fs_swab32(b);
53#endif
54 ((blk_t *) block_buf)[nr] = b;
55 return io_channel_write_blk(fs->io, ind, 1, block_buf);
56 }
57
58 b = ((blk_t *) block_buf)[nr];
59
60#if BB_BIG_ENDIAN
61 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
62 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
63 b = ext2fs_swab32(b);
64#endif
65
66 if (!b && (flags & BMAP_ALLOC)) {
67 b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
68 retval = ext2fs_alloc_block(fs, b,
69 block_buf + fs->blocksize, &b);
70 if (retval)
71 return retval;
72
73#if BB_BIG_ENDIAN
74 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
75 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
76 ((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
77 else
78#endif
79 ((blk_t *) block_buf)[nr] = b;
80
81 retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
82 if (retval)
83 return retval;
84
85 (*blocks_alloc)++;
86 }
87
88 *ret_blk = b;
89 return 0;
90}
91
92static errcode_t block_dind_bmap(ext2_filsys fs, int flags,
93 blk_t dind, char *block_buf,
94 int *blocks_alloc,
95 blk_t nr, blk_t *ret_blk)
96{
97 blk_t b;
98 errcode_t retval;
99 blk_t addr_per_block;
100
101 addr_per_block = (blk_t) fs->blocksize >> 2;
102
103 retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf,
104 blocks_alloc, nr / addr_per_block, &b);
105 if (retval)
106 return retval;
107 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
108 nr % addr_per_block, ret_blk);
109 return retval;
110}
111
112static errcode_t block_tind_bmap(ext2_filsys fs, int flags,
113 blk_t tind, char *block_buf,
114 int *blocks_alloc,
115 blk_t nr, blk_t *ret_blk)
116{
117 blk_t b;
118 errcode_t retval;
119 blk_t addr_per_block;
120
121 addr_per_block = (blk_t) fs->blocksize >> 2;
122
123 retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf,
124 blocks_alloc, nr / addr_per_block, &b);
125 if (retval)
126 return retval;
127 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
128 nr % addr_per_block, ret_blk);
129 return retval;
130}
131
132errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
133 char *block_buf, int bmap_flags, blk_t block,
134 blk_t *phys_blk)
135{
136 struct ext2_inode inode_buf;
137 blk_t addr_per_block;
138 blk_t b;
139 char *buf = 0;
140 errcode_t retval = 0;
141 int blocks_alloc = 0, inode_dirty = 0;
142
143 if (!(bmap_flags & BMAP_SET))
144 *phys_blk = 0;
145
146 /* Read inode structure if necessary */
147 if (!inode) {
148 retval = ext2fs_read_inode(fs, ino, &inode_buf);
149 if (retval)
150 return retval;
151 inode = &inode_buf;
152 }
153 addr_per_block = (blk_t) fs->blocksize >> 2;
154
155 if (!block_buf) {
156 retval = ext2fs_get_mem(fs->blocksize * 2, &buf);
157 if (retval)
158 return retval;
159 block_buf = buf;
160 }
161
162 if (block < EXT2_NDIR_BLOCKS) {
163 if (bmap_flags & BMAP_SET) {
164 b = *phys_blk;
165#if BB_BIG_ENDIAN
166 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
167 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
168 b = ext2fs_swab32(b);
169#endif
170 inode_bmap(inode, block) = b;
171 inode_dirty++;
172 goto done;
173 }
174
175 *phys_blk = inode_bmap(inode, block);
176 b = block ? inode_bmap(inode, block-1) : 0;
177
178 if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
179 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
180 if (retval)
181 goto done;
182 inode_bmap(inode, block) = b;
183 blocks_alloc++;
184 *phys_blk = b;
185 }
186 goto done;
187 }
188
189 /* Indirect block */
190 block -= EXT2_NDIR_BLOCKS;
191 if (block < addr_per_block) {
192 b = inode_bmap(inode, EXT2_IND_BLOCK);
193 if (!b) {
194 if (!(bmap_flags & BMAP_ALLOC)) {
195 if (bmap_flags & BMAP_SET)
196 retval = EXT2_ET_SET_BMAP_NO_IND;
197 goto done;
198 }
199
200 b = inode_bmap(inode, EXT2_IND_BLOCK-1);
201 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
202 if (retval)
203 goto done;
204 inode_bmap(inode, EXT2_IND_BLOCK) = b;
205 blocks_alloc++;
206 }
207 retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
208 &blocks_alloc, block, phys_blk);
209 goto done;
210 }
211
212 /* Doubly indirect block */
213 block -= addr_per_block;
214 if (block < addr_per_block * addr_per_block) {
215 b = inode_bmap(inode, EXT2_DIND_BLOCK);
216 if (!b) {
217 if (!(bmap_flags & BMAP_ALLOC)) {
218 if (bmap_flags & BMAP_SET)
219 retval = EXT2_ET_SET_BMAP_NO_IND;
220 goto done;
221 }
222
223 b = inode_bmap(inode, EXT2_IND_BLOCK);
224 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
225 if (retval)
226 goto done;
227 inode_bmap(inode, EXT2_DIND_BLOCK) = b;
228 blocks_alloc++;
229 }
230 retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
231 &blocks_alloc, block, phys_blk);
232 goto done;
233 }
234
235 /* Triply indirect block */
236 block -= addr_per_block * addr_per_block;
237 b = inode_bmap(inode, EXT2_TIND_BLOCK);
238 if (!b) {
239 if (!(bmap_flags & BMAP_ALLOC)) {
240 if (bmap_flags & BMAP_SET)
241 retval = EXT2_ET_SET_BMAP_NO_IND;
242 goto done;
243 }
244
245 b = inode_bmap(inode, EXT2_DIND_BLOCK);
246 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
247 if (retval)
248 goto done;
249 inode_bmap(inode, EXT2_TIND_BLOCK) = b;
250 blocks_alloc++;
251 }
252 retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
253 &blocks_alloc, block, phys_blk);
254done:
255 ext2fs_free_mem(&buf);
256 if ((retval == 0) && (blocks_alloc || inode_dirty)) {
257 inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
258 retval = ext2fs_write_inode(fs, ino, inode);
259 }
260 return retval;
261}
262
263
264
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c b/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c
new file mode 100644
index 000000000..635410da5
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c
@@ -0,0 +1,156 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * bmove.c --- Move blocks around to make way for a particular
4 * filesystem structure.
5 *
6 * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed
7 * under the terms of the GNU Public License.
8 */
9
10#include <stdio.h>
11#include <string.h>
12#if HAVE_UNISTD_H
13#include <unistd.h>
14#endif
15#if HAVE_SYS_TYPES_H
16#include <sys/types.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fsP.h"
21
22struct process_block_struct {
23 ext2_ino_t ino;
24 struct ext2_inode * inode;
25 ext2fs_block_bitmap reserve;
26 ext2fs_block_bitmap alloc_map;
27 errcode_t error;
28 char *buf;
29 int add_dir;
30 int flags;
31};
32
33static int process_block(ext2_filsys fs, blk_t *block_nr,
34 e2_blkcnt_t blockcnt, blk_t ref_block,
35 int ref_offset, void *priv_data)
36{
37 struct process_block_struct *pb;
38 errcode_t retval;
39 int ret;
40 blk_t block, orig;
41
42 pb = (struct process_block_struct *) priv_data;
43 block = orig = *block_nr;
44 ret = 0;
45
46 /*
47 * Let's see if this is one which we need to relocate
48 */
49 if (ext2fs_test_block_bitmap(pb->reserve, block)) {
50 do {
51 if (++block >= fs->super->s_blocks_count)
52 block = fs->super->s_first_data_block;
53 if (block == orig) {
54 pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
55 return BLOCK_ABORT;
56 }
57 } while (ext2fs_test_block_bitmap(pb->reserve, block) ||
58 ext2fs_test_block_bitmap(pb->alloc_map, block));
59
60 retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
61 if (retval) {
62 pb->error = retval;
63 return BLOCK_ABORT;
64 }
65 retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
66 if (retval) {
67 pb->error = retval;
68 return BLOCK_ABORT;
69 }
70 *block_nr = block;
71 ext2fs_mark_block_bitmap(pb->alloc_map, block);
72 ret = BLOCK_CHANGED;
73 if (pb->flags & EXT2_BMOVE_DEBUG)
74 printf("ino=%ld, blockcnt=%lld, %d->%d\n", pb->ino,
75 blockcnt, orig, block);
76 }
77 if (pb->add_dir) {
78 retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
79 block, (int) blockcnt);
80 if (retval) {
81 pb->error = retval;
82 ret |= BLOCK_ABORT;
83 }
84 }
85 return ret;
86}
87
88errcode_t ext2fs_move_blocks(ext2_filsys fs,
89 ext2fs_block_bitmap reserve,
90 ext2fs_block_bitmap alloc_map,
91 int flags)
92{
93 ext2_ino_t ino;
94 struct ext2_inode inode;
95 errcode_t retval;
96 struct process_block_struct pb;
97 ext2_inode_scan scan;
98 char *block_buf;
99
100 retval = ext2fs_open_inode_scan(fs, 0, &scan);
101 if (retval)
102 return retval;
103
104 pb.reserve = reserve;
105 pb.error = 0;
106 pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
107 pb.flags = flags;
108
109 retval = ext2fs_get_mem(fs->blocksize * 4, &block_buf);
110 if (retval)
111 return retval;
112 pb.buf = block_buf + fs->blocksize * 3;
113
114 /*
115 * If GET_DBLIST is set in the flags field, then we should
116 * gather directory block information while we're doing the
117 * block move.
118 */
119 if (flags & EXT2_BMOVE_GET_DBLIST) {
120 ext2fs_free_dblist(fs->dblist);
121 fs->dblist = NULL;
122 retval = ext2fs_init_dblist(fs, 0);
123 if (retval)
124 return retval;
125 }
126
127 retval = ext2fs_get_next_inode(scan, &ino, &inode);
128 if (retval)
129 return retval;
130
131 while (ino) {
132 if ((inode.i_links_count == 0) ||
133 !ext2fs_inode_has_valid_blocks(&inode))
134 goto next;
135
136 pb.ino = ino;
137 pb.inode = &inode;
138
139 pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
140 flags & EXT2_BMOVE_GET_DBLIST);
141
142 retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
143 process_block, &pb);
144 if (retval)
145 return retval;
146 if (pb.error)
147 return pb.error;
148
149 next:
150 retval = ext2fs_get_next_inode(scan, &ino, &inode);
151 if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
152 goto next;
153 }
154 return 0;
155}
156
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/brel.h b/e2fsprogs/old_e2fsprogs/ext2fs/brel.h
new file mode 100644
index 000000000..216fd132c
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/brel.h
@@ -0,0 +1,87 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * brel.h
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13struct ext2_block_relocate_entry {
14 blk_t new;
15 __s16 offset;
16 __u16 flags;
17 union {
18 blk_t block_ref;
19 ext2_ino_t inode_ref;
20 } owner;
21};
22
23#define RELOCATE_TYPE_REF 0x0007
24#define RELOCATE_BLOCK_REF 0x0001
25#define RELOCATE_INODE_REF 0x0002
26
27typedef struct ext2_block_relocation_table *ext2_brel;
28
29struct ext2_block_relocation_table {
30 __u32 magic;
31 char *name;
32 blk_t current;
33 void *priv_data;
34
35 /*
36 * Add a block relocation entry.
37 */
38 errcode_t (*put)(ext2_brel brel, blk_t old,
39 struct ext2_block_relocate_entry *ent);
40
41 /*
42 * Get a block relocation entry.
43 */
44 errcode_t (*get)(ext2_brel brel, blk_t old,
45 struct ext2_block_relocate_entry *ent);
46
47 /*
48 * Initialize for iterating over the block relocation entries.
49 */
50 errcode_t (*start_iter)(ext2_brel brel);
51
52 /*
53 * The iterator function for the inode relocation entries.
54 * Returns an inode number of 0 when out of entries.
55 */
56 errcode_t (*next)(ext2_brel brel, blk_t *old,
57 struct ext2_block_relocate_entry *ent);
58
59 /*
60 * Move the inode relocation table from one block number to
61 * another.
62 */
63 errcode_t (*move)(ext2_brel brel, blk_t old, blk_t new);
64
65 /*
66 * Remove a block relocation entry.
67 */
68 errcode_t (*delete)(ext2_brel brel, blk_t old);
69
70
71 /*
72 * Free the block relocation table.
73 */
74 errcode_t (*free)(ext2_brel brel);
75};
76
77errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
78 ext2_brel *brel);
79
80#define ext2fs_brel_put(brel, old, ent) ((brel)->put((brel), old, ent))
81#define ext2fs_brel_get(brel, old, ent) ((brel)->get((brel), old, ent))
82#define ext2fs_brel_start_iter(brel) ((brel)->start_iter((brel)))
83#define ext2fs_brel_next(brel, old, ent) ((brel)->next((brel), old, ent))
84#define ext2fs_brel_move(brel, old, new) ((brel)->move((brel), old, new))
85#define ext2fs_brel_delete(brel, old) ((brel)->delete((brel), old))
86#define ext2fs_brel_free(brel) ((brel)->free((brel)))
87
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/brel_ma.c b/e2fsprogs/old_e2fsprogs/ext2fs/brel_ma.c
new file mode 100644
index 000000000..652a3509c
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/brel_ma.c
@@ -0,0 +1,196 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * brel_ma.c
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * TODO: rewrite to not use a direct array!!! (Fortunately this
8 * module isn't really used yet.)
9 *
10 * %Begin-Header%
11 * This file may be redistributed under the terms of the GNU Public
12 * License.
13 * %End-Header%
14 */
15
16#include <fcntl.h>
17#include <stdio.h>
18#include <string.h>
19#if HAVE_UNISTD_H
20#include <unistd.h>
21#endif
22#if HAVE_ERRNO_H
23#include <errno.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28#include "brel.h"
29
30static errcode_t bma_put(ext2_brel brel, blk_t old,
31 struct ext2_block_relocate_entry *ent);
32static errcode_t bma_get(ext2_brel brel, blk_t old,
33 struct ext2_block_relocate_entry *ent);
34static errcode_t bma_start_iter(ext2_brel brel);
35static errcode_t bma_next(ext2_brel brel, blk_t *old,
36 struct ext2_block_relocate_entry *ent);
37static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new);
38static errcode_t bma_delete(ext2_brel brel, blk_t old);
39static errcode_t bma_free(ext2_brel brel);
40
41struct brel_ma {
42 __u32 magic;
43 blk_t max_block;
44 struct ext2_block_relocate_entry *entries;
45};
46
47errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
48 ext2_brel *new_brel)
49{
50 ext2_brel brel = 0;
51 errcode_t retval;
52 struct brel_ma *ma = 0;
53 size_t size;
54
55 *new_brel = 0;
56
57 /*
58 * Allocate memory structures
59 */
60 retval = ext2fs_get_mem(sizeof(struct ext2_block_relocation_table),
61 &brel);
62 if (retval)
63 goto errout;
64 memset(brel, 0, sizeof(struct ext2_block_relocation_table));
65
66 retval = ext2fs_get_mem(strlen(name)+1, &brel->name);
67 if (retval)
68 goto errout;
69 strcpy(brel->name, name);
70
71 retval = ext2fs_get_mem(sizeof(struct brel_ma), &ma);
72 if (retval)
73 goto errout;
74 memset(ma, 0, sizeof(struct brel_ma));
75 brel->priv_data = ma;
76
77 size = (size_t) (sizeof(struct ext2_block_relocate_entry) *
78 (max_block+1));
79 retval = ext2fs_get_mem(size, &ma->entries);
80 if (retval)
81 goto errout;
82 memset(ma->entries, 0, size);
83 ma->max_block = max_block;
84
85 /*
86 * Fill in the brel data structure
87 */
88 brel->put = bma_put;
89 brel->get = bma_get;
90 brel->start_iter = bma_start_iter;
91 brel->next = bma_next;
92 brel->move = bma_move;
93 brel->delete = bma_delete;
94 brel->free = bma_free;
95
96 *new_brel = brel;
97 return 0;
98
99errout:
100 bma_free(brel);
101 return retval;
102}
103
104static errcode_t bma_put(ext2_brel brel, blk_t old,
105 struct ext2_block_relocate_entry *ent)
106{
107 struct brel_ma *ma;
108
109 ma = brel->priv_data;
110 if (old > ma->max_block)
111 return EXT2_ET_INVALID_ARGUMENT;
112 ma->entries[(unsigned)old] = *ent;
113 return 0;
114}
115
116static errcode_t bma_get(ext2_brel brel, blk_t old,
117 struct ext2_block_relocate_entry *ent)
118{
119 struct brel_ma *ma;
120
121 ma = brel->priv_data;
122 if (old > ma->max_block)
123 return EXT2_ET_INVALID_ARGUMENT;
124 if (ma->entries[(unsigned)old].new == 0)
125 return ENOENT;
126 *ent = ma->entries[old];
127 return 0;
128}
129
130static errcode_t bma_start_iter(ext2_brel brel)
131{
132 brel->current = 0;
133 return 0;
134}
135
136static errcode_t bma_next(ext2_brel brel, blk_t *old,
137 struct ext2_block_relocate_entry *ent)
138{
139 struct brel_ma *ma;
140
141 ma = brel->priv_data;
142 while (++brel->current < ma->max_block) {
143 if (ma->entries[(unsigned)brel->current].new == 0)
144 continue;
145 *old = brel->current;
146 *ent = ma->entries[(unsigned)brel->current];
147 return 0;
148 }
149 *old = 0;
150 return 0;
151}
152
153static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new)
154{
155 struct brel_ma *ma;
156
157 ma = brel->priv_data;
158 if ((old > ma->max_block) || (new > ma->max_block))
159 return EXT2_ET_INVALID_ARGUMENT;
160 if (ma->entries[(unsigned)old].new == 0)
161 return ENOENT;
162 ma->entries[(unsigned)new] = ma->entries[old];
163 ma->entries[(unsigned)old].new = 0;
164 return 0;
165}
166
167static errcode_t bma_delete(ext2_brel brel, blk_t old)
168{
169 struct brel_ma *ma;
170
171 ma = brel->priv_data;
172 if (old > ma->max_block)
173 return EXT2_ET_INVALID_ARGUMENT;
174 if (ma->entries[(unsigned)old].new == 0)
175 return ENOENT;
176 ma->entries[(unsigned)old].new = 0;
177 return 0;
178}
179
180static errcode_t bma_free(ext2_brel brel)
181{
182 struct brel_ma *ma;
183
184 if (!brel)
185 return 0;
186
187 ma = brel->priv_data;
188
189 if (ma) {
190 ext2fs_free_mem(&ma->entries);
191 ext2fs_free_mem(&ma);
192 }
193 ext2fs_free_mem(&brel->name);
194 ext2fs_free_mem(&brel);
195 return 0;
196}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/check_desc.c b/e2fsprogs/old_e2fsprogs/ext2fs/check_desc.c
new file mode 100644
index 000000000..dd4b0e9cf
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/check_desc.c
@@ -0,0 +1,69 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * check_desc.c --- Check the group descriptors of an ext2 filesystem
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29
30/*
31 * This routine sanity checks the group descriptors
32 */
33errcode_t ext2fs_check_desc(ext2_filsys fs)
34{
35 dgrp_t i;
36 blk_t block = fs->super->s_first_data_block;
37 blk_t next;
38
39 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
40
41 for (i = 0; i < fs->group_desc_count; i++) {
42 next = block + fs->super->s_blocks_per_group;
43 /*
44 * Check to make sure block bitmap for group is
45 * located within the group.
46 */
47 if (fs->group_desc[i].bg_block_bitmap < block ||
48 fs->group_desc[i].bg_block_bitmap >= next)
49 return EXT2_ET_GDESC_BAD_BLOCK_MAP;
50 /*
51 * Check to make sure inode bitmap for group is
52 * located within the group
53 */
54 if (fs->group_desc[i].bg_inode_bitmap < block ||
55 fs->group_desc[i].bg_inode_bitmap >= next)
56 return EXT2_ET_GDESC_BAD_INODE_MAP;
57 /*
58 * Check to make sure inode table for group is located
59 * within the group
60 */
61 if (fs->group_desc[i].bg_inode_table < block ||
62 ((fs->group_desc[i].bg_inode_table +
63 fs->inode_blocks_per_group) >= next))
64 return EXT2_ET_GDESC_BAD_INODE_TABLE;
65
66 block = next;
67 }
68 return 0;
69}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c b/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c
new file mode 100644
index 000000000..008d5f36e
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c
@@ -0,0 +1,381 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * closefs.c --- close an ext2 filesystem
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <time.h>
18#include <string.h>
19
20#include "ext2_fs.h"
21#include "ext2fsP.h"
22
23static int test_root(int a, int b)
24{
25 if (a == 0)
26 return 1;
27 while (1) {
28 if (a == 1)
29 return 1;
30 if (a % b)
31 return 0;
32 a = a / b;
33 }
34}
35
36int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
37{
38 if (!(fs->super->s_feature_ro_compat &
39 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
40 return 1;
41
42 if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
43 test_root(group_block, 7))
44 return 1;
45
46 return 0;
47}
48
49int ext2fs_super_and_bgd_loc(ext2_filsys fs,
50 dgrp_t group,
51 blk_t *ret_super_blk,
52 blk_t *ret_old_desc_blk,
53 blk_t *ret_new_desc_blk,
54 int *ret_meta_bg)
55{
56 blk_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
57 unsigned int meta_bg, meta_bg_size;
58 int numblocks, has_super;
59 int old_desc_blocks;
60
61 group_block = fs->super->s_first_data_block +
62 (group * fs->super->s_blocks_per_group);
63
64 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
65 old_desc_blocks = fs->super->s_first_meta_bg;
66 else
67 old_desc_blocks =
68 fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
69
70 if (group == fs->group_desc_count-1) {
71 numblocks = (fs->super->s_blocks_count -
72 fs->super->s_first_data_block) %
73 fs->super->s_blocks_per_group;
74 if (!numblocks)
75 numblocks = fs->super->s_blocks_per_group;
76 } else
77 numblocks = fs->super->s_blocks_per_group;
78
79 has_super = ext2fs_bg_has_super(fs, group);
80
81 if (has_super) {
82 super_blk = group_block;
83 numblocks--;
84 }
85 meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
86 meta_bg = group / meta_bg_size;
87
88 if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
89 (meta_bg < fs->super->s_first_meta_bg)) {
90 if (has_super) {
91 old_desc_blk = group_block + 1;
92 numblocks -= old_desc_blocks;
93 }
94 } else {
95 if (((group % meta_bg_size) == 0) ||
96 ((group % meta_bg_size) == 1) ||
97 ((group % meta_bg_size) == (meta_bg_size-1))) {
98 if (has_super)
99 has_super = 1;
100 new_desc_blk = group_block + has_super;
101 numblocks--;
102 }
103 }
104
105 numblocks -= 2 + fs->inode_blocks_per_group;
106
107 if (ret_super_blk)
108 *ret_super_blk = super_blk;
109 if (ret_old_desc_blk)
110 *ret_old_desc_blk = old_desc_blk;
111 if (ret_new_desc_blk)
112 *ret_new_desc_blk = new_desc_blk;
113 if (ret_meta_bg)
114 *ret_meta_bg = meta_bg;
115 return numblocks;
116}
117
118
119/*
120 * This function forces out the primary superblock. We need to only
121 * write out those fields which we have changed, since if the
122 * filesystem is mounted, it may have changed some of the other
123 * fields.
124 *
125 * It takes as input a superblock which has already been byte swapped
126 * (if necessary).
127 *
128 */
129static errcode_t write_primary_superblock(ext2_filsys fs,
130 struct ext2_super_block *super)
131{
132 __u16 *old_super, *new_super;
133 int check_idx, write_idx, size;
134 errcode_t retval;
135
136 if (!fs->io->manager->write_byte || !fs->orig_super) {
137 io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
138 retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
139 super);
140 io_channel_set_blksize(fs->io, fs->blocksize);
141 return retval;
142 }
143
144 old_super = (__u16 *) fs->orig_super;
145 new_super = (__u16 *) super;
146
147 for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) {
148 if (old_super[check_idx] == new_super[check_idx])
149 continue;
150 write_idx = check_idx;
151 for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++)
152 if (old_super[check_idx] == new_super[check_idx])
153 break;
154 size = 2 * (check_idx - write_idx);
155 retval = io_channel_write_byte(fs->io,
156 SUPERBLOCK_OFFSET + (2 * write_idx), size,
157 new_super + write_idx);
158 if (retval)
159 return retval;
160 }
161 memcpy(fs->orig_super, super, SUPERBLOCK_SIZE);
162 return 0;
163}
164
165
166/*
167 * Updates the revision to EXT2_DYNAMIC_REV
168 */
169void ext2fs_update_dynamic_rev(ext2_filsys fs)
170{
171 struct ext2_super_block *sb = fs->super;
172
173 if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
174 return;
175
176 sb->s_rev_level = EXT2_DYNAMIC_REV;
177 sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
178 sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
179 /* s_uuid is handled by e2fsck already */
180 /* other fields should be left alone */
181}
182
183static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
184 blk_t group_block,
185 struct ext2_super_block *super_shadow)
186{
187 dgrp_t sgrp = group;
188
189 if (sgrp > ((1 << 16) - 1))
190 sgrp = (1 << 16) - 1;
191#if BB_BIG_ENDIAN
192 if (fs->flags & EXT2_FLAG_SWAP_BYTES)
193 super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
194 else
195#endif
196 fs->super->s_block_group_nr = sgrp;
197
198 return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE,
199 super_shadow);
200}
201
202
203errcode_t ext2fs_flush(ext2_filsys fs)
204{
205 dgrp_t i;
206 blk_t group_block;
207 errcode_t retval;
208 unsigned long fs_state;
209 struct ext2_super_block *super_shadow = 0;
210 struct ext2_group_desc *group_shadow = 0;
211 char *group_ptr;
212 int old_desc_blocks;
213#if BB_BIG_ENDIAN
214 dgrp_t j;
215 struct ext2_group_desc *s, *t;
216#endif
217
218 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
219
220 fs_state = fs->super->s_state;
221
222 fs->super->s_wtime = time(NULL);
223 fs->super->s_block_group_nr = 0;
224#if BB_BIG_ENDIAN
225 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
226 retval = EXT2_ET_NO_MEMORY;
227 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
228 if (retval)
229 goto errout;
230 retval = ext2fs_get_mem((size_t)(fs->blocksize *
231 fs->desc_blocks),
232 &group_shadow);
233 if (retval)
234 goto errout;
235 memset(group_shadow, 0, (size_t) fs->blocksize *
236 fs->desc_blocks);
237
238 /* swap the group descriptors */
239 for (j=0, s=fs->group_desc, t=group_shadow;
240 j < fs->group_desc_count; j++, t++, s++) {
241 *t = *s;
242 ext2fs_swap_group_desc(t);
243 }
244 } else {
245 super_shadow = fs->super;
246 group_shadow = fs->group_desc;
247 }
248#else
249 super_shadow = fs->super;
250 group_shadow = fs->group_desc;
251#endif
252
253 /*
254 * If this is an external journal device, don't write out the
255 * block group descriptors or any of the backup superblocks
256 */
257 if (fs->super->s_feature_incompat &
258 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
259 goto write_primary_superblock_only;
260
261 /*
262 * Set the state of the FS to be non-valid. (The state has
263 * already been backed up earlier, and will be restored after
264 * we write out the backup superblocks.)
265 */
266 fs->super->s_state &= ~EXT2_VALID_FS;
267#if BB_BIG_ENDIAN
268 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
269 *super_shadow = *fs->super;
270 ext2fs_swap_super(super_shadow);
271 }
272#endif
273
274 /*
275 * Write out the master group descriptors, and the backup
276 * superblocks and group descriptors.
277 */
278 group_block = fs->super->s_first_data_block;
279 group_ptr = (char *) group_shadow;
280 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
281 old_desc_blocks = fs->super->s_first_meta_bg;
282 else
283 old_desc_blocks = fs->desc_blocks;
284
285 for (i = 0; i < fs->group_desc_count; i++) {
286 blk_t super_blk, old_desc_blk, new_desc_blk;
287 int meta_bg;
288
289 ext2fs_super_and_bgd_loc(fs, i, &super_blk, &old_desc_blk,
290 &new_desc_blk, &meta_bg);
291
292 if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) {
293 retval = write_backup_super(fs, i, super_blk,
294 super_shadow);
295 if (retval)
296 goto errout;
297 }
298 if (fs->flags & EXT2_FLAG_SUPER_ONLY)
299 continue;
300 if ((old_desc_blk) &&
301 (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) {
302 retval = io_channel_write_blk(fs->io,
303 old_desc_blk, old_desc_blocks, group_ptr);
304 if (retval)
305 goto errout;
306 }
307 if (new_desc_blk) {
308 retval = io_channel_write_blk(fs->io, new_desc_blk,
309 1, group_ptr + (meta_bg*fs->blocksize));
310 if (retval)
311 goto errout;
312 }
313 }
314 fs->super->s_block_group_nr = 0;
315 fs->super->s_state = fs_state;
316#if BB_BIG_ENDIAN
317 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
318 *super_shadow = *fs->super;
319 ext2fs_swap_super(super_shadow);
320 }
321#endif
322
323 /*
324 * If the write_bitmaps() function is present, call it to
325 * flush the bitmaps. This is done this way so that a simple
326 * program that doesn't mess with the bitmaps doesn't need to
327 * drag in the bitmaps.c code.
328 */
329 if (fs->write_bitmaps) {
330 retval = fs->write_bitmaps(fs);
331 if (retval)
332 goto errout;
333 }
334
335write_primary_superblock_only:
336 /*
337 * Write out master superblock. This has to be done
338 * separately, since it is located at a fixed location
339 * (SUPERBLOCK_OFFSET). We flush all other pending changes
340 * out to disk first, just to avoid a race condition with an
341 * insy-tinsy window....
342 */
343 retval = io_channel_flush(fs->io);
344 retval = write_primary_superblock(fs, super_shadow);
345 if (retval)
346 goto errout;
347
348 fs->flags &= ~EXT2_FLAG_DIRTY;
349
350 retval = io_channel_flush(fs->io);
351errout:
352 fs->super->s_state = fs_state;
353 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
354 if (super_shadow)
355 ext2fs_free_mem(&super_shadow);
356 if (group_shadow)
357 ext2fs_free_mem(&group_shadow);
358 }
359 return retval;
360}
361
362errcode_t ext2fs_close(ext2_filsys fs)
363{
364 errcode_t retval;
365
366 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
367
368 if (fs->flags & EXT2_FLAG_DIRTY) {
369 retval = ext2fs_flush(fs);
370 if (retval)
371 return retval;
372 }
373 if (fs->write_bitmaps) {
374 retval = fs->write_bitmaps(fs);
375 if (retval)
376 return retval;
377 }
378 ext2fs_free(fs);
379 return 0;
380}
381
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c b/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c
new file mode 100644
index 000000000..05b8eb8d7
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c
@@ -0,0 +1,73 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * cmp_bitmaps.c --- routines to compare inode and block bitmaps.
4 *
5 * Copyright (C) 1995 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29
30errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
31 ext2fs_block_bitmap bm2)
32{
33 blk_t i;
34
35 EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_BLOCK_BITMAP);
36 EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_BLOCK_BITMAP);
37
38 if ((bm1->start != bm2->start) ||
39 (bm1->end != bm2->end) ||
40 (memcmp(bm1->bitmap, bm2->bitmap,
41 (size_t) (bm1->end - bm1->start)/8)))
42 return EXT2_ET_NEQ_BLOCK_BITMAP;
43
44 for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
45 if (ext2fs_fast_test_block_bitmap(bm1, i) !=
46 ext2fs_fast_test_block_bitmap(bm2, i))
47 return EXT2_ET_NEQ_BLOCK_BITMAP;
48
49 return 0;
50}
51
52errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
53 ext2fs_inode_bitmap bm2)
54{
55 ext2_ino_t i;
56
57 EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_INODE_BITMAP);
58 EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_INODE_BITMAP);
59
60 if ((bm1->start != bm2->start) ||
61 (bm1->end != bm2->end) ||
62 (memcmp(bm1->bitmap, bm2->bitmap,
63 (size_t) (bm1->end - bm1->start)/8)))
64 return EXT2_ET_NEQ_INODE_BITMAP;
65
66 for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
67 if (ext2fs_fast_test_inode_bitmap(bm1, i) !=
68 ext2fs_fast_test_inode_bitmap(bm2, i))
69 return EXT2_ET_NEQ_INODE_BITMAP;
70
71 return 0;
72}
73
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/dblist.c b/e2fsprogs/old_e2fsprogs/ext2fs/dblist.c
new file mode 100644
index 000000000..06ff6d807
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/dblist.c
@@ -0,0 +1,260 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * dblist.c -- directory block list functions
4 *
5 * Copyright 1997 by Theodore Ts'o
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 *
12 */
13
14#include <stdio.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <string.h>
19#include <time.h>
20
21#include "ext2_fs.h"
22#include "ext2fsP.h"
23
24static int dir_block_cmp(const void *a, const void *b);
25
26/*
27 * Returns the number of directories in the filesystem as reported by
28 * the group descriptors. Of course, the group descriptors could be
29 * wrong!
30 */
31errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
32{
33 dgrp_t i;
34 ext2_ino_t num_dirs, max_dirs;
35
36 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
37
38 num_dirs = 0;
39 max_dirs = fs->super->s_inodes_per_group;
40 for (i = 0; i < fs->group_desc_count; i++) {
41 if (fs->group_desc[i].bg_used_dirs_count > max_dirs)
42 num_dirs += max_dirs / 8;
43 else
44 num_dirs += fs->group_desc[i].bg_used_dirs_count;
45 }
46 if (num_dirs > fs->super->s_inodes_count)
47 num_dirs = fs->super->s_inodes_count;
48
49 *ret_num_dirs = num_dirs;
50
51 return 0;
52}
53
54/*
55 * helper function for making a new directory block list (for
56 * initialize and copy).
57 */
58static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size, ext2_ino_t count,
59 struct ext2_db_entry *list,
60 ext2_dblist *ret_dblist)
61{
62 ext2_dblist dblist;
63 errcode_t retval;
64 size_t len;
65
66 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
67
68 if ((ret_dblist == 0) && fs->dblist &&
69 (fs->dblist->magic == EXT2_ET_MAGIC_DBLIST))
70 return 0;
71
72 retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist);
73 if (retval)
74 return retval;
75 memset(dblist, 0, sizeof(struct ext2_struct_dblist));
76
77 dblist->magic = EXT2_ET_MAGIC_DBLIST;
78 dblist->fs = fs;
79 if (size)
80 dblist->size = size;
81 else {
82 retval = ext2fs_get_num_dirs(fs, &dblist->size);
83 if (retval)
84 goto cleanup;
85 dblist->size = (dblist->size * 2) + 12;
86 }
87 len = (size_t) sizeof(struct ext2_db_entry) * dblist->size;
88 dblist->count = count;
89 retval = ext2fs_get_mem(len, &dblist->list);
90 if (retval)
91 goto cleanup;
92
93 if (list)
94 memcpy(dblist->list, list, len);
95 else
96 memset(dblist->list, 0, len);
97 if (ret_dblist)
98 *ret_dblist = dblist;
99 else
100 fs->dblist = dblist;
101 return 0;
102cleanup:
103 ext2fs_free_mem(&dblist);
104 return retval;
105}
106
107/*
108 * Initialize a directory block list
109 */
110errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist)
111{
112 ext2_dblist dblist;
113 errcode_t retval;
114
115 retval = make_dblist(fs, 0, 0, 0, &dblist);
116 if (retval)
117 return retval;
118
119 dblist->sorted = 1;
120 if (ret_dblist)
121 *ret_dblist = dblist;
122 else
123 fs->dblist = dblist;
124
125 return 0;
126}
127
128/*
129 * Copy a directory block list
130 */
131errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)
132{
133 ext2_dblist dblist;
134 errcode_t retval;
135
136 retval = make_dblist(src->fs, src->size, src->count, src->list,
137 &dblist);
138 if (retval)
139 return retval;
140 dblist->sorted = src->sorted;
141 *dest = dblist;
142 return 0;
143}
144
145/*
146 * Close a directory block list
147 *
148 * (moved to closefs.c)
149 */
150
151
152/*
153 * Add a directory block to the directory block list
154 */
155errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
156 int blockcnt)
157{
158 struct ext2_db_entry *new_entry;
159 errcode_t retval;
160 unsigned long old_size;
161
162 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
163
164 if (dblist->count >= dblist->size) {
165 old_size = dblist->size * sizeof(struct ext2_db_entry);
166 dblist->size += 100;
167 retval = ext2fs_resize_mem(old_size, (size_t) dblist->size *
168 sizeof(struct ext2_db_entry),
169 &dblist->list);
170 if (retval) {
171 dblist->size -= 100;
172 return retval;
173 }
174 }
175 new_entry = dblist->list + ( (int) dblist->count++);
176 new_entry->blk = blk;
177 new_entry->ino = ino;
178 new_entry->blockcnt = blockcnt;
179
180 dblist->sorted = 0;
181
182 return 0;
183}
184
185/*
186 * Change the directory block to the directory block list
187 */
188errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
189 int blockcnt)
190{
191 dgrp_t i;
192
193 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
194
195 for (i=0; i < dblist->count; i++) {
196 if ((dblist->list[i].ino != ino) ||
197 (dblist->list[i].blockcnt != blockcnt))
198 continue;
199 dblist->list[i].blk = blk;
200 dblist->sorted = 0;
201 return 0;
202 }
203 return EXT2_ET_DB_NOT_FOUND;
204}
205
206void ext2fs_dblist_sort(ext2_dblist dblist,
207 int (*sortfunc)(const void *,
208 const void *))
209{
210 if (!sortfunc)
211 sortfunc = dir_block_cmp;
212 qsort(dblist->list, (size_t) dblist->count,
213 sizeof(struct ext2_db_entry), sortfunc);
214 dblist->sorted = 1;
215}
216
217/*
218 * This function iterates over the directory block list
219 */
220errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
221 int (*func)(ext2_filsys fs,
222 struct ext2_db_entry *db_info,
223 void *priv_data),
224 void *priv_data)
225{
226 ext2_ino_t i;
227 int ret;
228
229 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
230
231 if (!dblist->sorted)
232 ext2fs_dblist_sort(dblist, 0);
233 for (i=0; i < dblist->count; i++) {
234 ret = (*func)(dblist->fs, &dblist->list[(int)i], priv_data);
235 if (ret & DBLIST_ABORT)
236 return 0;
237 }
238 return 0;
239}
240
241static int dir_block_cmp(const void *a, const void *b)
242{
243 const struct ext2_db_entry *db_a =
244 (const struct ext2_db_entry *) a;
245 const struct ext2_db_entry *db_b =
246 (const struct ext2_db_entry *) b;
247
248 if (db_a->blk != db_b->blk)
249 return (int) (db_a->blk - db_b->blk);
250
251 if (db_a->ino != db_b->ino)
252 return (int) (db_a->ino - db_b->ino);
253
254 return (int) (db_a->blockcnt - db_b->blockcnt);
255}
256
257int ext2fs_dblist_count(ext2_dblist dblist)
258{
259 return (int) dblist->count;
260}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/dblist_dir.c b/e2fsprogs/old_e2fsprogs/ext2fs/dblist_dir.c
new file mode 100644
index 000000000..b23920466
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/dblist_dir.c
@@ -0,0 +1,76 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * dblist_dir.c --- iterate by directory entry
4 *
5 * Copyright 1997 by Theodore Ts'o
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 *
12 */
13
14#include <stdio.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <string.h>
19#include <time.h>
20
21#include "ext2_fs.h"
22#include "ext2fsP.h"
23
24static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
25 void *priv_data);
26
27errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist,
28 int flags,
29 char *block_buf,
30 int (*func)(ext2_ino_t dir,
31 int entry,
32 struct ext2_dir_entry *dirent,
33 int offset,
34 int blocksize,
35 char *buf,
36 void *priv_data),
37 void *priv_data)
38{
39 errcode_t retval;
40 struct dir_context ctx;
41
42 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
43
44 ctx.dir = 0;
45 ctx.flags = flags;
46 if (block_buf)
47 ctx.buf = block_buf;
48 else {
49 retval = ext2fs_get_mem(dblist->fs->blocksize, &ctx.buf);
50 if (retval)
51 return retval;
52 }
53 ctx.func = func;
54 ctx.priv_data = priv_data;
55 ctx.errcode = 0;
56
57 retval = ext2fs_dblist_iterate(dblist, db_dir_proc, &ctx);
58
59 if (!block_buf)
60 ext2fs_free_mem(&ctx.buf);
61 if (retval)
62 return retval;
63 return ctx.errcode;
64}
65
66static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
67 void *priv_data)
68{
69 struct dir_context *ctx;
70
71 ctx = (struct dir_context *) priv_data;
72 ctx->dir = db_info->ino;
73
74 return ext2fs_process_dir_block(fs, &db_info->blk,
75 db_info->blockcnt, 0, 0, priv_data);
76}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c b/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c
new file mode 100644
index 000000000..b7d873595
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c
@@ -0,0 +1,220 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * dir_iterate.c --- ext2fs directory iteration operations
4 *
5 * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#if HAVE_ERRNO_H
19#include <errno.h>
20#endif
21
22#include "ext2_fs.h"
23#include "ext2fsP.h"
24
25/*
26 * This function checks to see whether or not a potential deleted
27 * directory entry looks valid. What we do is check the deleted entry
28 * and each successive entry to make sure that they all look valid and
29 * that the last deleted entry ends at the beginning of the next
30 * undeleted entry. Returns 1 if the deleted entry looks valid, zero
31 * if not valid.
32 */
33static int ext2fs_validate_entry(char *buf, int offset, int final_offset)
34{
35 struct ext2_dir_entry *dirent;
36
37 while (offset < final_offset) {
38 dirent = (struct ext2_dir_entry *)(buf + offset);
39 offset += dirent->rec_len;
40 if ((dirent->rec_len < 8) ||
41 ((dirent->rec_len % 4) != 0) ||
42 (((dirent->name_len & 0xFF)+8) > dirent->rec_len))
43 return 0;
44 }
45 return (offset == final_offset);
46}
47
48errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
49 ext2_ino_t dir,
50 int flags,
51 char *block_buf,
52 int (*func)(ext2_ino_t dir,
53 int entry,
54 struct ext2_dir_entry *dirent,
55 int offset,
56 int blocksize,
57 char *buf,
58 void *priv_data),
59 void *priv_data)
60{
61 struct dir_context ctx;
62 errcode_t retval;
63
64 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
65
66 retval = ext2fs_check_directory(fs, dir);
67 if (retval)
68 return retval;
69
70 ctx.dir = dir;
71 ctx.flags = flags;
72 if (block_buf)
73 ctx.buf = block_buf;
74 else {
75 retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
76 if (retval)
77 return retval;
78 }
79 ctx.func = func;
80 ctx.priv_data = priv_data;
81 ctx.errcode = 0;
82 retval = ext2fs_block_iterate2(fs, dir, 0, 0,
83 ext2fs_process_dir_block, &ctx);
84 if (!block_buf)
85 ext2fs_free_mem(&ctx.buf);
86 if (retval)
87 return retval;
88 return ctx.errcode;
89}
90
91struct xlate {
92 int (*func)(struct ext2_dir_entry *dirent,
93 int offset,
94 int blocksize,
95 char *buf,
96 void *priv_data);
97 void *real_private;
98};
99
100static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
101 int entry EXT2FS_ATTR((unused)),
102 struct ext2_dir_entry *dirent, int offset,
103 int blocksize, char *buf, void *priv_data)
104{
105 struct xlate *xl = (struct xlate *) priv_data;
106
107 return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
108}
109
110extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
111 ext2_ino_t dir,
112 int flags,
113 char *block_buf,
114 int (*func)(struct ext2_dir_entry *dirent,
115 int offset,
116 int blocksize,
117 char *buf,
118 void *priv_data),
119 void *priv_data)
120{
121 struct xlate xl;
122
123 xl.real_private = priv_data;
124 xl.func = func;
125
126 return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
127 xlate_func, &xl);
128}
129
130
131/*
132 * Helper function which is private to this module. Used by
133 * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
134 */
135int ext2fs_process_dir_block(ext2_filsys fs,
136 blk_t *blocknr,
137 e2_blkcnt_t blockcnt,
138 blk_t ref_block EXT2FS_ATTR((unused)),
139 int ref_offset EXT2FS_ATTR((unused)),
140 void *priv_data)
141{
142 struct dir_context *ctx = (struct dir_context *) priv_data;
143 unsigned int offset = 0;
144 unsigned int next_real_entry = 0;
145 int ret = 0;
146 int changed = 0;
147 int do_abort = 0;
148 int entry, size;
149 struct ext2_dir_entry *dirent;
150
151 if (blockcnt < 0)
152 return 0;
153
154 entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
155
156 ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf);
157 if (ctx->errcode)
158 return BLOCK_ABORT;
159
160 while (offset < fs->blocksize) {
161 dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
162 if (((offset + dirent->rec_len) > fs->blocksize) ||
163 (dirent->rec_len < 8) ||
164 ((dirent->rec_len % 4) != 0) ||
165 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
166 ctx->errcode = EXT2_ET_DIR_CORRUPTED;
167 return BLOCK_ABORT;
168 }
169 if (!dirent->inode &&
170 !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
171 goto next;
172
173 ret = (ctx->func)(ctx->dir,
174 (next_real_entry > offset) ?
175 DIRENT_DELETED_FILE : entry,
176 dirent, offset,
177 fs->blocksize, ctx->buf,
178 ctx->priv_data);
179 if (entry < DIRENT_OTHER_FILE)
180 entry++;
181
182 if (ret & DIRENT_CHANGED)
183 changed++;
184 if (ret & DIRENT_ABORT) {
185 do_abort++;
186 break;
187 }
188next:
189 if (next_real_entry == offset)
190 next_real_entry += dirent->rec_len;
191
192 if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
193 size = ((dirent->name_len & 0xFF) + 11) & ~3;
194
195 if (dirent->rec_len != size) {
196 unsigned int final_offset;
197
198 final_offset = offset + dirent->rec_len;
199 offset += size;
200 while (offset < final_offset &&
201 !ext2fs_validate_entry(ctx->buf,
202 offset,
203 final_offset))
204 offset += 4;
205 continue;
206 }
207 }
208 offset += dirent->rec_len;
209 }
210
211 if (changed) {
212 ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf);
213 if (ctx->errcode)
214 return BLOCK_ABORT;
215 }
216 if (do_abort)
217 return BLOCK_ABORT;
218 return 0;
219}
220
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c b/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c
new file mode 100644
index 000000000..5d3f6a1bc
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c
@@ -0,0 +1,133 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * dirblock.c --- directory block routines.
4 *
5 * Copyright (C) 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <string.h>
18#include <time.h>
19
20#include "ext2_fs.h"
21#include "ext2fs.h"
22
23errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
24 void *buf, int flags EXT2FS_ATTR((unused)))
25{
26 errcode_t retval;
27 char *p, *end;
28 struct ext2_dir_entry *dirent;
29 unsigned int name_len, rec_len;
30#if BB_BIG_ENDIAN
31 unsigned int do_swap;
32#endif
33
34 retval = io_channel_read_blk(fs->io, block, 1, buf);
35 if (retval)
36 return retval;
37#if BB_BIG_ENDIAN
38 do_swap = (fs->flags & (EXT2_FLAG_SWAP_BYTES|
39 EXT2_FLAG_SWAP_BYTES_READ)) != 0;
40#endif
41 p = (char *) buf;
42 end = (char *) buf + fs->blocksize;
43 while (p < end-8) {
44 dirent = (struct ext2_dir_entry *) p;
45#if BB_BIG_ENDIAN
46 if (do_swap) {
47 dirent->inode = ext2fs_swab32(dirent->inode);
48 dirent->rec_len = ext2fs_swab16(dirent->rec_len);
49 dirent->name_len = ext2fs_swab16(dirent->name_len);
50 }
51#endif
52 name_len = dirent->name_len;
53#ifdef WORDS_BIGENDIAN
54 if (flags & EXT2_DIRBLOCK_V2_STRUCT)
55 dirent->name_len = ext2fs_swab16(dirent->name_len);
56#endif
57 rec_len = dirent->rec_len;
58 if ((rec_len < 8) || (rec_len % 4)) {
59 rec_len = 8;
60 retval = EXT2_ET_DIR_CORRUPTED;
61 }
62 if (((name_len & 0xFF) + 8) > dirent->rec_len)
63 retval = EXT2_ET_DIR_CORRUPTED;
64 p += rec_len;
65 }
66 return retval;
67}
68
69errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
70 void *buf)
71{
72 return ext2fs_read_dir_block2(fs, block, buf, 0);
73}
74
75
76errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
77 void *inbuf, int flags EXT2FS_ATTR((unused)))
78{
79#if BB_BIG_ENDIAN
80 int do_swap = 0;
81 errcode_t retval;
82 char *p, *end;
83 char *buf = 0;
84 struct ext2_dir_entry *dirent;
85
86 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
87 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
88 do_swap = 1;
89
90#ifndef WORDS_BIGENDIAN
91 if (!do_swap)
92 return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
93#endif
94
95 retval = ext2fs_get_mem(fs->blocksize, &buf);
96 if (retval)
97 return retval;
98 memcpy(buf, inbuf, fs->blocksize);
99 p = buf;
100 end = buf + fs->blocksize;
101 while (p < end) {
102 dirent = (struct ext2_dir_entry *) p;
103 if ((dirent->rec_len < 8) ||
104 (dirent->rec_len % 4)) {
105 ext2fs_free_mem(&buf);
106 return EXT2_ET_DIR_CORRUPTED;
107 }
108 p += dirent->rec_len;
109 if (do_swap) {
110 dirent->inode = ext2fs_swab32(dirent->inode);
111 dirent->rec_len = ext2fs_swab16(dirent->rec_len);
112 dirent->name_len = ext2fs_swab16(dirent->name_len);
113 }
114#ifdef WORDS_BIGENDIAN
115 if (flags & EXT2_DIRBLOCK_V2_STRUCT)
116 dirent->name_len = ext2fs_swab16(dirent->name_len);
117#endif
118 }
119 retval = io_channel_write_blk(fs->io, block, 1, buf);
120 ext2fs_free_mem(&buf);
121 return retval;
122#else
123 return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
124#endif
125}
126
127
128errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
129 void *inbuf)
130{
131 return ext2fs_write_dir_block2(fs, block, inbuf, 0);
132}
133
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c b/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c
new file mode 100644
index 000000000..ab3243fd7
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/dirhash.c
@@ -0,0 +1,234 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * dirhash.c -- Calculate the hash of a directory entry
4 *
5 * Copyright (c) 2001 Daniel Phillips
6 *
7 * Copyright (c) 2002 Theodore Ts'o.
8 *
9 * %Begin-Header%
10 * This file may be redistributed under the terms of the GNU Public
11 * License.
12 * %End-Header%
13 */
14
15#include <stdio.h>
16#include <string.h>
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21/*
22 * Keyed 32-bit hash function using TEA in a Davis-Meyer function
23 * H0 = Key
24 * Hi = E Mi(Hi-1) + Hi-1
25 *
26 * (see Applied Cryptography, 2nd edition, p448).
27 *
28 * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
29 *
30 * This code is made available under the terms of the GPL
31 */
32#define DELTA 0x9E3779B9
33
34static void TEA_transform(__u32 buf[4], __u32 const in[])
35{
36 __u32 sum = 0;
37 __u32 b0 = buf[0], b1 = buf[1];
38 __u32 a = in[0], b = in[1], c = in[2], d = in[3];
39 int n = 16;
40
41 do {
42 sum += DELTA;
43 b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
44 b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
45 } while(--n);
46
47 buf[0] += b0;
48 buf[1] += b1;
49}
50
51/* F, G and H are basic MD4 functions: selection, majority, parity */
52#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
53#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
54#define H(x, y, z) ((x) ^ (y) ^ (z))
55
56/*
57 * The generic round function. The application is so specific that
58 * we don't bother protecting all the arguments with parens, as is generally
59 * good macro practice, in favor of extra legibility.
60 * Rotation is separate from addition to prevent recomputation
61 */
62#define ROUND(f, a, b, c, d, x, s) \
63 (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
64#define K1 0
65#define K2 013240474631UL
66#define K3 015666365641UL
67
68/*
69 * Basic cut-down MD4 transform. Returns only 32 bits of result.
70 */
71static void halfMD4Transform (__u32 buf[4], __u32 const in[])
72{
73 __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
74
75 /* Round 1 */
76 ROUND(F, a, b, c, d, in[0] + K1, 3);
77 ROUND(F, d, a, b, c, in[1] + K1, 7);
78 ROUND(F, c, d, a, b, in[2] + K1, 11);
79 ROUND(F, b, c, d, a, in[3] + K1, 19);
80 ROUND(F, a, b, c, d, in[4] + K1, 3);
81 ROUND(F, d, a, b, c, in[5] + K1, 7);
82 ROUND(F, c, d, a, b, in[6] + K1, 11);
83 ROUND(F, b, c, d, a, in[7] + K1, 19);
84
85 /* Round 2 */
86 ROUND(G, a, b, c, d, in[1] + K2, 3);
87 ROUND(G, d, a, b, c, in[3] + K2, 5);
88 ROUND(G, c, d, a, b, in[5] + K2, 9);
89 ROUND(G, b, c, d, a, in[7] + K2, 13);
90 ROUND(G, a, b, c, d, in[0] + K2, 3);
91 ROUND(G, d, a, b, c, in[2] + K2, 5);
92 ROUND(G, c, d, a, b, in[4] + K2, 9);
93 ROUND(G, b, c, d, a, in[6] + K2, 13);
94
95 /* Round 3 */
96 ROUND(H, a, b, c, d, in[3] + K3, 3);
97 ROUND(H, d, a, b, c, in[7] + K3, 9);
98 ROUND(H, c, d, a, b, in[2] + K3, 11);
99 ROUND(H, b, c, d, a, in[6] + K3, 15);
100 ROUND(H, a, b, c, d, in[1] + K3, 3);
101 ROUND(H, d, a, b, c, in[5] + K3, 9);
102 ROUND(H, c, d, a, b, in[0] + K3, 11);
103 ROUND(H, b, c, d, a, in[4] + K3, 15);
104
105 buf[0] += a;
106 buf[1] += b;
107 buf[2] += c;
108 buf[3] += d;
109}
110
111#undef ROUND
112#undef F
113#undef G
114#undef H
115#undef K1
116#undef K2
117#undef K3
118
119/* The old legacy hash */
120static ext2_dirhash_t dx_hack_hash (const char *name, int len)
121{
122 __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
123 while (len--) {
124 __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
125
126 if (hash & 0x80000000) hash -= 0x7fffffff;
127 hash1 = hash0;
128 hash0 = hash;
129 }
130 return (hash0 << 1);
131}
132
133static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
134{
135 __u32 pad, val;
136 int i;
137
138 pad = (__u32)len | ((__u32)len << 8);
139 pad |= pad << 16;
140
141 val = pad;
142 if (len > num*4)
143 len = num * 4;
144 for (i=0; i < len; i++) {
145 if ((i % 4) == 0)
146 val = pad;
147 val = msg[i] + (val << 8);
148 if ((i % 4) == 3) {
149 *buf++ = val;
150 val = pad;
151 num--;
152 }
153 }
154 if (--num >= 0)
155 *buf++ = val;
156 while (--num >= 0)
157 *buf++ = pad;
158}
159
160/*
161 * Returns the hash of a filename. If len is 0 and name is NULL, then
162 * this function can be used to test whether or not a hash version is
163 * supported.
164 *
165 * The seed is an 4 longword (32 bits) "secret" which can be used to
166 * uniquify a hash. If the seed is all zero's, then some default seed
167 * may be used.
168 *
169 * A particular hash version specifies whether or not the seed is
170 * represented, and whether or not the returned hash is 32 bits or 64
171 * bits. 32 bit hashes will return 0 for the minor hash.
172 */
173errcode_t ext2fs_dirhash(int version, const char *name, int len,
174 const __u32 *seed,
175 ext2_dirhash_t *ret_hash,
176 ext2_dirhash_t *ret_minor_hash)
177{
178 __u32 hash;
179 __u32 minor_hash = 0;
180 const char *p;
181 int i;
182 __u32 in[8], buf[4];
183
184 /* Initialize the default seed for the hash checksum functions */
185 buf[0] = 0x67452301;
186 buf[1] = 0xefcdab89;
187 buf[2] = 0x98badcfe;
188 buf[3] = 0x10325476;
189
190 /* Check to see if the seed is all zero's */
191 if (seed) {
192 for (i=0; i < 4; i++) {
193 if (seed[i])
194 break;
195 }
196 if (i < 4)
197 memcpy(buf, seed, sizeof(buf));
198 }
199
200 switch (version) {
201 case EXT2_HASH_LEGACY:
202 hash = dx_hack_hash(name, len);
203 break;
204 case EXT2_HASH_HALF_MD4:
205 p = name;
206 while (len > 0) {
207 str2hashbuf(p, len, in, 8);
208 halfMD4Transform(buf, in);
209 len -= 32;
210 p += 32;
211 }
212 minor_hash = buf[2];
213 hash = buf[1];
214 break;
215 case EXT2_HASH_TEA:
216 p = name;
217 while (len > 0) {
218 str2hashbuf(p, len, in, 4);
219 TEA_transform(buf, in);
220 len -= 16;
221 p += 16;
222 }
223 hash = buf[0];
224 minor_hash = buf[1];
225 break;
226 default:
227 *ret_hash = 0;
228 return EXT2_ET_DIRHASH_UNSUPP;
229 }
230 *ret_hash = hash & ~1;
231 if (ret_minor_hash)
232 *ret_minor_hash = minor_hash;
233 return 0;
234}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c b/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c
new file mode 100644
index 000000000..203c29fe3
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c
@@ -0,0 +1,97 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * dupfs.c --- duplicate a ext2 filesystem handle
4 *
5 * Copyright (C) 1997, 1998, 2001, 2003, 2005 by Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <time.h>
18#include <string.h>
19
20#include "ext2_fs.h"
21#include "ext2fsP.h"
22
23errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest)
24{
25 ext2_filsys fs;
26 errcode_t retval;
27
28 EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS);
29
30 retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
31 if (retval)
32 return retval;
33
34 *fs = *src;
35 fs->device_name = 0;
36 fs->super = 0;
37 fs->orig_super = 0;
38 fs->group_desc = 0;
39 fs->inode_map = 0;
40 fs->block_map = 0;
41 fs->badblocks = 0;
42 fs->dblist = 0;
43
44 io_channel_bumpcount(fs->io);
45 if (fs->icache)
46 fs->icache->refcount++;
47
48 retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name);
49 if (retval)
50 goto errout;
51 strcpy(fs->device_name, src->device_name);
52
53 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
54 if (retval)
55 goto errout;
56 memcpy(fs->super, src->super, SUPERBLOCK_SIZE);
57
58 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
59 if (retval)
60 goto errout;
61 memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE);
62
63 retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
64 &fs->group_desc);
65 if (retval)
66 goto errout;
67 memcpy(fs->group_desc, src->group_desc,
68 (size_t) fs->desc_blocks * fs->blocksize);
69
70 if (src->inode_map) {
71 retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map);
72 if (retval)
73 goto errout;
74 }
75 if (src->block_map) {
76 retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map);
77 if (retval)
78 goto errout;
79 }
80 if (src->badblocks) {
81 retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks);
82 if (retval)
83 goto errout;
84 }
85 if (src->dblist) {
86 retval = ext2fs_copy_dblist(src->dblist, &fs->dblist);
87 if (retval)
88 goto errout;
89 }
90 *dest = fs;
91 return 0;
92errout:
93 ext2fs_free(fs);
94 return retval;
95
96}
97
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h b/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h
new file mode 100644
index 000000000..8d38ecc13
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h
@@ -0,0 +1,52 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * e2image.h --- header file describing the ext2 image format
4 *
5 * Copyright (C) 2000 Theodore Ts'o.
6 *
7 * Note: this uses the POSIX IO interfaces, unlike most of the other
8 * functions in this library. So sue me.
9 *
10 * %Begin-Header%
11 * This file may be redistributed under the terms of the GNU Public
12 * License.
13 * %End-Header%
14 */
15
16
17struct ext2_image_hdr {
18 __u32 magic_number; /* This must be EXT2_ET_MAGIC_E2IMAGE */
19 char magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */
20 char fs_hostname[64];/* Hostname of machine of image */
21 char fs_netaddr[32]; /* Network address */
22 __u32 fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */
23 __u32 fs_device; /* Device number of image */
24 char fs_device_name[64]; /* Device name */
25 char fs_uuid[16]; /* UUID of filesystem */
26 __u32 fs_blocksize; /* Block size of the filesystem */
27 __u32 fs_reserved[8];
28
29 __u32 image_device; /* Device number of image file */
30 __u32 image_inode; /* Inode number of image file */
31 __u32 image_time; /* Time of image creation */
32 __u32 image_reserved[8];
33
34 __u32 offset_super; /* Byte offset of the sb and descriptors */
35 __u32 offset_inode; /* Byte offset of the inode table */
36 __u32 offset_inodemap; /* Byte offset of the inode bitmaps */
37 __u32 offset_blockmap; /* Byte offset of the inode bitmaps */
38 __u32 offset_reserved[8];
39};
40
41
42
43
44
45
46
47
48
49
50
51
52
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/expanddir.c b/e2fsprogs/old_e2fsprogs/ext2fs/expanddir.c
new file mode 100644
index 000000000..8a29ae584
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/expanddir.c
@@ -0,0 +1,127 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * expand.c --- expand an ext2fs directory
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22struct expand_dir_struct {
23 int done;
24 int newblocks;
25 errcode_t err;
26};
27
28static int expand_dir_proc(ext2_filsys fs,
29 blk_t *blocknr,
30 e2_blkcnt_t blockcnt,
31 blk_t ref_block EXT2FS_ATTR((unused)),
32 int ref_offset EXT2FS_ATTR((unused)),
33 void *priv_data)
34{
35 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
36 blk_t new_blk;
37 static blk_t last_blk = 0;
38 char *block;
39 errcode_t retval;
40
41 if (*blocknr) {
42 last_blk = *blocknr;
43 return 0;
44 }
45 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
46 if (retval) {
47 es->err = retval;
48 return BLOCK_ABORT;
49 }
50 if (blockcnt > 0) {
51 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
52 if (retval) {
53 es->err = retval;
54 return BLOCK_ABORT;
55 }
56 es->done = 1;
57 retval = ext2fs_write_dir_block(fs, new_blk, block);
58 } else {
59 retval = ext2fs_get_mem(fs->blocksize, &block);
60 if (retval) {
61 es->err = retval;
62 return BLOCK_ABORT;
63 }
64 memset(block, 0, fs->blocksize);
65 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
66 }
67 if (retval) {
68 es->err = retval;
69 return BLOCK_ABORT;
70 }
71 ext2fs_free_mem(&block);
72 *blocknr = new_blk;
73 ext2fs_block_alloc_stats(fs, new_blk, +1);
74 es->newblocks++;
75
76 if (es->done)
77 return (BLOCK_CHANGED | BLOCK_ABORT);
78 else
79 return BLOCK_CHANGED;
80}
81
82errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
83{
84 errcode_t retval;
85 struct expand_dir_struct es;
86 struct ext2_inode inode;
87
88 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
89
90 if (!(fs->flags & EXT2_FLAG_RW))
91 return EXT2_ET_RO_FILSYS;
92
93 if (!fs->block_map)
94 return EXT2_ET_NO_BLOCK_BITMAP;
95
96 retval = ext2fs_check_directory(fs, dir);
97 if (retval)
98 return retval;
99
100 es.done = 0;
101 es.err = 0;
102 es.newblocks = 0;
103
104 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
105 0, expand_dir_proc, &es);
106
107 if (es.err)
108 return es.err;
109 if (!es.done)
110 return EXT2_ET_EXPAND_DIR_ERR;
111
112 /*
113 * Update the size and block count fields in the inode.
114 */
115 retval = ext2fs_read_inode(fs, dir, &inode);
116 if (retval)
117 return retval;
118
119 inode.i_size += fs->blocksize;
120 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
121
122 retval = ext2fs_write_inode(fs, dir, &inode);
123 if (retval)
124 return retval;
125
126 return 0;
127}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2_err.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_err.h
new file mode 100644
index 000000000..ead352810
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_err.h
@@ -0,0 +1,116 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ext2_err.h:
4 * This file is automatically generated; please do not edit it.
5 */
6
7#define EXT2_ET_BASE (2133571328L)
8#define EXT2_ET_MAGIC_EXT2FS_FILSYS (2133571329L)
9#define EXT2_ET_MAGIC_BADBLOCKS_LIST (2133571330L)
10#define EXT2_ET_MAGIC_BADBLOCKS_ITERATE (2133571331L)
11#define EXT2_ET_MAGIC_INODE_SCAN (2133571332L)
12#define EXT2_ET_MAGIC_IO_CHANNEL (2133571333L)
13#define EXT2_ET_MAGIC_UNIX_IO_CHANNEL (2133571334L)
14#define EXT2_ET_MAGIC_IO_MANAGER (2133571335L)
15#define EXT2_ET_MAGIC_BLOCK_BITMAP (2133571336L)
16#define EXT2_ET_MAGIC_INODE_BITMAP (2133571337L)
17#define EXT2_ET_MAGIC_GENERIC_BITMAP (2133571338L)
18#define EXT2_ET_MAGIC_TEST_IO_CHANNEL (2133571339L)
19#define EXT2_ET_MAGIC_DBLIST (2133571340L)
20#define EXT2_ET_MAGIC_ICOUNT (2133571341L)
21#define EXT2_ET_MAGIC_PQ_IO_CHANNEL (2133571342L)
22#define EXT2_ET_MAGIC_EXT2_FILE (2133571343L)
23#define EXT2_ET_MAGIC_E2IMAGE (2133571344L)
24#define EXT2_ET_MAGIC_INODE_IO_CHANNEL (2133571345L)
25#define EXT2_ET_MAGIC_RESERVED_9 (2133571346L)
26#define EXT2_ET_BAD_MAGIC (2133571347L)
27#define EXT2_ET_REV_TOO_HIGH (2133571348L)
28#define EXT2_ET_RO_FILSYS (2133571349L)
29#define EXT2_ET_GDESC_READ (2133571350L)
30#define EXT2_ET_GDESC_WRITE (2133571351L)
31#define EXT2_ET_GDESC_BAD_BLOCK_MAP (2133571352L)
32#define EXT2_ET_GDESC_BAD_INODE_MAP (2133571353L)
33#define EXT2_ET_GDESC_BAD_INODE_TABLE (2133571354L)
34#define EXT2_ET_INODE_BITMAP_WRITE (2133571355L)
35#define EXT2_ET_INODE_BITMAP_READ (2133571356L)
36#define EXT2_ET_BLOCK_BITMAP_WRITE (2133571357L)
37#define EXT2_ET_BLOCK_BITMAP_READ (2133571358L)
38#define EXT2_ET_INODE_TABLE_WRITE (2133571359L)
39#define EXT2_ET_INODE_TABLE_READ (2133571360L)
40#define EXT2_ET_NEXT_INODE_READ (2133571361L)
41#define EXT2_ET_UNEXPECTED_BLOCK_SIZE (2133571362L)
42#define EXT2_ET_DIR_CORRUPTED (2133571363L)
43#define EXT2_ET_SHORT_READ (2133571364L)
44#define EXT2_ET_SHORT_WRITE (2133571365L)
45#define EXT2_ET_DIR_NO_SPACE (2133571366L)
46#define EXT2_ET_NO_INODE_BITMAP (2133571367L)
47#define EXT2_ET_NO_BLOCK_BITMAP (2133571368L)
48#define EXT2_ET_BAD_INODE_NUM (2133571369L)
49#define EXT2_ET_BAD_BLOCK_NUM (2133571370L)
50#define EXT2_ET_EXPAND_DIR_ERR (2133571371L)
51#define EXT2_ET_TOOSMALL (2133571372L)
52#define EXT2_ET_BAD_BLOCK_MARK (2133571373L)
53#define EXT2_ET_BAD_BLOCK_UNMARK (2133571374L)
54#define EXT2_ET_BAD_BLOCK_TEST (2133571375L)
55#define EXT2_ET_BAD_INODE_MARK (2133571376L)
56#define EXT2_ET_BAD_INODE_UNMARK (2133571377L)
57#define EXT2_ET_BAD_INODE_TEST (2133571378L)
58#define EXT2_ET_FUDGE_BLOCK_BITMAP_END (2133571379L)
59#define EXT2_ET_FUDGE_INODE_BITMAP_END (2133571380L)
60#define EXT2_ET_BAD_IND_BLOCK (2133571381L)
61#define EXT2_ET_BAD_DIND_BLOCK (2133571382L)
62#define EXT2_ET_BAD_TIND_BLOCK (2133571383L)
63#define EXT2_ET_NEQ_BLOCK_BITMAP (2133571384L)
64#define EXT2_ET_NEQ_INODE_BITMAP (2133571385L)
65#define EXT2_ET_BAD_DEVICE_NAME (2133571386L)
66#define EXT2_ET_MISSING_INODE_TABLE (2133571387L)
67#define EXT2_ET_CORRUPT_SUPERBLOCK (2133571388L)
68#define EXT2_ET_BAD_GENERIC_MARK (2133571389L)
69#define EXT2_ET_BAD_GENERIC_UNMARK (2133571390L)
70#define EXT2_ET_BAD_GENERIC_TEST (2133571391L)
71#define EXT2_ET_SYMLINK_LOOP (2133571392L)
72#define EXT2_ET_CALLBACK_NOTHANDLED (2133571393L)
73#define EXT2_ET_BAD_BLOCK_IN_INODE_TABLE (2133571394L)
74#define EXT2_ET_UNSUPP_FEATURE (2133571395L)
75#define EXT2_ET_RO_UNSUPP_FEATURE (2133571396L)
76#define EXT2_ET_LLSEEK_FAILED (2133571397L)
77#define EXT2_ET_NO_MEMORY (2133571398L)
78#define EXT2_ET_INVALID_ARGUMENT (2133571399L)
79#define EXT2_ET_BLOCK_ALLOC_FAIL (2133571400L)
80#define EXT2_ET_INODE_ALLOC_FAIL (2133571401L)
81#define EXT2_ET_NO_DIRECTORY (2133571402L)
82#define EXT2_ET_TOO_MANY_REFS (2133571403L)
83#define EXT2_ET_FILE_NOT_FOUND (2133571404L)
84#define EXT2_ET_FILE_RO (2133571405L)
85#define EXT2_ET_DB_NOT_FOUND (2133571406L)
86#define EXT2_ET_DIR_EXISTS (2133571407L)
87#define EXT2_ET_UNIMPLEMENTED (2133571408L)
88#define EXT2_ET_CANCEL_REQUESTED (2133571409L)
89#define EXT2_ET_FILE_TOO_BIG (2133571410L)
90#define EXT2_ET_JOURNAL_NOT_BLOCK (2133571411L)
91#define EXT2_ET_NO_JOURNAL_SB (2133571412L)
92#define EXT2_ET_JOURNAL_TOO_SMALL (2133571413L)
93#define EXT2_ET_JOURNAL_UNSUPP_VERSION (2133571414L)
94#define EXT2_ET_LOAD_EXT_JOURNAL (2133571415L)
95#define EXT2_ET_NO_JOURNAL (2133571416L)
96#define EXT2_ET_DIRHASH_UNSUPP (2133571417L)
97#define EXT2_ET_BAD_EA_BLOCK_NUM (2133571418L)
98#define EXT2_ET_TOO_MANY_INODES (2133571419L)
99#define EXT2_ET_NOT_IMAGE_FILE (2133571420L)
100#define EXT2_ET_RES_GDT_BLOCKS (2133571421L)
101#define EXT2_ET_RESIZE_INODE_CORRUPT (2133571422L)
102#define EXT2_ET_SET_BMAP_NO_IND (2133571423L)
103
104#if 0
105extern const struct error_table et_ext2_error_table;
106extern void initialize_ext2_error_table(void);
107
108/* For compatibility with Heimdal */
109extern void initialize_ext2_error_table_r(struct et_list **list);
110
111#define ERROR_TABLE_BASE_ext2 (2133571328L)
112
113/* for compatibility with older versions... */
114#define init_ext2_err_tbl initialize_ext2_error_table
115#define ext2_err_base ERROR_TABLE_BASE_ext2
116#endif
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h
new file mode 100644
index 000000000..cc91bb8d6
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h
@@ -0,0 +1,53 @@
1/* vi: set sw=4 ts=4: */
2/*
3 File: linux/ext2_ext_attr.h
4
5 On-disk format of extended attributes for the ext2 filesystem.
6
7 (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org>
8*/
9
10/* Magic value in attribute blocks */
11#define EXT2_EXT_ATTR_MAGIC_v1 0xEA010000
12#define EXT2_EXT_ATTR_MAGIC 0xEA020000
13
14/* Maximum number of references to one attribute block */
15#define EXT2_EXT_ATTR_REFCOUNT_MAX 1024
16
17struct ext2_ext_attr_header {
18 __u32 h_magic; /* magic number for identification */
19 __u32 h_refcount; /* reference count */
20 __u32 h_blocks; /* number of disk blocks used */
21 __u32 h_hash; /* hash value of all attributes */
22 __u32 h_reserved[4]; /* zero right now */
23};
24
25struct ext2_ext_attr_entry {
26 __u8 e_name_len; /* length of name */
27 __u8 e_name_index; /* attribute name index */
28 __u16 e_value_offs; /* offset in disk block of value */
29 __u32 e_value_block; /* disk block attribute is stored on (n/i) */
30 __u32 e_value_size; /* size of attribute value */
31 __u32 e_hash; /* hash value of name and value */
32};
33
34#define EXT2_EXT_ATTR_PAD_BITS 2
35#define EXT2_EXT_ATTR_PAD (1<<EXT2_EXT_ATTR_PAD_BITS)
36#define EXT2_EXT_ATTR_ROUND (EXT2_EXT_ATTR_PAD-1)
37#define EXT2_EXT_ATTR_LEN(name_len) \
38 (((name_len) + EXT2_EXT_ATTR_ROUND + \
39 sizeof(struct ext2_ext_attr_entry)) & ~EXT2_EXT_ATTR_ROUND)
40#define EXT2_EXT_ATTR_NEXT(entry) \
41 ( (struct ext2_ext_attr_entry *)( \
42 (char *)(entry) + EXT2_EXT_ATTR_LEN((entry)->e_name_len)) )
43#define EXT2_EXT_ATTR_SIZE(size) \
44 (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
45#define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL)
46#define EXT2_EXT_ATTR_NAME(entry) \
47 (((char *) (entry)) + sizeof(struct ext2_ext_attr_entry))
48#define EXT2_XATTR_LEN(name_len) \
49 (((name_len) + EXT2_EXT_ATTR_ROUND + \
50 sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND)
51#define EXT2_XATTR_SIZE(size) \
52 (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
53
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h
new file mode 100644
index 000000000..cb49d7a60
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h
@@ -0,0 +1,570 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * linux/include/linux/ext2_fs.h
4 *
5 * Copyright (C) 1992, 1993, 1994, 1995
6 * Remy Card (card@masi.ibp.fr)
7 * Laboratoire MASI - Institut Blaise Pascal
8 * Universite Pierre et Marie Curie (Paris VI)
9 *
10 * from
11 *
12 * linux/include/linux/minix_fs.h
13 *
14 * Copyright (C) 1991, 1992 Linus Torvalds
15 */
16
17#ifndef _LINUX_EXT2_FS_H
18#define _LINUX_EXT2_FS_H
19
20#include "ext2_types.h" /* Changed from linux/types.h */
21
22/*
23 * Special inode numbers
24 */
25#define EXT2_BAD_INO 1 /* Bad blocks inode */
26#define EXT2_ROOT_INO 2 /* Root inode */
27#define EXT2_ACL_IDX_INO 3 /* ACL inode */
28#define EXT2_ACL_DATA_INO 4 /* ACL inode */
29#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
30#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
31#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */
32#define EXT2_JOURNAL_INO 8 /* Journal inode */
33
34/* First non-reserved inode for old ext2 filesystems */
35#define EXT2_GOOD_OLD_FIRST_INO 11
36
37/*
38 * The second extended file system magic number
39 */
40#define EXT2_SUPER_MAGIC 0xEF53
41
42/* Assume that user mode programs are passing in an ext2fs superblock, not
43 * a kernel struct super_block. This will allow us to call the feature-test
44 * macros from user land. */
45#define EXT2_SB(sb) (sb)
46
47/*
48 * Maximal count of links to a file
49 */
50#define EXT2_LINK_MAX 32000
51
52/*
53 * Macro-instructions used to manage several block sizes
54 */
55#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
56#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */
57#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE)
58#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE)
59#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
60#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
61#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
62 EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
63#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
64 EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
65#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(__u32))
66
67/*
68 * Macro-instructions used to manage fragments
69 */
70#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE
71#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE
72#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE
73# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
74# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
75
76/*
77 * ACL structures
78 */
79struct ext2_acl_header /* Header of Access Control Lists */
80{
81 __u32 aclh_size;
82 __u32 aclh_file_count;
83 __u32 aclh_acle_count;
84 __u32 aclh_first_acle;
85};
86
87struct ext2_acl_entry /* Access Control List Entry */
88{
89 __u32 acle_size;
90 __u16 acle_perms; /* Access permissions */
91 __u16 acle_type; /* Type of entry */
92 __u16 acle_tag; /* User or group identity */
93 __u16 acle_pad1;
94 __u32 acle_next; /* Pointer on next entry for the */
95 /* same inode or on next free entry */
96};
97
98/*
99 * Structure of a blocks group descriptor
100 */
101struct ext2_group_desc
102{
103 __u32 bg_block_bitmap; /* Blocks bitmap block */
104 __u32 bg_inode_bitmap; /* Inodes bitmap block */
105 __u32 bg_inode_table; /* Inodes table block */
106 __u16 bg_free_blocks_count; /* Free blocks count */
107 __u16 bg_free_inodes_count; /* Free inodes count */
108 __u16 bg_used_dirs_count; /* Directories count */
109 __u16 bg_pad;
110 __u32 bg_reserved[3];
111};
112
113/*
114 * Data structures used by the directory indexing feature
115 *
116 * Note: all of the multibyte integer fields are little endian.
117 */
118
119/*
120 * Note: dx_root_info is laid out so that if it should somehow get
121 * overlaid by a dirent the two low bits of the hash version will be
122 * zero. Therefore, the hash version mod 4 should never be 0.
123 * Sincerely, the paranoia department.
124 */
125struct ext2_dx_root_info {
126 __u32 reserved_zero;
127 __u8 hash_version; /* 0 now, 1 at release */
128 __u8 info_length; /* 8 */
129 __u8 indirect_levels;
130 __u8 unused_flags;
131};
132
133#define EXT2_HASH_LEGACY 0
134#define EXT2_HASH_HALF_MD4 1
135#define EXT2_HASH_TEA 2
136
137#define EXT2_HASH_FLAG_INCOMPAT 0x1
138
139struct ext2_dx_entry {
140 __u32 hash;
141 __u32 block;
142};
143
144struct ext2_dx_countlimit {
145 __u16 limit;
146 __u16 count;
147};
148
149
150/*
151 * Macro-instructions used to manage group descriptors
152 */
153#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group)
154#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group)
155#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
156/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
157#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((1 << 16) - 8)
158#define EXT2_MAX_INODES_PER_GROUP(s) ((1 << 16) - EXT2_INODES_PER_BLOCK(s))
159#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
160
161/*
162 * Constants relative to the data blocks
163 */
164#define EXT2_NDIR_BLOCKS 12
165#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
166#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
167#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
168#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
169
170/*
171 * Inode flags
172 */
173#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
174#define EXT2_UNRM_FL 0x00000002 /* Undelete */
175#define EXT2_COMPR_FL 0x00000004 /* Compress file */
176#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
177#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
178#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
179#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
180#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
181/* Reserved for compression usage... */
182#define EXT2_DIRTY_FL 0x00000100
183#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
184#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */
185#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
186/* End compression flags --- maybe not all used */
187#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
188#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
189#define EXT2_IMAGIC_FL 0x00002000
190#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
191#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
192#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */
193#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
194#define EXT3_EXTENTS_FL 0x00080000 /* Inode uses extents */
195#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
196
197#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
198#define EXT2_FL_USER_MODIFIABLE 0x000080FF /* User modifiable flags */
199
200/*
201 * ioctl commands
202 */
203#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
204#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
205#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
206#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
207
208/*
209 * Structure of an inode on the disk
210 */
211struct ext2_inode {
212 __u16 i_mode; /* File mode */
213 __u16 i_uid; /* Low 16 bits of Owner Uid */
214 __u32 i_size; /* Size in bytes */
215 __u32 i_atime; /* Access time */
216 __u32 i_ctime; /* Creation time */
217 __u32 i_mtime; /* Modification time */
218 __u32 i_dtime; /* Deletion Time */
219 __u16 i_gid; /* Low 16 bits of Group Id */
220 __u16 i_links_count; /* Links count */
221 __u32 i_blocks; /* Blocks count */
222 __u32 i_flags; /* File flags */
223 union {
224 struct {
225 __u32 l_i_reserved1;
226 } linux1;
227 struct {
228 __u32 h_i_translator;
229 } hurd1;
230 struct {
231 __u32 m_i_reserved1;
232 } masix1;
233 } osd1; /* OS dependent 1 */
234 __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
235 __u32 i_generation; /* File version (for NFS) */
236 __u32 i_file_acl; /* File ACL */
237 __u32 i_dir_acl; /* Directory ACL */
238 __u32 i_faddr; /* Fragment address */
239 union {
240 struct {
241 __u8 l_i_frag; /* Fragment number */
242 __u8 l_i_fsize; /* Fragment size */
243 __u16 i_pad1;
244 __u16 l_i_uid_high; /* these 2 fields */
245 __u16 l_i_gid_high; /* were reserved2[0] */
246 __u32 l_i_reserved2;
247 } linux2;
248 struct {
249 __u8 h_i_frag; /* Fragment number */
250 __u8 h_i_fsize; /* Fragment size */
251 __u16 h_i_mode_high;
252 __u16 h_i_uid_high;
253 __u16 h_i_gid_high;
254 __u32 h_i_author;
255 } hurd2;
256 struct {
257 __u8 m_i_frag; /* Fragment number */
258 __u8 m_i_fsize; /* Fragment size */
259 __u16 m_pad1;
260 __u32 m_i_reserved2[2];
261 } masix2;
262 } osd2; /* OS dependent 2 */
263};
264
265/*
266 * Permanent part of an large inode on the disk
267 */
268struct ext2_inode_large {
269 __u16 i_mode; /* File mode */
270 __u16 i_uid; /* Low 16 bits of Owner Uid */
271 __u32 i_size; /* Size in bytes */
272 __u32 i_atime; /* Access time */
273 __u32 i_ctime; /* Creation time */
274 __u32 i_mtime; /* Modification time */
275 __u32 i_dtime; /* Deletion Time */
276 __u16 i_gid; /* Low 16 bits of Group Id */
277 __u16 i_links_count; /* Links count */
278 __u32 i_blocks; /* Blocks count */
279 __u32 i_flags; /* File flags */
280 union {
281 struct {
282 __u32 l_i_reserved1;
283 } linux1;
284 struct {
285 __u32 h_i_translator;
286 } hurd1;
287 struct {
288 __u32 m_i_reserved1;
289 } masix1;
290 } osd1; /* OS dependent 1 */
291 __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
292 __u32 i_generation; /* File version (for NFS) */
293 __u32 i_file_acl; /* File ACL */
294 __u32 i_dir_acl; /* Directory ACL */
295 __u32 i_faddr; /* Fragment address */
296 union {
297 struct {
298 __u8 l_i_frag; /* Fragment number */
299 __u8 l_i_fsize; /* Fragment size */
300 __u16 i_pad1;
301 __u16 l_i_uid_high; /* these 2 fields */
302 __u16 l_i_gid_high; /* were reserved2[0] */
303 __u32 l_i_reserved2;
304 } linux2;
305 struct {
306 __u8 h_i_frag; /* Fragment number */
307 __u8 h_i_fsize; /* Fragment size */
308 __u16 h_i_mode_high;
309 __u16 h_i_uid_high;
310 __u16 h_i_gid_high;
311 __u32 h_i_author;
312 } hurd2;
313 struct {
314 __u8 m_i_frag; /* Fragment number */
315 __u8 m_i_fsize; /* Fragment size */
316 __u16 m_pad1;
317 __u32 m_i_reserved2[2];
318 } masix2;
319 } osd2; /* OS dependent 2 */
320 __u16 i_extra_isize;
321 __u16 i_pad1;
322};
323
324#define i_size_high i_dir_acl
325
326/*
327 * File system states
328 */
329#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
330#define EXT2_ERROR_FS 0x0002 /* Errors detected */
331
332/*
333 * Mount flags
334 */
335#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
336#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
337#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
338#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
339#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
340#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
341#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
342#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
343
344#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
345#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
346#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
347 EXT2_MOUNT_##opt)
348/*
349 * Maximal mount counts between two filesystem checks
350 */
351#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
352#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
353
354/*
355 * Behaviour when detecting errors
356 */
357#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
358#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
359#define EXT2_ERRORS_PANIC 3 /* Panic */
360#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
361
362/*
363 * Structure of the super block
364 */
365struct ext2_super_block {
366 __u32 s_inodes_count; /* Inodes count */
367 __u32 s_blocks_count; /* Blocks count */
368 __u32 s_r_blocks_count; /* Reserved blocks count */
369 __u32 s_free_blocks_count; /* Free blocks count */
370 __u32 s_free_inodes_count; /* Free inodes count */
371 __u32 s_first_data_block; /* First Data Block */
372 __u32 s_log_block_size; /* Block size */
373 __s32 s_log_frag_size; /* Fragment size */
374 __u32 s_blocks_per_group; /* # Blocks per group */
375 __u32 s_frags_per_group; /* # Fragments per group */
376 __u32 s_inodes_per_group; /* # Inodes per group */
377 __u32 s_mtime; /* Mount time */
378 __u32 s_wtime; /* Write time */
379 __u16 s_mnt_count; /* Mount count */
380 __s16 s_max_mnt_count; /* Maximal mount count */
381 __u16 s_magic; /* Magic signature */
382 __u16 s_state; /* File system state */
383 __u16 s_errors; /* Behaviour when detecting errors */
384 __u16 s_minor_rev_level; /* minor revision level */
385 __u32 s_lastcheck; /* time of last check */
386 __u32 s_checkinterval; /* max. time between checks */
387 __u32 s_creator_os; /* OS */
388 __u32 s_rev_level; /* Revision level */
389 __u16 s_def_resuid; /* Default uid for reserved blocks */
390 __u16 s_def_resgid; /* Default gid for reserved blocks */
391 /*
392 * These fields are for EXT2_DYNAMIC_REV superblocks only.
393 *
394 * Note: the difference between the compatible feature set and
395 * the incompatible feature set is that if there is a bit set
396 * in the incompatible feature set that the kernel doesn't
397 * know about, it should refuse to mount the filesystem.
398 *
399 * e2fsck's requirements are more strict; if it doesn't know
400 * about a feature in either the compatible or incompatible
401 * feature set, it must abort and not try to meddle with
402 * things it doesn't understand...
403 */
404 __u32 s_first_ino; /* First non-reserved inode */
405 __u16 s_inode_size; /* size of inode structure */
406 __u16 s_block_group_nr; /* block group # of this superblock */
407 __u32 s_feature_compat; /* compatible feature set */
408 __u32 s_feature_incompat; /* incompatible feature set */
409 __u32 s_feature_ro_compat; /* readonly-compatible feature set */
410 __u8 s_uuid[16]; /* 128-bit uuid for volume */
411 char s_volume_name[16]; /* volume name */
412 char s_last_mounted[64]; /* directory where last mounted */
413 __u32 s_algorithm_usage_bitmap; /* For compression */
414 /*
415 * Performance hints. Directory preallocation should only
416 * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
417 */
418 __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
419 __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
420 __u16 s_reserved_gdt_blocks; /* Per group table for online growth */
421 /*
422 * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
423 */
424 __u8 s_journal_uuid[16]; /* uuid of journal superblock */
425 __u32 s_journal_inum; /* inode number of journal file */
426 __u32 s_journal_dev; /* device number of journal file */
427 __u32 s_last_orphan; /* start of list of inodes to delete */
428 __u32 s_hash_seed[4]; /* HTREE hash seed */
429 __u8 s_def_hash_version; /* Default hash version to use */
430 __u8 s_jnl_backup_type; /* Default type of journal backup */
431 __u16 s_reserved_word_pad;
432 __u32 s_default_mount_opts;
433 __u32 s_first_meta_bg; /* First metablock group */
434 __u32 s_mkfs_time; /* When the filesystem was created */
435 __u32 s_jnl_blocks[17]; /* Backup of the journal inode */
436 __u32 s_reserved[172]; /* Padding to the end of the block */
437};
438
439/*
440 * Codes for operating systems
441 */
442#define EXT2_OS_LINUX 0
443#define EXT2_OS_HURD 1
444#define EXT2_OS_MASIX 2
445#define EXT2_OS_FREEBSD 3
446#define EXT2_OS_LITES 4
447
448/*
449 * Revision levels
450 */
451#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
452#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
453
454#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
455#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
456
457#define EXT2_GOOD_OLD_INODE_SIZE 128
458
459/*
460 * Journal inode backup types
461 */
462#define EXT3_JNL_BACKUP_BLOCKS 1
463
464/*
465 * Feature set definitions
466 */
467
468#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
469 ( EXT2_SB(sb)->s_feature_compat & (mask) )
470#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
471 ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
472#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
473 ( EXT2_SB(sb)->s_feature_incompat & (mask) )
474
475#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
476#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
477#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
478#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
479#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
480#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
481
482#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
483#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
484/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */
485
486#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
487#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
488#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
489#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
490#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
491#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
492
493
494#define EXT2_FEATURE_COMPAT_SUPP 0
495#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE)
496#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
497 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
498 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
499
500/*
501 * Default values for user and/or group using reserved blocks
502 */
503#define EXT2_DEF_RESUID 0
504#define EXT2_DEF_RESGID 0
505
506/*
507 * Default mount options
508 */
509#define EXT2_DEFM_DEBUG 0x0001
510#define EXT2_DEFM_BSDGROUPS 0x0002
511#define EXT2_DEFM_XATTR_USER 0x0004
512#define EXT2_DEFM_ACL 0x0008
513#define EXT2_DEFM_UID16 0x0010
514#define EXT3_DEFM_JMODE 0x0060
515#define EXT3_DEFM_JMODE_DATA 0x0020
516#define EXT3_DEFM_JMODE_ORDERED 0x0040
517#define EXT3_DEFM_JMODE_WBACK 0x0060
518
519/*
520 * Structure of a directory entry
521 */
522#define EXT2_NAME_LEN 255
523
524struct ext2_dir_entry {
525 __u32 inode; /* Inode number */
526 __u16 rec_len; /* Directory entry length */
527 __u16 name_len; /* Name length */
528 char name[EXT2_NAME_LEN]; /* File name */
529};
530
531/*
532 * The new version of the directory entry. Since EXT2 structures are
533 * stored in intel byte order, and the name_len field could never be
534 * bigger than 255 chars, it's safe to reclaim the extra byte for the
535 * file_type field.
536 */
537struct ext2_dir_entry_2 {
538 __u32 inode; /* Inode number */
539 __u16 rec_len; /* Directory entry length */
540 __u8 name_len; /* Name length */
541 __u8 file_type;
542 char name[EXT2_NAME_LEN]; /* File name */
543};
544
545/*
546 * Ext2 directory file types. Only the low 3 bits are used. The
547 * other bits are reserved for now.
548 */
549#define EXT2_FT_UNKNOWN 0
550#define EXT2_FT_REG_FILE 1
551#define EXT2_FT_DIR 2
552#define EXT2_FT_CHRDEV 3
553#define EXT2_FT_BLKDEV 4
554#define EXT2_FT_FIFO 5
555#define EXT2_FT_SOCK 6
556#define EXT2_FT_SYMLINK 7
557
558#define EXT2_FT_MAX 8
559
560/*
561 * EXT2_DIR_PAD defines the directory entries boundaries
562 *
563 * NOTE: It must be a multiple of 4
564 */
565#define EXT2_DIR_PAD 4
566#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
567#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
568 ~EXT2_DIR_ROUND)
569
570#endif /* _LINUX_EXT2_FS_H */
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h
new file mode 100644
index 000000000..e6c9630e2
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_io.h
@@ -0,0 +1,114 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * io.h --- the I/O manager abstraction
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#ifndef _EXT2FS_EXT2_IO_H
14#define _EXT2FS_EXT2_IO_H
15
16/*
17 * ext2_loff_t is defined here since unix_io.c needs it.
18 */
19#if defined(__GNUC__) || defined(HAS_LONG_LONG)
20typedef long long ext2_loff_t;
21#else
22typedef long ext2_loff_t;
23#endif
24
25/* llseek.c */
26/* ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int); */
27#ifdef CONFIG_LFS
28# define ext2fs_llseek lseek64
29#else
30# define ext2fs_llseek lseek
31#endif
32
33typedef struct struct_io_manager *io_manager;
34typedef struct struct_io_channel *io_channel;
35
36#define CHANNEL_FLAGS_WRITETHROUGH 0x01
37
38struct struct_io_channel {
39 errcode_t magic;
40 io_manager manager;
41 char *name;
42 int block_size;
43 errcode_t (*read_error)(io_channel channel,
44 unsigned long block,
45 int count,
46 void *data,
47 size_t size,
48 int actual_bytes_read,
49 errcode_t error);
50 errcode_t (*write_error)(io_channel channel,
51 unsigned long block,
52 int count,
53 const void *data,
54 size_t size,
55 int actual_bytes_written,
56 errcode_t error);
57 int refcount;
58 int flags;
59 int reserved[14];
60 void *private_data;
61 void *app_data;
62};
63
64struct struct_io_manager {
65 errcode_t magic;
66 const char *name;
67 errcode_t (*open)(const char *name, int flags, io_channel *channel);
68 errcode_t (*close)(io_channel channel);
69 errcode_t (*set_blksize)(io_channel channel, int blksize);
70 errcode_t (*read_blk)(io_channel channel, unsigned long block,
71 int count, void *data);
72 errcode_t (*write_blk)(io_channel channel, unsigned long block,
73 int count, const void *data);
74 errcode_t (*flush)(io_channel channel);
75 errcode_t (*write_byte)(io_channel channel, unsigned long offset,
76 int count, const void *data);
77 errcode_t (*set_option)(io_channel channel, const char *option,
78 const char *arg);
79 int reserved[14];
80};
81
82#define IO_FLAG_RW 1
83
84/*
85 * Convenience functions....
86 */
87#define io_channel_close(c) ((c)->manager->close((c)))
88#define io_channel_set_blksize(c,s) ((c)->manager->set_blksize((c),s))
89#define io_channel_read_blk(c,b,n,d) ((c)->manager->read_blk((c),b,n,d))
90#define io_channel_write_blk(c,b,n,d) ((c)->manager->write_blk((c),b,n,d))
91#define io_channel_flush(c) ((c)->manager->flush((c)))
92#define io_channel_bumpcount(c) ((c)->refcount++)
93
94/* io_manager.c */
95extern errcode_t io_channel_set_options(io_channel channel,
96 const char *options);
97extern errcode_t io_channel_write_byte(io_channel channel,
98 unsigned long offset,
99 int count, const void *data);
100
101/* unix_io.c */
102extern io_manager unix_io_manager;
103
104/* test_io.c */
105extern io_manager test_io_manager, test_io_backing_manager;
106extern void (*test_io_cb_read_blk)
107 (unsigned long block, int count, errcode_t err);
108extern void (*test_io_cb_write_blk)
109 (unsigned long block, int count, errcode_t err);
110extern void (*test_io_cb_set_blksize)
111 (int blksize, errcode_t err);
112
113#endif /* _EXT2FS_EXT2_IO_H */
114
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2_types.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_types.h
new file mode 100644
index 000000000..2c1196b8b
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_types.h
@@ -0,0 +1,2 @@
1/* vi: set sw=4 ts=4: */
2#include <linux/types.h>
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h
new file mode 100644
index 000000000..133fb1f1b
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h
@@ -0,0 +1,923 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ext2fs.h --- ext2fs
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#ifndef _EXT2FS_EXT2FS_H
14#define _EXT2FS_EXT2FS_H
15
16
17#define EXT2FS_ATTR(x)
18
19#ifdef __cplusplus
20extern "C" {
21#endif
22
23/*
24 * Where the master copy of the superblock is located, and how big
25 * superblocks are supposed to be. We define SUPERBLOCK_SIZE because
26 * the size of the superblock structure is not necessarily trustworthy
27 * (some versions have the padding set up so that the superblock is
28 * 1032 bytes long).
29 */
30#define SUPERBLOCK_OFFSET 1024
31#define SUPERBLOCK_SIZE 1024
32
33/*
34 * The last ext2fs revision level that this version of the library is
35 * able to support.
36 */
37#define EXT2_LIB_CURRENT_REV EXT2_DYNAMIC_REV
38
39#ifdef HAVE_SYS_TYPES_H
40#include <sys/types.h>
41#endif
42
43#include <stdio.h>
44#include <stdlib.h>
45
46#include "ext2_types.h"
47#include "ext2_fs.h"
48
49typedef __u32 ext2_ino_t;
50typedef __u32 blk_t;
51typedef __u32 dgrp_t;
52typedef __u32 ext2_off_t;
53typedef __s64 e2_blkcnt_t;
54typedef __u32 ext2_dirhash_t;
55
56#include "ext2_io.h"
57#include "ext2_err.h"
58
59typedef struct struct_ext2_filsys *ext2_filsys;
60
61struct ext2fs_struct_generic_bitmap {
62 errcode_t magic;
63 ext2_filsys fs;
64 __u32 start, end;
65 __u32 real_end;
66 char * description;
67 char * bitmap;
68 errcode_t base_error_code;
69 __u32 reserved[7];
70};
71
72#define EXT2FS_MARK_ERROR 0
73#define EXT2FS_UNMARK_ERROR 1
74#define EXT2FS_TEST_ERROR 2
75
76typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap;
77typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap;
78typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap;
79
80#define EXT2_FIRST_INODE(s) EXT2_FIRST_INO(s)
81
82/*
83 * badblocks list definitions
84 */
85
86typedef struct ext2_struct_u32_list *ext2_badblocks_list;
87typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate;
88
89typedef struct ext2_struct_u32_list *ext2_u32_list;
90typedef struct ext2_struct_u32_iterate *ext2_u32_iterate;
91
92/* old */
93typedef struct ext2_struct_u32_list *badblocks_list;
94typedef struct ext2_struct_u32_iterate *badblocks_iterate;
95
96#define BADBLOCKS_FLAG_DIRTY 1
97
98/*
99 * ext2_dblist structure and abstractions (see dblist.c)
100 */
101struct ext2_db_entry {
102 ext2_ino_t ino;
103 blk_t blk;
104 int blockcnt;
105};
106
107typedef struct ext2_struct_dblist *ext2_dblist;
108
109#define DBLIST_ABORT 1
110
111/*
112 * ext2_fileio definitions
113 */
114
115#define EXT2_FILE_WRITE 0x0001
116#define EXT2_FILE_CREATE 0x0002
117
118#define EXT2_FILE_MASK 0x00FF
119
120#define EXT2_FILE_BUF_DIRTY 0x4000
121#define EXT2_FILE_BUF_VALID 0x2000
122
123typedef struct ext2_file *ext2_file_t;
124
125#define EXT2_SEEK_SET 0
126#define EXT2_SEEK_CUR 1
127#define EXT2_SEEK_END 2
128
129/*
130 * Flags for the ext2_filsys structure and for ext2fs_open()
131 */
132#define EXT2_FLAG_RW 0x01
133#define EXT2_FLAG_CHANGED 0x02
134#define EXT2_FLAG_DIRTY 0x04
135#define EXT2_FLAG_VALID 0x08
136#define EXT2_FLAG_IB_DIRTY 0x10
137#define EXT2_FLAG_BB_DIRTY 0x20
138#define EXT2_FLAG_SWAP_BYTES 0x40
139#define EXT2_FLAG_SWAP_BYTES_READ 0x80
140#define EXT2_FLAG_SWAP_BYTES_WRITE 0x100
141#define EXT2_FLAG_MASTER_SB_ONLY 0x200
142#define EXT2_FLAG_FORCE 0x400
143#define EXT2_FLAG_SUPER_ONLY 0x800
144#define EXT2_FLAG_JOURNAL_DEV_OK 0x1000
145#define EXT2_FLAG_IMAGE_FILE 0x2000
146
147/*
148 * Special flag in the ext2 inode i_flag field that means that this is
149 * a new inode. (So that ext2_write_inode() can clear extra fields.)
150 */
151#define EXT2_NEW_INODE_FL 0x80000000
152
153/*
154 * Flags for mkjournal
155 *
156 * EXT2_MKJOURNAL_V1_SUPER Make a (deprecated) V1 journal superblock
157 */
158#define EXT2_MKJOURNAL_V1_SUPER 0x0000001
159
160struct struct_ext2_filsys {
161 errcode_t magic;
162 io_channel io;
163 int flags;
164 char * device_name;
165 struct ext2_super_block * super;
166 unsigned int blocksize;
167 int fragsize;
168 dgrp_t group_desc_count;
169 unsigned long desc_blocks;
170 struct ext2_group_desc * group_desc;
171 int inode_blocks_per_group;
172 ext2fs_inode_bitmap inode_map;
173 ext2fs_block_bitmap block_map;
174 errcode_t (*get_blocks)(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
175 errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino);
176 errcode_t (*write_bitmaps)(ext2_filsys fs);
177 errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino,
178 struct ext2_inode *inode);
179 errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino,
180 struct ext2_inode *inode);
181 ext2_badblocks_list badblocks;
182 ext2_dblist dblist;
183 __u32 stride; /* for mke2fs */
184 struct ext2_super_block * orig_super;
185 struct ext2_image_hdr * image_header;
186 __u32 umask;
187 /*
188 * Reserved for future expansion
189 */
190 __u32 reserved[8];
191
192 /*
193 * Reserved for the use of the calling application.
194 */
195 void * priv_data;
196
197 /*
198 * Inode cache
199 */
200 struct ext2_inode_cache *icache;
201 io_channel image_io;
202};
203
204#include "bitops.h"
205
206/*
207 * Return flags for the block iterator functions
208 */
209#define BLOCK_CHANGED 1
210#define BLOCK_ABORT 2
211#define BLOCK_ERROR 4
212
213/*
214 * Block interate flags
215 *
216 * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the interator
217 * function should be called on blocks where the block number is zero.
218 * This is used by ext2fs_expand_dir() to be able to add a new block
219 * to an inode. It can also be used for programs that want to be able
220 * to deal with files that contain "holes".
221 *
222 * BLOCK_FLAG_TRAVERSE indicates that the iterator function for the
223 * indirect, doubly indirect, etc. blocks should be called after all
224 * of the blocks containined in the indirect blocks are processed.
225 * This is useful if you are going to be deallocating blocks from an
226 * inode.
227 *
228 * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be
229 * called for data blocks only.
230 *
231 * BLOCK_FLAG_NO_LARGE is for internal use only. It informs
232 * ext2fs_block_iterate2 that large files won't be accepted.
233 */
234#define BLOCK_FLAG_APPEND 1
235#define BLOCK_FLAG_HOLE 1
236#define BLOCK_FLAG_DEPTH_TRAVERSE 2
237#define BLOCK_FLAG_DATA_ONLY 4
238
239#define BLOCK_FLAG_NO_LARGE 0x1000
240
241/*
242 * Magic "block count" return values for the block iterator function.
243 */
244#define BLOCK_COUNT_IND (-1)
245#define BLOCK_COUNT_DIND (-2)
246#define BLOCK_COUNT_TIND (-3)
247#define BLOCK_COUNT_TRANSLATOR (-4)
248
249#if 0
250/*
251 * Flags for ext2fs_move_blocks
252 */
253#define EXT2_BMOVE_GET_DBLIST 0x0001
254#define EXT2_BMOVE_DEBUG 0x0002
255#endif
256
257/*
258 * Flags for directory block reading and writing functions
259 */
260#define EXT2_DIRBLOCK_V2_STRUCT 0x0001
261
262/*
263 * Return flags for the directory iterator functions
264 */
265#define DIRENT_CHANGED 1
266#define DIRENT_ABORT 2
267#define DIRENT_ERROR 3
268
269/*
270 * Directory iterator flags
271 */
272
273#define DIRENT_FLAG_INCLUDE_EMPTY 1
274#define DIRENT_FLAG_INCLUDE_REMOVED 2
275
276#define DIRENT_DOT_FILE 1
277#define DIRENT_DOT_DOT_FILE 2
278#define DIRENT_OTHER_FILE 3
279#define DIRENT_DELETED_FILE 4
280
281/*
282 * Inode scan definitions
283 */
284typedef struct ext2_struct_inode_scan *ext2_inode_scan;
285
286/*
287 * ext2fs_scan flags
288 */
289#define EXT2_SF_CHK_BADBLOCKS 0x0001
290#define EXT2_SF_BAD_INODE_BLK 0x0002
291#define EXT2_SF_BAD_EXTRA_BYTES 0x0004
292#define EXT2_SF_SKIP_MISSING_ITABLE 0x0008
293
294/*
295 * ext2fs_check_if_mounted flags
296 */
297#define EXT2_MF_MOUNTED 1
298#define EXT2_MF_ISROOT 2
299#define EXT2_MF_READONLY 4
300#define EXT2_MF_SWAP 8
301#define EXT2_MF_BUSY 16
302
303/*
304 * Ext2/linux mode flags. We define them here so that we don't need
305 * to depend on the OS's sys/stat.h, since we may be compiling on a
306 * non-Linux system.
307 */
308#define LINUX_S_IFMT 00170000
309#define LINUX_S_IFSOCK 0140000
310#define LINUX_S_IFLNK 0120000
311#define LINUX_S_IFREG 0100000
312#define LINUX_S_IFBLK 0060000
313#define LINUX_S_IFDIR 0040000
314#define LINUX_S_IFCHR 0020000
315#define LINUX_S_IFIFO 0010000
316#define LINUX_S_ISUID 0004000
317#define LINUX_S_ISGID 0002000
318#define LINUX_S_ISVTX 0001000
319
320#define LINUX_S_IRWXU 00700
321#define LINUX_S_IRUSR 00400
322#define LINUX_S_IWUSR 00200
323#define LINUX_S_IXUSR 00100
324
325#define LINUX_S_IRWXG 00070
326#define LINUX_S_IRGRP 00040
327#define LINUX_S_IWGRP 00020
328#define LINUX_S_IXGRP 00010
329
330#define LINUX_S_IRWXO 00007
331#define LINUX_S_IROTH 00004
332#define LINUX_S_IWOTH 00002
333#define LINUX_S_IXOTH 00001
334
335#define LINUX_S_ISLNK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK)
336#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG)
337#define LINUX_S_ISDIR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR)
338#define LINUX_S_ISCHR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR)
339#define LINUX_S_ISBLK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK)
340#define LINUX_S_ISFIFO(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO)
341#define LINUX_S_ISSOCK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK)
342
343/*
344 * ext2 size of an inode
345 */
346#define EXT2_I_SIZE(i) ((i)->i_size | ((__u64) (i)->i_size_high << 32))
347
348/*
349 * ext2_icount_t abstraction
350 */
351#define EXT2_ICOUNT_OPT_INCREMENT 0x01
352
353typedef struct ext2_icount *ext2_icount_t;
354
355/*
356 * Flags for ext2fs_bmap
357 */
358#define BMAP_ALLOC 0x0001
359#define BMAP_SET 0x0002
360
361/*
362 * Flags for imager.c functions
363 */
364#define IMAGER_FLAG_INODEMAP 1
365#define IMAGER_FLAG_SPARSEWRITE 2
366
367/*
368 * For checking structure magic numbers...
369 */
370
371#define EXT2_CHECK_MAGIC(struct, code) \
372 if ((struct)->magic != (code)) return (code)
373
374
375/*
376 * For ext2 compression support
377 */
378#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) 0xffffffff)
379#define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR)
380
381/*
382 * Features supported by this version of the library
383 */
384#define EXT2_LIB_FEATURE_COMPAT_SUPP (EXT2_FEATURE_COMPAT_DIR_PREALLOC|\
385 EXT2_FEATURE_COMPAT_IMAGIC_INODES|\
386 EXT3_FEATURE_COMPAT_HAS_JOURNAL|\
387 EXT2_FEATURE_COMPAT_RESIZE_INODE|\
388 EXT2_FEATURE_COMPAT_DIR_INDEX|\
389 EXT2_FEATURE_COMPAT_EXT_ATTR)
390
391/* This #ifdef is temporary until compression is fully supported */
392#ifdef ENABLE_COMPRESSION
393#ifndef I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL
394/* If the below warning bugs you, then have
395 `CPPFLAGS=-DI_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL' in your
396 environment at configure time. */
397 #warning "Compression support is experimental"
398#endif
399#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
400 EXT2_FEATURE_INCOMPAT_COMPRESSION|\
401 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
402 EXT2_FEATURE_INCOMPAT_META_BG|\
403 EXT3_FEATURE_INCOMPAT_RECOVER)
404#else
405#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
406 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
407 EXT2_FEATURE_INCOMPAT_META_BG|\
408 EXT3_FEATURE_INCOMPAT_RECOVER)
409#endif
410#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
411 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
412/*
413 * function prototypes
414 */
415
416/* alloc.c */
417extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode,
418 ext2fs_inode_bitmap map, ext2_ino_t *ret);
419extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
420 ext2fs_block_bitmap map, blk_t *ret);
421extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start,
422 blk_t finish, int num,
423 ext2fs_block_bitmap map,
424 blk_t *ret);
425extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
426 char *block_buf, blk_t *ret);
427
428/* alloc_sb.c */
429extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
430 dgrp_t group,
431 ext2fs_block_bitmap bmap);
432
433/* alloc_stats.c */
434void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse);
435void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
436 int inuse, int isdir);
437void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse);
438
439/* alloc_tables.c */
440extern errcode_t ext2fs_allocate_tables(ext2_filsys fs);
441extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
442 ext2fs_block_bitmap bmap);
443
444/* badblocks.c */
445extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size);
446extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk);
447extern int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk);
448extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk);
449extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
450 ext2_u32_iterate *ret);
451extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk);
452extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter);
453extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest);
454extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2);
455
456extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret,
457 int size);
458extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb,
459 blk_t blk);
460extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb,
461 blk_t blk);
462extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk);
463extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk);
464extern errcode_t
465 ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
466 ext2_badblocks_iterate *ret);
467extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter,
468 blk_t *blk);
469extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter);
470extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
471 ext2_badblocks_list *dest);
472extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1,
473 ext2_badblocks_list bb2);
474extern int ext2fs_u32_list_count(ext2_u32_list bb);
475
476/* bb_compat */
477extern errcode_t badblocks_list_create(badblocks_list *ret, int size);
478extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk);
479extern int badblocks_list_test(badblocks_list bb, blk_t blk);
480extern errcode_t badblocks_list_iterate_begin(badblocks_list bb,
481 badblocks_iterate *ret);
482extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk);
483extern void badblocks_list_iterate_end(badblocks_iterate iter);
484extern void badblocks_list_free(badblocks_list bb);
485
486/* bb_inode.c */
487extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs,
488 ext2_badblocks_list bb_list);
489
490/* bitmaps.c */
491extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs);
492extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs);
493extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs);
494extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs);
495extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
496 __u32 end,
497 __u32 real_end,
498 const char *descr,
499 ext2fs_generic_bitmap *ret);
500extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
501 const char *descr,
502 ext2fs_block_bitmap *ret);
503extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
504 const char *descr,
505 ext2fs_inode_bitmap *ret);
506extern errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
507 ext2_ino_t end, ext2_ino_t *oend);
508extern errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
509 blk_t end, blk_t *oend);
510extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap);
511extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap);
512extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs);
513extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs);
514
515/* block.c */
516extern errcode_t ext2fs_block_iterate(ext2_filsys fs,
517 ext2_ino_t ino,
518 int flags,
519 char *block_buf,
520 int (*func)(ext2_filsys fs,
521 blk_t *blocknr,
522 int blockcnt,
523 void *priv_data),
524 void *priv_data);
525errcode_t ext2fs_block_iterate2(ext2_filsys fs,
526 ext2_ino_t ino,
527 int flags,
528 char *block_buf,
529 int (*func)(ext2_filsys fs,
530 blk_t *blocknr,
531 e2_blkcnt_t blockcnt,
532 blk_t ref_blk,
533 int ref_offset,
534 void *priv_data),
535 void *priv_data);
536
537/* bmap.c */
538extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
539 struct ext2_inode *inode,
540 char *block_buf, int bmap_flags,
541 blk_t block, blk_t *phys_blk);
542
543
544#if 0
545/* bmove.c */
546extern errcode_t ext2fs_move_blocks(ext2_filsys fs,
547 ext2fs_block_bitmap reserve,
548 ext2fs_block_bitmap alloc_map,
549 int flags);
550#endif
551
552/* check_desc.c */
553extern errcode_t ext2fs_check_desc(ext2_filsys fs);
554
555/* closefs.c */
556extern errcode_t ext2fs_close(ext2_filsys fs);
557extern errcode_t ext2fs_flush(ext2_filsys fs);
558extern int ext2fs_bg_has_super(ext2_filsys fs, int group_block);
559extern int ext2fs_super_and_bgd_loc(ext2_filsys fs,
560 dgrp_t group,
561 blk_t *ret_super_blk,
562 blk_t *ret_old_desc_blk,
563 blk_t *ret_new_desc_blk,
564 int *ret_meta_bg);
565extern void ext2fs_update_dynamic_rev(ext2_filsys fs);
566
567/* cmp_bitmaps.c */
568extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
569 ext2fs_block_bitmap bm2);
570extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
571 ext2fs_inode_bitmap bm2);
572
573/* dblist.c */
574
575extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
576extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist);
577extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino,
578 blk_t blk, int blockcnt);
579extern void ext2fs_dblist_sort(ext2_dblist dblist,
580 int (*sortfunc)(const void *,
581 const void *));
582extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
583 int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info,
584 void *priv_data),
585 void *priv_data);
586extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino,
587 blk_t blk, int blockcnt);
588extern errcode_t ext2fs_copy_dblist(ext2_dblist src,
589 ext2_dblist *dest);
590extern int ext2fs_dblist_count(ext2_dblist dblist);
591
592/* dblist_dir.c */
593extern errcode_t
594 ext2fs_dblist_dir_iterate(ext2_dblist dblist,
595 int flags,
596 char *block_buf,
597 int (*func)(ext2_ino_t dir,
598 int entry,
599 struct ext2_dir_entry *dirent,
600 int offset,
601 int blocksize,
602 char *buf,
603 void *priv_data),
604 void *priv_data);
605
606/* dirblock.c */
607extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
608 void *buf);
609extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
610 void *buf, int flags);
611extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
612 void *buf);
613extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
614 void *buf, int flags);
615
616/* dirhash.c */
617extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
618 const __u32 *seed,
619 ext2_dirhash_t *ret_hash,
620 ext2_dirhash_t *ret_minor_hash);
621
622
623/* dir_iterate.c */
624extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
625 ext2_ino_t dir,
626 int flags,
627 char *block_buf,
628 int (*func)(struct ext2_dir_entry *dirent,
629 int offset,
630 int blocksize,
631 char *buf,
632 void *priv_data),
633 void *priv_data);
634extern errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
635 ext2_ino_t dir,
636 int flags,
637 char *block_buf,
638 int (*func)(ext2_ino_t dir,
639 int entry,
640 struct ext2_dir_entry *dirent,
641 int offset,
642 int blocksize,
643 char *buf,
644 void *priv_data),
645 void *priv_data);
646
647/* dupfs.c */
648extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest);
649
650/* expanddir.c */
651extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
652
653/* ext_attr.c */
654extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
655extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
656 void *buf);
657extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
658 char *block_buf,
659 int adjust, __u32 *newcount);
660
661/* fileio.c */
662extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
663 struct ext2_inode *inode,
664 int flags, ext2_file_t *ret);
665extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
666 int flags, ext2_file_t *ret);
667extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file);
668extern errcode_t ext2fs_file_close(ext2_file_t file);
669extern errcode_t ext2fs_file_flush(ext2_file_t file);
670extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
671 unsigned int wanted, unsigned int *got);
672extern errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
673 unsigned int nbytes, unsigned int *written);
674extern errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
675 int whence, __u64 *ret_pos);
676extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
677 int whence, ext2_off_t *ret_pos);
678errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size);
679extern ext2_off_t ext2fs_file_get_size(ext2_file_t file);
680extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size);
681
682/* finddev.c */
683extern char *ext2fs_find_block_device(dev_t device);
684
685/* flushb.c */
686extern errcode_t ext2fs_sync_device(int fd, int flushb);
687
688/* freefs.c */
689extern void ext2fs_free(ext2_filsys fs);
690extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap);
691extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
692extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
693extern void ext2fs_free_dblist(ext2_dblist dblist);
694extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb);
695extern void ext2fs_u32_list_free(ext2_u32_list bb);
696
697/* getsize.c */
698extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
699 blk_t *retblocks);
700
701/* getsectsize.c */
702errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize);
703
704/* imager.c */
705extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags);
706extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags);
707extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags);
708extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags);
709extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags);
710extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags);
711
712/* ind_block.c */
713errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf);
714errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf);
715
716/* initialize.c */
717extern errcode_t ext2fs_initialize(const char *name, int flags,
718 struct ext2_super_block *param,
719 io_manager manager, ext2_filsys *ret_fs);
720
721/* icount.c */
722extern void ext2fs_free_icount(ext2_icount_t icount);
723extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags,
724 unsigned int size,
725 ext2_icount_t hint, ext2_icount_t *ret);
726extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags,
727 unsigned int size,
728 ext2_icount_t *ret);
729extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino,
730 __u16 *ret);
731extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
732 __u16 *ret);
733extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
734 __u16 *ret);
735extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
736 __u16 count);
737extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
738errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
739
740/* inode.c */
741extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
742extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
743 ext2_ino_t *ino,
744 struct ext2_inode *inode,
745 int bufsize);
746extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
747 ext2_inode_scan *ret_scan);
748extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
749extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
750 struct ext2_inode *inode);
751extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
752 int group);
753extern void ext2fs_set_inode_callback
754 (ext2_inode_scan scan,
755 errcode_t (*done_group)(ext2_filsys fs,
756 dgrp_t group,
757 void * priv_data),
758 void *done_group_data);
759extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
760 int clear_flags);
761extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
762 struct ext2_inode * inode,
763 int bufsize);
764extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
765 struct ext2_inode * inode);
766extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
767 struct ext2_inode * inode,
768 int bufsize);
769extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
770 struct ext2_inode * inode);
771extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
772 struct ext2_inode * inode);
773extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
774extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino);
775
776/* inode_io.c */
777extern io_manager inode_io_manager;
778extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
779 char **name);
780extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
781 struct ext2_inode *inode,
782 char **name);
783
784/* ismounted.c */
785extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags);
786extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
787 char *mtpt, int mtlen);
788
789/* namei.c */
790extern errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
791 int namelen, char *buf, ext2_ino_t *inode);
792extern errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
793 const char *name, ext2_ino_t *inode);
794errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
795 const char *name, ext2_ino_t *inode);
796extern errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
797 ext2_ino_t inode, ext2_ino_t *res_inode);
798
799/* native.c */
800int ext2fs_native_flag(void);
801
802/* newdir.c */
803extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
804 ext2_ino_t parent_ino, char **block);
805
806/* mkdir.c */
807extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
808 const char *name);
809
810/* mkjournal.c */
811extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
812 __u32 size, int flags,
813 char **ret_jsb);
814extern errcode_t ext2fs_add_journal_device(ext2_filsys fs,
815 ext2_filsys journal_dev);
816extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size,
817 int flags);
818
819/* openfs.c */
820extern errcode_t ext2fs_open(const char *name, int flags, int superblock,
821 unsigned int block_size, io_manager manager,
822 ext2_filsys *ret_fs);
823extern errcode_t ext2fs_open2(const char *name, const char *io_options,
824 int flags, int superblock,
825 unsigned int block_size, io_manager manager,
826 ext2_filsys *ret_fs);
827extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block,
828 dgrp_t i);
829errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io);
830errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io);
831errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io);
832
833/* get_pathname.c */
834extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
835 char **name);
836
837/* link.c */
838errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
839 ext2_ino_t ino, int flags);
840errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name,
841 ext2_ino_t ino, int flags);
842
843/* read_bb.c */
844extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs,
845 ext2_badblocks_list *bb_list);
846
847/* read_bb_file.c */
848extern errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
849 ext2_badblocks_list *bb_list,
850 void *priv_data,
851 void (*invalid)(ext2_filsys fs,
852 blk_t blk,
853 char *badstr,
854 void *priv_data));
855extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
856 ext2_badblocks_list *bb_list,
857 void (*invalid)(ext2_filsys fs,
858 blk_t blk));
859
860/* res_gdt.c */
861extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
862
863/* rs_bitmap.c */
864extern errcode_t ext2fs_resize_generic_bitmap(__u32 new_end,
865 __u32 new_real_end,
866 ext2fs_generic_bitmap bmap);
867extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
868 ext2fs_inode_bitmap bmap);
869extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
870 ext2fs_block_bitmap bmap);
871extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
872 ext2fs_generic_bitmap *dest);
873
874/* swapfs.c */
875extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize,
876 int has_header);
877extern void ext2fs_swap_super(struct ext2_super_block * super);
878extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp);
879extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
880 struct ext2_inode_large *f, int hostorder,
881 int bufsize);
882extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
883 struct ext2_inode *f, int hostorder);
884
885/* valid_blk.c */
886extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
887
888/* version.c */
889extern int ext2fs_parse_version_string(const char *ver_string);
890extern int ext2fs_get_library_version(const char **ver_string,
891 const char **date_string);
892
893/* write_bb_file.c */
894extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
895 unsigned int flags,
896 FILE *f);
897
898
899/* inline functions */
900extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr);
901extern errcode_t ext2fs_free_mem(void *ptr);
902extern errcode_t ext2fs_resize_mem(unsigned long old_size,
903 unsigned long size, void *ptr);
904extern void ext2fs_mark_super_dirty(ext2_filsys fs);
905extern void ext2fs_mark_changed(ext2_filsys fs);
906extern int ext2fs_test_changed(ext2_filsys fs);
907extern void ext2fs_mark_valid(ext2_filsys fs);
908extern void ext2fs_unmark_valid(ext2_filsys fs);
909extern int ext2fs_test_valid(ext2_filsys fs);
910extern void ext2fs_mark_ib_dirty(ext2_filsys fs);
911extern void ext2fs_mark_bb_dirty(ext2_filsys fs);
912extern int ext2fs_test_ib_dirty(ext2_filsys fs);
913extern int ext2fs_test_bb_dirty(ext2_filsys fs);
914extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
915extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
916extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
917 struct ext2_inode *inode);
918
919#ifdef __cplusplus
920}
921#endif
922
923#endif /* _EXT2FS_EXT2FS_H */
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h
new file mode 100644
index 000000000..908b5d9a4
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h
@@ -0,0 +1,89 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ext2fsP.h --- private header file for ext2 library
4 *
5 * Copyright (C) 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include "ext2fs.h"
14
15/*
16 * Badblocks list
17 */
18struct ext2_struct_u32_list {
19 int magic;
20 int num;
21 int size;
22 __u32 *list;
23 int badblocks_flags;
24};
25
26struct ext2_struct_u32_iterate {
27 int magic;
28 ext2_u32_list bb;
29 int ptr;
30};
31
32
33/*
34 * Directory block iterator definition
35 */
36struct ext2_struct_dblist {
37 int magic;
38 ext2_filsys fs;
39 ext2_ino_t size;
40 ext2_ino_t count;
41 int sorted;
42 struct ext2_db_entry * list;
43};
44
45/*
46 * For directory iterators
47 */
48struct dir_context {
49 ext2_ino_t dir;
50 int flags;
51 char *buf;
52 int (*func)(ext2_ino_t dir,
53 int entry,
54 struct ext2_dir_entry *dirent,
55 int offset,
56 int blocksize,
57 char *buf,
58 void *priv_data);
59 void *priv_data;
60 errcode_t errcode;
61};
62
63/*
64 * Inode cache structure
65 */
66struct ext2_inode_cache {
67 void * buffer;
68 blk_t buffer_blk;
69 int cache_last;
70 int cache_size;
71 int refcount;
72 struct ext2_inode_cache_ent *cache;
73};
74
75struct ext2_inode_cache_ent {
76 ext2_ino_t ino;
77 struct ext2_inode inode;
78};
79
80/* Function prototypes */
81
82extern int ext2fs_process_dir_block(ext2_filsys fs,
83 blk_t *blocknr,
84 e2_blkcnt_t blockcnt,
85 blk_t ref_block,
86 int ref_offset,
87 void *priv_data);
88
89
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c
new file mode 100644
index 000000000..da1cf5be5
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c
@@ -0,0 +1,367 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ext2fs.h --- ext2fs
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include "ext2fs.h"
14#include "bitops.h"
15#include <string.h>
16
17/*
18 * Allocate memory
19 */
20errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
21{
22 void **pp = (void **)ptr;
23
24 *pp = malloc(size);
25 if (!*pp)
26 return EXT2_ET_NO_MEMORY;
27 return 0;
28}
29
30/*
31 * Free memory
32 */
33errcode_t ext2fs_free_mem(void *ptr)
34{
35 void **pp = (void **)ptr;
36
37 free(*pp);
38 *pp = 0;
39 return 0;
40}
41
42/*
43 * Resize memory
44 */
45errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size,
46 unsigned long size, void *ptr)
47{
48 void *p;
49
50 /* Use "memcpy" for pointer assignments here to avoid problems
51 * with C99 strict type aliasing rules. */
52 memcpy(&p, ptr, sizeof (p));
53 p = realloc(p, size);
54 if (!p)
55 return EXT2_ET_NO_MEMORY;
56 memcpy(ptr, &p, sizeof (p));
57 return 0;
58}
59
60/*
61 * Mark a filesystem superblock as dirty
62 */
63void ext2fs_mark_super_dirty(ext2_filsys fs)
64{
65 fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_CHANGED;
66}
67
68/*
69 * Mark a filesystem as changed
70 */
71void ext2fs_mark_changed(ext2_filsys fs)
72{
73 fs->flags |= EXT2_FLAG_CHANGED;
74}
75
76/*
77 * Check to see if a filesystem has changed
78 */
79int ext2fs_test_changed(ext2_filsys fs)
80{
81 return (fs->flags & EXT2_FLAG_CHANGED);
82}
83
84/*
85 * Mark a filesystem as valid
86 */
87void ext2fs_mark_valid(ext2_filsys fs)
88{
89 fs->flags |= EXT2_FLAG_VALID;
90}
91
92/*
93 * Mark a filesystem as NOT valid
94 */
95void ext2fs_unmark_valid(ext2_filsys fs)
96{
97 fs->flags &= ~EXT2_FLAG_VALID;
98}
99
100/*
101 * Check to see if a filesystem is valid
102 */
103int ext2fs_test_valid(ext2_filsys fs)
104{
105 return (fs->flags & EXT2_FLAG_VALID);
106}
107
108/*
109 * Mark the inode bitmap as dirty
110 */
111void ext2fs_mark_ib_dirty(ext2_filsys fs)
112{
113 fs->flags |= EXT2_FLAG_IB_DIRTY | EXT2_FLAG_CHANGED;
114}
115
116/*
117 * Mark the block bitmap as dirty
118 */
119void ext2fs_mark_bb_dirty(ext2_filsys fs)
120{
121 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_CHANGED;
122}
123
124/*
125 * Check to see if a filesystem's inode bitmap is dirty
126 */
127int ext2fs_test_ib_dirty(ext2_filsys fs)
128{
129 return (fs->flags & EXT2_FLAG_IB_DIRTY);
130}
131
132/*
133 * Check to see if a filesystem's block bitmap is dirty
134 */
135int ext2fs_test_bb_dirty(ext2_filsys fs)
136{
137 return (fs->flags & EXT2_FLAG_BB_DIRTY);
138}
139
140/*
141 * Return the group # of a block
142 */
143int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk)
144{
145 return (blk - fs->super->s_first_data_block) /
146 fs->super->s_blocks_per_group;
147}
148
149/*
150 * Return the group # of an inode number
151 */
152int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
153{
154 return (ino - 1) / fs->super->s_inodes_per_group;
155}
156
157blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
158 struct ext2_inode *inode)
159{
160 return inode->i_blocks -
161 (inode->i_file_acl ? fs->blocksize >> 9 : 0);
162}
163
164
165
166
167
168
169
170
171
172__u16 ext2fs_swab16(__u16 val)
173{
174 return (val >> 8) | (val << 8);
175}
176
177__u32 ext2fs_swab32(__u32 val)
178{
179 return ((val>>24) | ((val>>8)&0xFF00) |
180 ((val<<8)&0xFF0000) | (val<<24));
181}
182
183int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
184 blk_t bitno);
185
186int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
187 blk_t bitno)
188{
189 if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
190 ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
191 return 0;
192 }
193 return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
194}
195
196int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
197 blk_t block)
198{
199 return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap)
200 bitmap,
201 block);
202}
203
204int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
205 blk_t block)
206{
207 return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
208 block);
209}
210
211int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
212 blk_t block)
213{
214 return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
215 block);
216}
217
218int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
219 ext2_ino_t inode)
220{
221 return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
222 inode);
223}
224
225int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
226 ext2_ino_t inode)
227{
228 return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
229 inode);
230}
231
232int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
233 ext2_ino_t inode)
234{
235 return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
236 inode);
237}
238
239void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
240 blk_t block)
241{
242 ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
243}
244
245void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
246 blk_t block)
247{
248 ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
249}
250
251int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
252 blk_t block)
253{
254 return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
255}
256
257void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
258 ext2_ino_t inode)
259{
260 ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
261}
262
263void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
264 ext2_ino_t inode)
265{
266 ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
267}
268
269int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
270 ext2_ino_t inode)
271{
272 return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
273}
274
275blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
276{
277 return bitmap->start;
278}
279
280ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
281{
282 return bitmap->start;
283}
284
285blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
286{
287 return bitmap->end;
288}
289
290ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
291{
292 return bitmap->end;
293}
294
295int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
296 blk_t block, int num)
297{
298 int i;
299
300 if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
301 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
302 block, bitmap->description);
303 return 0;
304 }
305 for (i=0; i < num; i++) {
306 if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
307 return 0;
308 }
309 return 1;
310}
311
312int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
313 blk_t block, int num)
314{
315 int i;
316
317 for (i=0; i < num; i++) {
318 if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
319 return 0;
320 }
321 return 1;
322}
323
324void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
325 blk_t block, int num)
326{
327 int i;
328
329 if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
330 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
331 bitmap->description);
332 return;
333 }
334 for (i=0; i < num; i++)
335 ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
336}
337
338void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
339 blk_t block, int num)
340{
341 int i;
342
343 for (i=0; i < num; i++)
344 ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
345}
346
347void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
348 blk_t block, int num)
349{
350 int i;
351
352 if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
353 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
354 bitmap->description);
355 return;
356 }
357 for (i=0; i < num; i++)
358 ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
359}
360
361void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
362 blk_t block, int num)
363{
364 int i;
365 for (i=0; i < num; i++)
366 ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
367}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext_attr.c b/e2fsprogs/old_e2fsprogs/ext2fs/ext_attr.c
new file mode 100644
index 000000000..7ee41f234
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext_attr.c
@@ -0,0 +1,101 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ext_attr.c --- extended attribute blocks
4 *
5 * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
6 *
7 * Copyright (C) 2002 Theodore Ts'o.
8 *
9 * %Begin-Header%
10 * This file may be redistributed under the terms of the GNU Public
11 * License.
12 * %End-Header%
13 */
14
15#include <stdio.h>
16#include <unistd.h>
17#include <string.h>
18#include <time.h>
19
20#include "ext2_fs.h"
21#include "ext2_ext_attr.h"
22#include "ext2fs.h"
23
24errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
25{
26 errcode_t retval;
27
28 retval = io_channel_read_blk(fs->io, block, 1, buf);
29 if (retval)
30 return retval;
31#if BB_BIG_ENDIAN
32 if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
33 EXT2_FLAG_SWAP_BYTES_READ)) != 0)
34 ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
35#endif
36 return 0;
37}
38
39errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
40{
41 errcode_t retval;
42 char *write_buf;
43 char *buf = NULL;
44
45 if (BB_BIG_ENDIAN && ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
46 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) {
47 retval = ext2fs_get_mem(fs->blocksize, &buf);
48 if (retval)
49 return retval;
50 write_buf = buf;
51 ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
52 } else
53 write_buf = (char *) inbuf;
54 retval = io_channel_write_blk(fs->io, block, 1, write_buf);
55 if (buf)
56 ext2fs_free_mem(&buf);
57 if (!retval)
58 ext2fs_mark_changed(fs);
59 return retval;
60}
61
62/*
63 * This function adjusts the reference count of the EA block.
64 */
65errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
66 char *block_buf, int adjust,
67 __u32 *newcount)
68{
69 errcode_t retval;
70 struct ext2_ext_attr_header *header;
71 char *buf = 0;
72
73 if ((blk >= fs->super->s_blocks_count) ||
74 (blk < fs->super->s_first_data_block))
75 return EXT2_ET_BAD_EA_BLOCK_NUM;
76
77 if (!block_buf) {
78 retval = ext2fs_get_mem(fs->blocksize, &buf);
79 if (retval)
80 return retval;
81 block_buf = buf;
82 }
83
84 retval = ext2fs_read_ext_attr(fs, blk, block_buf);
85 if (retval)
86 goto errout;
87
88 header = (struct ext2_ext_attr_header *) block_buf;
89 header->h_refcount += adjust;
90 if (newcount)
91 *newcount = header->h_refcount;
92
93 retval = ext2fs_write_ext_attr(fs, blk, block_buf);
94 if (retval)
95 goto errout;
96
97errout:
98 if (buf)
99 ext2fs_free_mem(&buf);
100 return retval;
101}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/fileio.c b/e2fsprogs/old_e2fsprogs/ext2fs/fileio.c
new file mode 100644
index 000000000..c56a21aa8
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/fileio.c
@@ -0,0 +1,377 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fileio.c --- Simple file I/O routines
4 *
5 * Copyright (C) 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22struct ext2_file {
23 errcode_t magic;
24 ext2_filsys fs;
25 ext2_ino_t ino;
26 struct ext2_inode inode;
27 int flags;
28 __u64 pos;
29 blk_t blockno;
30 blk_t physblock;
31 char *buf;
32};
33
34#define BMAP_BUFFER (file->buf + fs->blocksize)
35
36errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
37 struct ext2_inode *inode,
38 int flags, ext2_file_t *ret)
39{
40 ext2_file_t file;
41 errcode_t retval;
42
43 /*
44 * Don't let caller create or open a file for writing if the
45 * filesystem is read-only.
46 */
47 if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
48 !(fs->flags & EXT2_FLAG_RW))
49 return EXT2_ET_RO_FILSYS;
50
51 retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
52 if (retval)
53 return retval;
54
55 memset(file, 0, sizeof(struct ext2_file));
56 file->magic = EXT2_ET_MAGIC_EXT2_FILE;
57 file->fs = fs;
58 file->ino = ino;
59 file->flags = flags & EXT2_FILE_MASK;
60
61 if (inode) {
62 memcpy(&file->inode, inode, sizeof(struct ext2_inode));
63 } else {
64 retval = ext2fs_read_inode(fs, ino, &file->inode);
65 if (retval)
66 goto fail;
67 }
68
69 retval = ext2fs_get_mem(fs->blocksize * 3, &file->buf);
70 if (retval)
71 goto fail;
72
73 *ret = file;
74 return 0;
75
76fail:
77 ext2fs_free_mem(&file->buf);
78 ext2fs_free_mem(&file);
79 return retval;
80}
81
82errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
83 int flags, ext2_file_t *ret)
84{
85 return ext2fs_file_open2(fs, ino, NULL, flags, ret);
86}
87
88/*
89 * This function returns the filesystem handle of a file from the structure
90 */
91ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
92{
93 if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
94 return 0;
95 return file->fs;
96}
97
98/*
99 * This function flushes the dirty block buffer out to disk if
100 * necessary.
101 */
102errcode_t ext2fs_file_flush(ext2_file_t file)
103{
104 errcode_t retval;
105 ext2_filsys fs;
106
107 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
108 fs = file->fs;
109
110 if (!(file->flags & EXT2_FILE_BUF_VALID) ||
111 !(file->flags & EXT2_FILE_BUF_DIRTY))
112 return 0;
113
114 /*
115 * OK, the physical block hasn't been allocated yet.
116 * Allocate it.
117 */
118 if (!file->physblock) {
119 retval = ext2fs_bmap(fs, file->ino, &file->inode,
120 BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0,
121 file->blockno, &file->physblock);
122 if (retval)
123 return retval;
124 }
125
126 retval = io_channel_write_blk(fs->io, file->physblock,
127 1, file->buf);
128 if (retval)
129 return retval;
130
131 file->flags &= ~EXT2_FILE_BUF_DIRTY;
132
133 return retval;
134}
135
136/*
137 * This function synchronizes the file's block buffer and the current
138 * file position, possibly invalidating block buffer if necessary
139 */
140static errcode_t sync_buffer_position(ext2_file_t file)
141{
142 blk_t b;
143 errcode_t retval;
144
145 b = file->pos / file->fs->blocksize;
146 if (b != file->blockno) {
147 retval = ext2fs_file_flush(file);
148 if (retval)
149 return retval;
150 file->flags &= ~EXT2_FILE_BUF_VALID;
151 }
152 file->blockno = b;
153 return 0;
154}
155
156/*
157 * This function loads the file's block buffer with valid data from
158 * the disk as necessary.
159 *
160 * If dontfill is true, then skip initializing the buffer since we're
161 * going to be replacing its entire contents anyway. If set, then the
162 * function basically only sets file->physblock and EXT2_FILE_BUF_VALID
163 */
164#define DONTFILL 1
165static errcode_t load_buffer(ext2_file_t file, int dontfill)
166{
167 ext2_filsys fs = file->fs;
168 errcode_t retval;
169
170 if (!(file->flags & EXT2_FILE_BUF_VALID)) {
171 retval = ext2fs_bmap(fs, file->ino, &file->inode,
172 BMAP_BUFFER, 0, file->blockno,
173 &file->physblock);
174 if (retval)
175 return retval;
176 if (!dontfill) {
177 if (file->physblock) {
178 retval = io_channel_read_blk(fs->io,
179 file->physblock,
180 1, file->buf);
181 if (retval)
182 return retval;
183 } else
184 memset(file->buf, 0, fs->blocksize);
185 }
186 file->flags |= EXT2_FILE_BUF_VALID;
187 }
188 return 0;
189}
190
191
192errcode_t ext2fs_file_close(ext2_file_t file)
193{
194 errcode_t retval;
195
196 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
197
198 retval = ext2fs_file_flush(file);
199
200 ext2fs_free_mem(&file->buf);
201 ext2fs_free_mem(&file);
202
203 return retval;
204}
205
206
207errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
208 unsigned int wanted, unsigned int *got)
209{
210 ext2_filsys fs;
211 errcode_t retval = 0;
212 unsigned int start, c, count = 0;
213 __u64 left;
214 char *ptr = (char *) buf;
215
216 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
217 fs = file->fs;
218
219 while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
220 retval = sync_buffer_position(file);
221 if (retval)
222 goto fail;
223 retval = load_buffer(file, 0);
224 if (retval)
225 goto fail;
226
227 start = file->pos % fs->blocksize;
228 c = fs->blocksize - start;
229 if (c > wanted)
230 c = wanted;
231 left = EXT2_I_SIZE(&file->inode) - file->pos ;
232 if (c > left)
233 c = left;
234
235 memcpy(ptr, file->buf+start, c);
236 file->pos += c;
237 ptr += c;
238 count += c;
239 wanted -= c;
240 }
241
242fail:
243 if (got)
244 *got = count;
245 return retval;
246}
247
248
249errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
250 unsigned int nbytes, unsigned int *written)
251{
252 ext2_filsys fs;
253 errcode_t retval = 0;
254 unsigned int start, c, count = 0;
255 const char *ptr = (const char *) buf;
256
257 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
258 fs = file->fs;
259
260 if (!(file->flags & EXT2_FILE_WRITE))
261 return EXT2_ET_FILE_RO;
262
263 while (nbytes > 0) {
264 retval = sync_buffer_position(file);
265 if (retval)
266 goto fail;
267
268 start = file->pos % fs->blocksize;
269 c = fs->blocksize - start;
270 if (c > nbytes)
271 c = nbytes;
272
273 /*
274 * We only need to do a read-modify-update cycle if
275 * we're doing a partial write.
276 */
277 retval = load_buffer(file, (c == fs->blocksize));
278 if (retval)
279 goto fail;
280
281 file->flags |= EXT2_FILE_BUF_DIRTY;
282 memcpy(file->buf+start, ptr, c);
283 file->pos += c;
284 ptr += c;
285 count += c;
286 nbytes -= c;
287 }
288
289fail:
290 if (written)
291 *written = count;
292 return retval;
293}
294
295errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
296 int whence, __u64 *ret_pos)
297{
298 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
299
300 if (whence == EXT2_SEEK_SET)
301 file->pos = offset;
302 else if (whence == EXT2_SEEK_CUR)
303 file->pos += offset;
304 else if (whence == EXT2_SEEK_END)
305 file->pos = EXT2_I_SIZE(&file->inode) + offset;
306 else
307 return EXT2_ET_INVALID_ARGUMENT;
308
309 if (ret_pos)
310 *ret_pos = file->pos;
311
312 return 0;
313}
314
315errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
316 int whence, ext2_off_t *ret_pos)
317{
318 __u64 loffset, ret_loffset;
319 errcode_t retval;
320
321 loffset = offset;
322 retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset);
323 if (ret_pos)
324 *ret_pos = (ext2_off_t) ret_loffset;
325 return retval;
326}
327
328
329/*
330 * This function returns the size of the file, according to the inode
331 */
332errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size)
333{
334 if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
335 return EXT2_ET_MAGIC_EXT2_FILE;
336 *ret_size = EXT2_I_SIZE(&file->inode);
337 return 0;
338}
339
340/*
341 * This function returns the size of the file, according to the inode
342 */
343ext2_off_t ext2fs_file_get_size(ext2_file_t file)
344{
345 __u64 size;
346
347 if (ext2fs_file_get_lsize(file, &size))
348 return 0;
349 if ((size >> 32) != 0)
350 return 0;
351 return size;
352}
353
354/*
355 * This function sets the size of the file, truncating it if necessary
356 *
357 * XXX still need to call truncate
358 */
359errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
360{
361 errcode_t retval;
362 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
363
364 file->inode.i_size = size;
365 file->inode.i_size_high = 0;
366 if (file->ino) {
367 retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
368 if (retval)
369 return retval;
370 }
371
372 /*
373 * XXX truncate inode if necessary
374 */
375
376 return 0;
377}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/finddev.c b/e2fsprogs/old_e2fsprogs/ext2fs/finddev.c
new file mode 100644
index 000000000..5e2cce940
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/finddev.c
@@ -0,0 +1,199 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * finddev.c -- this routine attempts to find a particular device in
4 * /dev
5 *
6 * Copyright (C) 2000 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#ifdef HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#include <stdlib.h>
20#include <string.h>
21#ifdef HAVE_SYS_TYPES_H
22#include <sys/types.h>
23#endif
24#ifdef HAVE_SYS_STAT_H
25#include <sys/stat.h>
26#endif
27#include <dirent.h>
28#ifdef HAVE_ERRNO_H
29#include <errno.h>
30#endif
31#ifdef HAVE_SYS_MKDEV_H
32#include <sys/mkdev.h>
33#endif
34
35#include "ext2_fs.h"
36#include "ext2fs.h"
37
38struct dir_list {
39 char *name;
40 struct dir_list *next;
41};
42
43/*
44 * This function adds an entry to the directory list
45 */
46static void add_to_dirlist(const char *name, struct dir_list **list)
47{
48 struct dir_list *dp;
49
50 dp = xmalloc(sizeof(struct dir_list));
51 dp->name = xmalloc(strlen(name)+1);
52 strcpy(dp->name, name);
53 dp->next = *list;
54 *list = dp;
55}
56
57/*
58 * This function frees a directory list
59 */
60static void free_dirlist(struct dir_list **list)
61{
62 struct dir_list *dp, *next;
63
64 for (dp = *list; dp; dp = next) {
65 next = dp->next;
66 free(dp->name);
67 free(dp);
68 }
69 *list = 0;
70}
71
72static int scan_dir(char *dir_name, dev_t device, struct dir_list **list,
73 char **ret_path)
74{
75 DIR *dir;
76 struct dirent *dp;
77 char path[1024], *cp;
78 int dirlen;
79 struct stat st;
80
81 dirlen = strlen(dir_name);
82 if ((dir = opendir(dir_name)) == NULL)
83 return errno;
84 dp = readdir(dir);
85 while (dp) {
86 if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path))
87 goto skip_to_next;
88 if (dp->d_name[0] == '.' &&
89 ((dp->d_name[1] == 0) ||
90 ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
91 goto skip_to_next;
92 sprintf(path, "%s/%s", dir_name, dp->d_name);
93 if (stat(path, &st) < 0)
94 goto skip_to_next;
95 if (S_ISDIR(st.st_mode))
96 add_to_dirlist(path, list);
97 if (S_ISBLK(st.st_mode) && st.st_rdev == device) {
98 cp = xmalloc(strlen(path)+1);
99 strcpy(cp, path);
100 *ret_path = cp;
101 goto success;
102 }
103 skip_to_next:
104 dp = readdir(dir);
105 }
106success:
107 closedir(dir);
108 return 0;
109}
110
111/*
112 * This function finds the pathname to a block device with a given
113 * device number. It returns a pointer to allocated memory to the
114 * pathname on success, and NULL on failure.
115 */
116char *ext2fs_find_block_device(dev_t device)
117{
118 struct dir_list *list = 0, *new_list = 0;
119 struct dir_list *current;
120 char *ret_path = 0;
121
122 /*
123 * Add the starting directories to search...
124 */
125 add_to_dirlist("/devices", &list);
126 add_to_dirlist("/devfs", &list);
127 add_to_dirlist("/dev", &list);
128
129 while (list) {
130 current = list;
131 list = list->next;
132#ifdef DEBUG
133 printf("Scanning directory %s\n", current->name);
134#endif
135 scan_dir(current->name, device, &new_list, &ret_path);
136 free(current->name);
137 free(current);
138 if (ret_path)
139 break;
140 /*
141 * If we're done checking at this level, descend to
142 * the next level of subdirectories. (breadth-first)
143 */
144 if (list == 0) {
145 list = new_list;
146 new_list = 0;
147 }
148 }
149 free_dirlist(&list);
150 free_dirlist(&new_list);
151 return ret_path;
152}
153
154
155#ifdef DEBUG
156int main(int argc, char** argv)
157{
158 char *devname, *tmp;
159 int major, minor;
160 dev_t device;
161 const char *errmsg = "Cannot parse %s: %s\n";
162
163 if ((argc != 2) && (argc != 3)) {
164 fprintf(stderr, "Usage: %s device_number\n", argv[0]);
165 fprintf(stderr, "\t: %s major minor\n", argv[0]);
166 exit(1);
167 }
168 if (argc == 2) {
169 device = strtoul(argv[1], &tmp, 0);
170 if (*tmp) {
171 fprintf(stderr, errmsg, "device number", argv[1]);
172 exit(1);
173 }
174 } else {
175 major = strtoul(argv[1], &tmp, 0);
176 if (*tmp) {
177 fprintf(stderr, errmsg, "major number", argv[1]);
178 exit(1);
179 }
180 minor = strtoul(argv[2], &tmp, 0);
181 if (*tmp) {
182 fprintf(stderr, errmsg, "minor number", argv[2]);
183 exit(1);
184 }
185 device = makedev(major, minor);
186 printf("Looking for device 0x%04x (%d:%d)\n", device,
187 major, minor);
188 }
189 devname = ext2fs_find_block_device(device);
190 if (devname) {
191 printf("Found device! %s\n", devname);
192 free(devname);
193 } else {
194 printf("Cannot find device.\n");
195 }
196 return 0;
197}
198
199#endif
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c b/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c
new file mode 100644
index 000000000..e42982653
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c
@@ -0,0 +1,83 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * flushb.c --- Hides system-dependent information for both syncing a
4 * device to disk and to flush any buffers from disk cache.
5 *
6 * Copyright (C) 2000 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#if HAVE_ERRNO_H
16#include <errno.h>
17#endif
18#if HAVE_UNISTD_H
19#include <unistd.h>
20#endif
21#if HAVE_SYS_IOCTL_H
22#include <sys/ioctl.h>
23#endif
24#if HAVE_SYS_MOUNT_H
25#include <sys/param.h>
26#include <sys/mount.h> /* This may define BLKFLSBUF */
27#endif
28
29#include "ext2_fs.h"
30#include "ext2fs.h"
31
32/*
33 * For Linux, define BLKFLSBUF and FDFLUSH if necessary, since
34 * not all portable header file does so for us. This really should be
35 * fixed in the glibc header files. (Recent glibcs appear to define
36 * BLKFLSBUF in sys/mount.h, but FDFLUSH still doesn't seem to be
37 * defined anywhere portable.) Until then....
38 */
39#ifdef __linux__
40#ifndef BLKFLSBUF
41#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
42#endif
43#ifndef FDFLUSH
44#define FDFLUSH _IO(2,0x4b) /* flush floppy disk */
45#endif
46#endif
47
48/*
49 * This function will sync a device/file, and optionally attempt to
50 * flush the buffer cache. The latter is basically only useful for
51 * system benchmarks and for torturing systems in burn-in tests. :)
52 */
53errcode_t ext2fs_sync_device(int fd, int flushb)
54{
55 /*
56 * We always sync the device in case we're running on old
57 * kernels for which we can lose data if we don't. (There
58 * still is a race condition for those kernels, but this
59 * reduces it greatly.)
60 */
61 if (fsync (fd) == -1)
62 return errno;
63
64 if (flushb) {
65
66#ifdef BLKFLSBUF
67 if (ioctl (fd, BLKFLSBUF, 0) == 0)
68 return 0;
69#else
70#ifdef __GNUC__
71# warning BLKFLSBUF not defined
72#endif /* __GNUC__ */
73#endif
74#ifdef FDFLUSH
75 ioctl (fd, FDFLUSH, 0); /* In case this is a floppy */
76#else
77#ifdef __GNUC__
78# warning FDFLUSH not defined
79#endif /* __GNUC__ */
80#endif
81 }
82 return 0;
83}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c b/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c
new file mode 100644
index 000000000..65c4ee794
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c
@@ -0,0 +1,128 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * freefs.c --- free an ext2 filesystem
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fsP.h"
20
21static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
22
23void ext2fs_free(ext2_filsys fs)
24{
25 if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
26 return;
27 if (fs->image_io != fs->io) {
28 if (fs->image_io)
29 io_channel_close(fs->image_io);
30 }
31 if (fs->io) {
32 io_channel_close(fs->io);
33 }
34 ext2fs_free_mem(&fs->device_name);
35 ext2fs_free_mem(&fs->super);
36 ext2fs_free_mem(&fs->orig_super);
37 ext2fs_free_mem(&fs->group_desc);
38 ext2fs_free_block_bitmap(fs->block_map);
39 ext2fs_free_inode_bitmap(fs->inode_map);
40
41 ext2fs_badblocks_list_free(fs->badblocks);
42 fs->badblocks = 0;
43
44 ext2fs_free_dblist(fs->dblist);
45
46 if (fs->icache)
47 ext2fs_free_inode_cache(fs->icache);
48
49 fs->magic = 0;
50
51 ext2fs_free_mem(&fs);
52}
53
54void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
55{
56 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_GENERIC_BITMAP))
57 return;
58
59 bitmap->magic = 0;
60 ext2fs_free_mem(&bitmap->description);
61 ext2fs_free_mem(&bitmap->bitmap);
62 ext2fs_free_mem(&bitmap);
63}
64
65void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
66{
67 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
68 return;
69
70 bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
71 ext2fs_free_generic_bitmap(bitmap);
72}
73
74void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
75{
76 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
77 return;
78
79 bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
80 ext2fs_free_generic_bitmap(bitmap);
81}
82
83/*
84 * Free the inode cache structure
85 */
86static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
87{
88 if (--icache->refcount)
89 return;
90 ext2fs_free_mem(&icache->buffer);
91 ext2fs_free_mem(&icache->cache);
92 icache->buffer_blk = 0;
93 ext2fs_free_mem(&icache);
94}
95
96/*
97 * This procedure frees a badblocks list.
98 */
99void ext2fs_u32_list_free(ext2_u32_list bb)
100{
101 if (!bb || bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
102 return;
103
104 ext2fs_free_mem(&bb->list);
105 ext2fs_free_mem(&bb);
106}
107
108void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
109{
110 ext2fs_u32_list_free((ext2_u32_list) bb);
111}
112
113
114/*
115 * Free a directory block list
116 */
117void ext2fs_free_dblist(ext2_dblist dblist)
118{
119 if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST))
120 return;
121
122 ext2fs_free_mem(&dblist->list);
123 if (dblist->fs && dblist->fs->dblist == dblist)
124 dblist->fs->dblist = 0;
125 dblist->magic = 0;
126 ext2fs_free_mem(&dblist);
127}
128
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/gen_bitmap.c b/e2fsprogs/old_e2fsprogs/ext2fs/gen_bitmap.c
new file mode 100644
index 000000000..d0869c919
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/gen_bitmap.c
@@ -0,0 +1,49 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * gen_bitmap.c --- Generic bitmap routines that used to be inlined.
4 *
5 * Copyright (C) 2001 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13
14#include <stdio.h>
15#include <string.h>
16#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#include <fcntl.h>
20#include <time.h>
21#if HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#if HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27
28#include "ext2_fs.h"
29#include "ext2fs.h"
30
31int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
32 __u32 bitno)
33{
34 if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
35 ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
36 return 0;
37 }
38 return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
39}
40
41int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
42 blk_t bitno)
43{
44 if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
45 ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
46 return 0;
47 }
48 return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
49}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c b/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c
new file mode 100644
index 000000000..a98b2b9e5
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c
@@ -0,0 +1,157 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * get_pathname.c --- do directry/inode -> name translation
4 *
5 * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 *
12 * ext2fs_get_pathname(fs, dir, ino, name)
13 *
14 * This function translates takes two inode numbers into a
15 * string, placing the result in <name>. <dir> is the containing
16 * directory inode, and <ino> is the inode number itself. If
17 * <ino> is zero, then ext2fs_get_pathname will return pathname
18 * of the the directory <dir>.
19 *
20 */
21
22#include <stdio.h>
23#include <string.h>
24#if HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27
28#include "ext2_fs.h"
29#include "ext2fs.h"
30
31struct get_pathname_struct {
32 ext2_ino_t search_ino;
33 ext2_ino_t parent;
34 char *name;
35 errcode_t errcode;
36};
37
38#ifdef __TURBOC__
39# pragma argsused
40#endif
41static int get_pathname_proc(struct ext2_dir_entry *dirent,
42 int offset EXT2FS_ATTR((unused)),
43 int blocksize EXT2FS_ATTR((unused)),
44 char *buf EXT2FS_ATTR((unused)),
45 void *priv_data)
46{
47 struct get_pathname_struct *gp;
48 errcode_t retval;
49
50 gp = (struct get_pathname_struct *) priv_data;
51
52 if (((dirent->name_len & 0xFF) == 2) &&
53 !strncmp(dirent->name, "..", 2))
54 gp->parent = dirent->inode;
55 if (dirent->inode == gp->search_ino) {
56 retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1,
57 &gp->name);
58 if (retval) {
59 gp->errcode = retval;
60 return DIRENT_ABORT;
61 }
62 strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF));
63 gp->name[dirent->name_len & 0xFF] = '\0';
64 return DIRENT_ABORT;
65 }
66 return 0;
67}
68
69static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir,
70 ext2_ino_t ino, int maxdepth,
71 char *buf, char **name)
72{
73 struct get_pathname_struct gp;
74 char *parent_name, *ret;
75 errcode_t retval;
76
77 if (dir == ino) {
78 retval = ext2fs_get_mem(2, name);
79 if (retval)
80 return retval;
81 strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : ".");
82 return 0;
83 }
84
85 if (!dir || (maxdepth < 0)) {
86 retval = ext2fs_get_mem(4, name);
87 if (retval)
88 return retval;
89 strcpy(*name, "...");
90 return 0;
91 }
92
93 gp.search_ino = ino;
94 gp.parent = 0;
95 gp.name = 0;
96 gp.errcode = 0;
97
98 retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
99 if (retval)
100 goto cleanup;
101 if (gp.errcode) {
102 retval = gp.errcode;
103 goto cleanup;
104 }
105
106 retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1,
107 buf, &parent_name);
108 if (retval)
109 goto cleanup;
110 if (!ino) {
111 *name = parent_name;
112 return 0;
113 }
114
115 if (gp.name)
116 retval = ext2fs_get_mem(strlen(parent_name)+strlen(gp.name)+2,
117 &ret);
118 else
119 retval = ext2fs_get_mem(strlen(parent_name)+5, &ret);
120 if (retval)
121 goto cleanup;
122
123 ret[0] = 0;
124 if (parent_name[1])
125 strcat(ret, parent_name);
126 strcat(ret, "/");
127 if (gp.name)
128 strcat(ret, gp.name);
129 else
130 strcat(ret, "???");
131 *name = ret;
132 ext2fs_free_mem(&parent_name);
133 retval = 0;
134
135cleanup:
136 ext2fs_free_mem(&gp.name);
137 return retval;
138}
139
140errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
141 char **name)
142{
143 char *buf;
144 errcode_t retval;
145
146 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
147
148 retval = ext2fs_get_mem(fs->blocksize, &buf);
149 if (retval)
150 return retval;
151 if (dir == ino)
152 ino = 0;
153 retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name);
154 ext2fs_free_mem(&buf);
155 return retval;
156
157}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/getsectsize.c b/e2fsprogs/old_e2fsprogs/ext2fs/getsectsize.c
new file mode 100644
index 000000000..163ec65e5
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/getsectsize.c
@@ -0,0 +1,58 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * getsectsize.c --- get the sector size of a device.
4 *
5 * Copyright (C) 1995, 1995 Theodore Ts'o.
6 * Copyright (C) 2003 VMware, Inc.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#if HAVE_ERRNO_H
19#include <errno.h>
20#endif
21#include <fcntl.h>
22#ifdef HAVE_LINUX_FD_H
23#include <sys/ioctl.h>
24#include <linux/fd.h>
25#endif
26
27#if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET)
28#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
29#endif
30
31#include "ext2_fs.h"
32#include "ext2fs.h"
33
34/*
35 * Returns the number of blocks in a partition
36 */
37errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize)
38{
39 int fd;
40
41#ifdef CONFIG_LFS
42 fd = open64(file, O_RDONLY);
43#else
44 fd = open(file, O_RDONLY);
45#endif
46 if (fd < 0)
47 return errno;
48
49#ifdef BLKSSZGET
50 if (ioctl(fd, BLKSSZGET, sectsize) >= 0) {
51 close(fd);
52 return 0;
53 }
54#endif
55 *sectsize = 0;
56 close(fd);
57 return 0;
58}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c b/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c
new file mode 100644
index 000000000..516886c1f
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c
@@ -0,0 +1,291 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * getsize.c --- get the size of a partition.
4 *
5 * Copyright (C) 1995, 1995 Theodore Ts'o.
6 * Copyright (C) 2003 VMware, Inc.
7 *
8 * Windows version of ext2fs_get_device_size by Chris Li, VMware.
9 *
10 * %Begin-Header%
11 * This file may be redistributed under the terms of the GNU Public
12 * License.
13 * %End-Header%
14 */
15
16#include <stdio.h>
17#if HAVE_UNISTD_H
18#include <unistd.h>
19#endif
20#if HAVE_ERRNO_H
21#include <errno.h>
22#endif
23#include <fcntl.h>
24#ifdef HAVE_SYS_IOCTL_H
25#include <sys/ioctl.h>
26#endif
27#ifdef HAVE_LINUX_FD_H
28#include <linux/fd.h>
29#endif
30#ifdef HAVE_SYS_DISKLABEL_H
31#include <sys/disklabel.h>
32#endif
33#ifdef HAVE_SYS_DISK_H
34#ifdef HAVE_SYS_QUEUE_H
35#include <sys/queue.h> /* for LIST_HEAD */
36#endif
37#include <sys/disk.h>
38#endif
39#ifdef __linux__
40#include <sys/utsname.h>
41#endif
42
43#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
44#define BLKGETSIZE _IO(0x12,96) /* return device size */
45#endif
46
47#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
48#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
49#endif
50
51#ifdef APPLE_DARWIN
52#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
53#endif /* APPLE_DARWIN */
54
55#include "ext2_fs.h"
56#include "ext2fs.h"
57
58#if defined(__CYGWIN__) || defined (WIN32)
59#include <windows.h>
60#include <winioctl.h>
61
62#if (_WIN32_WINNT >= 0x0500)
63#define HAVE_GET_FILE_SIZE_EX 1
64#endif
65
66errcode_t ext2fs_get_device_size(const char *file, int blocksize,
67 blk_t *retblocks)
68{
69 HANDLE dev;
70 PARTITION_INFORMATION pi;
71 DISK_GEOMETRY gi;
72 DWORD retbytes;
73#ifdef HAVE_GET_FILE_SIZE_EX
74 LARGE_INTEGER filesize;
75#else
76 DWORD filesize;
77#endif /* HAVE_GET_FILE_SIZE_EX */
78
79 dev = CreateFile(file, GENERIC_READ,
80 FILE_SHARE_READ | FILE_SHARE_WRITE ,
81 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
82
83 if (dev == INVALID_HANDLE_VALUE)
84 return EBADF;
85 if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO,
86 &pi, sizeof(PARTITION_INFORMATION),
87 &pi, sizeof(PARTITION_INFORMATION),
88 &retbytes, NULL)) {
89
90 *retblocks = pi.PartitionLength.QuadPart / blocksize;
91
92 } else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY,
93 &gi, sizeof(DISK_GEOMETRY),
94 &gi, sizeof(DISK_GEOMETRY),
95 &retbytes, NULL)) {
96
97 *retblocks = gi.BytesPerSector *
98 gi.SectorsPerTrack *
99 gi.TracksPerCylinder *
100 gi.Cylinders.QuadPart / blocksize;
101
102#ifdef HAVE_GET_FILE_SIZE_EX
103 } else if (GetFileSizeEx(dev, &filesize)) {
104 *retblocks = filesize.QuadPart / blocksize;
105 }
106#else
107 } else {
108 filesize = GetFileSize(dev, NULL);
109 if (INVALID_FILE_SIZE != filesize) {
110 *retblocks = filesize / blocksize;
111 }
112 }
113#endif /* HAVE_GET_FILE_SIZE_EX */
114
115 CloseHandle(dev);
116 return 0;
117}
118
119#else
120
121static int valid_offset (int fd, ext2_loff_t offset)
122{
123 char ch;
124
125 if (ext2fs_llseek (fd, offset, 0) < 0)
126 return 0;
127 if (read (fd, &ch, 1) < 1)
128 return 0;
129 return 1;
130}
131
132/*
133 * Returns the number of blocks in a partition
134 */
135errcode_t ext2fs_get_device_size(const char *file, int blocksize,
136 blk_t *retblocks)
137{
138 int fd;
139 int valid_blkgetsize64 = 1;
140#ifdef __linux__
141 struct utsname ut;
142#endif
143 unsigned long long size64;
144 unsigned long size;
145 ext2_loff_t high, low;
146#ifdef FDGETPRM
147 struct floppy_struct this_floppy;
148#endif
149#ifdef HAVE_SYS_DISKLABEL_H
150 int part;
151 struct disklabel lab;
152 struct partition *pp;
153 char ch;
154#endif /* HAVE_SYS_DISKLABEL_H */
155
156#ifdef CONFIG_LFS
157 fd = open64(file, O_RDONLY);
158#else
159 fd = open(file, O_RDONLY);
160#endif
161 if (fd < 0)
162 return errno;
163
164#ifdef DKIOCGETBLOCKCOUNT /* For Apple Darwin */
165 if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
166 if ((sizeof(*retblocks) < sizeof(unsigned long long))
167 && ((size64 / (blocksize / 512)) > 0xFFFFFFFF))
168 return EFBIG;
169 close(fd);
170 *retblocks = size64 / (blocksize / 512);
171 return 0;
172 }
173#endif
174
175#ifdef BLKGETSIZE64
176#ifdef __linux__
177 if ((uname(&ut) == 0) &&
178 ((ut.release[0] == '2') && (ut.release[1] == '.') &&
179 (ut.release[2] < '6') && (ut.release[3] == '.')))
180 valid_blkgetsize64 = 0;
181#endif
182 if (valid_blkgetsize64 &&
183 ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
184 if ((sizeof(*retblocks) < sizeof(unsigned long long))
185 && ((size64 / blocksize) > 0xFFFFFFFF))
186 return EFBIG;
187 close(fd);
188 *retblocks = size64 / blocksize;
189 return 0;
190 }
191#endif
192
193#ifdef BLKGETSIZE
194 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
195 close(fd);
196 *retblocks = size / (blocksize / 512);
197 return 0;
198 }
199#endif
200
201#ifdef FDGETPRM
202 if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
203 close(fd);
204 *retblocks = this_floppy.size / (blocksize / 512);
205 return 0;
206 }
207#endif
208
209#ifdef HAVE_SYS_DISKLABEL_H
210#if defined(DIOCGMEDIASIZE)
211 {
212 off_t ms;
213 u_int bs;
214 if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
215 *retblocks = ms / blocksize;
216 return 0;
217 }
218 }
219#elif defined(DIOCGDINFO)
220 /* old disklabel interface */
221 part = strlen(file) - 1;
222 if (part >= 0) {
223 ch = file[part];
224 if (isdigit(ch))
225 part = 0;
226 else if (ch >= 'a' && ch <= 'h')
227 part = ch - 'a';
228 else
229 part = -1;
230 }
231 if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
232 pp = &lab.d_partitions[part];
233 if (pp->p_size) {
234 close(fd);
235 *retblocks = pp->p_size / (blocksize / 512);
236 return 0;
237 }
238 }
239#endif /* defined(DIOCG*) */
240#endif /* HAVE_SYS_DISKLABEL_H */
241
242 /*
243 * OK, we couldn't figure it out by using a specialized ioctl,
244 * which is generally the best way. So do binary search to
245 * find the size of the partition.
246 */
247 low = 0;
248 for (high = 1024; valid_offset (fd, high); high *= 2)
249 low = high;
250 while (low < high - 1)
251 {
252 const ext2_loff_t mid = (low + high) / 2;
253
254 if (valid_offset (fd, mid))
255 low = mid;
256 else
257 high = mid;
258 }
259 valid_offset (fd, 0);
260 close(fd);
261 size64 = low + 1;
262 if ((sizeof(*retblocks) < sizeof(unsigned long long))
263 && ((size64 / blocksize) > 0xFFFFFFFF))
264 return EFBIG;
265 *retblocks = size64 / blocksize;
266 return 0;
267}
268
269#endif /* WIN32 */
270
271#ifdef DEBUG
272int main(int argc, char **argv)
273{
274 blk_t blocks;
275 int retval;
276
277 if (argc < 2) {
278 fprintf(stderr, "Usage: %s device\n", argv[0]);
279 exit(1);
280 }
281
282 retval = ext2fs_get_device_size(argv[1], 1024, &blocks);
283 if (retval) {
284 com_err(argv[0], retval,
285 "while calling ext2fs_get_device_size");
286 exit(1);
287 }
288 printf("Device %s has %d 1k blocks.\n", argv[1], blocks);
289 exit(0);
290}
291#endif
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/icount.c b/e2fsprogs/old_e2fsprogs/ext2fs/icount.c
new file mode 100644
index 000000000..7ab5f51f4
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/icount.c
@@ -0,0 +1,467 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * icount.c --- an efficient inode count abstraction
4 *
5 * Copyright (C) 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#if HAVE_UNISTD_H
14#include <unistd.h>
15#endif
16#include <string.h>
17#include <stdio.h>
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22/*
23 * The data storage strategy used by icount relies on the observation
24 * that most inode counts are either zero (for non-allocated inodes),
25 * one (for most files), and only a few that are two or more
26 * (directories and files that are linked to more than one directory).
27 *
28 * Also, e2fsck tends to load the icount data sequentially.
29 *
30 * So, we use an inode bitmap to indicate which inodes have a count of
31 * one, and then use a sorted list to store the counts for inodes
32 * which are greater than one.
33 *
34 * We also use an optional bitmap to indicate which inodes are already
35 * in the sorted list, to speed up the use of this abstraction by
36 * e2fsck's pass 2. Pass 2 increments inode counts as it finds them,
37 * so this extra bitmap avoids searching the sorted list to see if a
38 * particular inode is on the sorted list already.
39 */
40
41struct ext2_icount_el {
42 ext2_ino_t ino;
43 __u16 count;
44};
45
46struct ext2_icount {
47 errcode_t magic;
48 ext2fs_inode_bitmap single;
49 ext2fs_inode_bitmap multiple;
50 ext2_ino_t count;
51 ext2_ino_t size;
52 ext2_ino_t num_inodes;
53 ext2_ino_t cursor;
54 struct ext2_icount_el *list;
55};
56
57void ext2fs_free_icount(ext2_icount_t icount)
58{
59 if (!icount)
60 return;
61
62 icount->magic = 0;
63 ext2fs_free_mem(&icount->list);
64 ext2fs_free_inode_bitmap(icount->single);
65 ext2fs_free_inode_bitmap(icount->multiple);
66 ext2fs_free_mem(&icount);
67}
68
69errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
70 ext2_icount_t hint, ext2_icount_t *ret)
71{
72 ext2_icount_t icount;
73 errcode_t retval;
74 size_t bytes;
75 ext2_ino_t i;
76
77 if (hint) {
78 EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT);
79 if (hint->size > size)
80 size = (size_t) hint->size;
81 }
82
83 retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount);
84 if (retval)
85 return retval;
86 memset(icount, 0, sizeof(struct ext2_icount));
87
88 retval = ext2fs_allocate_inode_bitmap(fs, 0,
89 &icount->single);
90 if (retval)
91 goto errout;
92
93 if (flags & EXT2_ICOUNT_OPT_INCREMENT) {
94 retval = ext2fs_allocate_inode_bitmap(fs, 0,
95 &icount->multiple);
96 if (retval)
97 goto errout;
98 } else
99 icount->multiple = 0;
100
101 if (size) {
102 icount->size = size;
103 } else {
104 /*
105 * Figure out how many special case inode counts we will
106 * have. We know we will need one for each directory;
107 * we also need to reserve some extra room for file links
108 */
109 retval = ext2fs_get_num_dirs(fs, &icount->size);
110 if (retval)
111 goto errout;
112 icount->size += fs->super->s_inodes_count / 50;
113 }
114
115 bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
116 retval = ext2fs_get_mem(bytes, &icount->list);
117 if (retval)
118 goto errout;
119 memset(icount->list, 0, bytes);
120
121 icount->magic = EXT2_ET_MAGIC_ICOUNT;
122 icount->count = 0;
123 icount->cursor = 0;
124 icount->num_inodes = fs->super->s_inodes_count;
125
126 /*
127 * Populate the sorted list with those entries which were
128 * found in the hint icount (since those are ones which will
129 * likely need to be in the sorted list this time around).
130 */
131 if (hint) {
132 for (i=0; i < hint->count; i++)
133 icount->list[i].ino = hint->list[i].ino;
134 icount->count = hint->count;
135 }
136
137 *ret = icount;
138 return 0;
139
140errout:
141 ext2fs_free_icount(icount);
142 return retval;
143}
144
145errcode_t ext2fs_create_icount(ext2_filsys fs, int flags,
146 unsigned int size,
147 ext2_icount_t *ret)
148{
149 return ext2fs_create_icount2(fs, flags, size, 0, ret);
150}
151
152/*
153 * insert_icount_el() --- Insert a new entry into the sorted list at a
154 * specified position.
155 */
156static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
157 ext2_ino_t ino, int pos)
158{
159 struct ext2_icount_el *el;
160 errcode_t retval;
161 ext2_ino_t new_size = 0;
162 int num;
163
164 if (icount->count >= icount->size) {
165 if (icount->count) {
166 new_size = icount->list[(unsigned)icount->count-1].ino;
167 new_size = (ext2_ino_t) (icount->count *
168 ((float) icount->num_inodes / new_size));
169 }
170 if (new_size < (icount->size + 100))
171 new_size = icount->size + 100;
172 retval = ext2fs_resize_mem((size_t) icount->size *
173 sizeof(struct ext2_icount_el),
174 (size_t) new_size *
175 sizeof(struct ext2_icount_el),
176 &icount->list);
177 if (retval)
178 return 0;
179 icount->size = new_size;
180 }
181 num = (int) icount->count - pos;
182 if (num < 0)
183 return 0; /* should never happen */
184 if (num) {
185 memmove(&icount->list[pos+1], &icount->list[pos],
186 sizeof(struct ext2_icount_el) * num);
187 }
188 icount->count++;
189 el = &icount->list[pos];
190 el->count = 0;
191 el->ino = ino;
192 return el;
193}
194
195/*
196 * get_icount_el() --- given an inode number, try to find icount
197 * information in the sorted list. If the create flag is set,
198 * and we can't find an entry, create one in the sorted list.
199 */
200static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
201 ext2_ino_t ino, int create)
202{
203 float range;
204 int low, high, mid;
205 ext2_ino_t lowval, highval;
206
207 if (!icount || !icount->list)
208 return 0;
209
210 if (create && ((icount->count == 0) ||
211 (ino > icount->list[(unsigned)icount->count-1].ino))) {
212 return insert_icount_el(icount, ino, (unsigned) icount->count);
213 }
214 if (icount->count == 0)
215 return 0;
216
217 if (icount->cursor >= icount->count)
218 icount->cursor = 0;
219 if (ino == icount->list[icount->cursor].ino)
220 return &icount->list[icount->cursor++];
221 low = 0;
222 high = (int) icount->count-1;
223 while (low <= high) {
224 if (low == high)
225 mid = low;
226 else {
227 /* Interpolate for efficiency */
228 lowval = icount->list[low].ino;
229 highval = icount->list[high].ino;
230
231 if (ino < lowval)
232 range = 0;
233 else if (ino > highval)
234 range = 1;
235 else
236 range = ((float) (ino - lowval)) /
237 (highval - lowval);
238 mid = low + ((int) (range * (high-low)));
239 }
240 if (ino == icount->list[mid].ino) {
241 icount->cursor = mid+1;
242 return &icount->list[mid];
243 }
244 if (ino < icount->list[mid].ino)
245 high = mid-1;
246 else
247 low = mid+1;
248 }
249 /*
250 * If we need to create a new entry, it should be right at
251 * low (where high will be left at low-1).
252 */
253 if (create)
254 return insert_icount_el(icount, ino, low);
255 return 0;
256}
257
258errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
259{
260 errcode_t ret = 0;
261 unsigned int i;
262 const char *bad = "bad icount";
263
264 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
265
266 if (icount->count > icount->size) {
267 fprintf(out, "%s: count > size\n", bad);
268 return EXT2_ET_INVALID_ARGUMENT;
269 }
270 for (i=1; i < icount->count; i++) {
271 if (icount->list[i-1].ino >= icount->list[i].ino) {
272 fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n",
273 bad, i-1, icount->list[i-1].ino,
274 i, icount->list[i].ino);
275 ret = EXT2_ET_INVALID_ARGUMENT;
276 }
277 }
278 return ret;
279}
280
281errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
282{
283 struct ext2_icount_el *el;
284
285 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
286
287 if (!ino || (ino > icount->num_inodes))
288 return EXT2_ET_INVALID_ARGUMENT;
289
290 if (ext2fs_test_inode_bitmap(icount->single, ino)) {
291 *ret = 1;
292 return 0;
293 }
294 if (icount->multiple &&
295 !ext2fs_test_inode_bitmap(icount->multiple, ino)) {
296 *ret = 0;
297 return 0;
298 }
299 el = get_icount_el(icount, ino, 0);
300 if (!el) {
301 *ret = 0;
302 return 0;
303 }
304 *ret = el->count;
305 return 0;
306}
307
308errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
309 __u16 *ret)
310{
311 struct ext2_icount_el *el;
312
313 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
314
315 if (!ino || (ino > icount->num_inodes))
316 return EXT2_ET_INVALID_ARGUMENT;
317
318 if (ext2fs_test_inode_bitmap(icount->single, ino)) {
319 /*
320 * If the existing count is 1, then we know there is
321 * no entry in the list.
322 */
323 el = get_icount_el(icount, ino, 1);
324 if (!el)
325 return EXT2_ET_NO_MEMORY;
326 ext2fs_unmark_inode_bitmap(icount->single, ino);
327 el->count = 2;
328 } else if (icount->multiple) {
329 /*
330 * The count is either zero or greater than 1; if the
331 * inode is set in icount->multiple, then there should
332 * be an entry in the list, so find it using
333 * get_icount_el().
334 */
335 if (ext2fs_test_inode_bitmap(icount->multiple, ino)) {
336 el = get_icount_el(icount, ino, 1);
337 if (!el)
338 return EXT2_ET_NO_MEMORY;
339 el->count++;
340 } else {
341 /*
342 * The count was zero; mark the single bitmap
343 * and return.
344 */
345 zero_count:
346 ext2fs_mark_inode_bitmap(icount->single, ino);
347 if (ret)
348 *ret = 1;
349 return 0;
350 }
351 } else {
352 /*
353 * The count is either zero or greater than 1; try to
354 * find an entry in the list to determine which.
355 */
356 el = get_icount_el(icount, ino, 0);
357 if (!el) {
358 /* No entry means the count was zero */
359 goto zero_count;
360 }
361 el = get_icount_el(icount, ino, 1);
362 if (!el)
363 return EXT2_ET_NO_MEMORY;
364 el->count++;
365 }
366 if (icount->multiple)
367 ext2fs_mark_inode_bitmap(icount->multiple, ino);
368 if (ret)
369 *ret = el->count;
370 return 0;
371}
372
373errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
374 __u16 *ret)
375{
376 struct ext2_icount_el *el;
377
378 if (!ino || (ino > icount->num_inodes))
379 return EXT2_ET_INVALID_ARGUMENT;
380
381 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
382
383 if (ext2fs_test_inode_bitmap(icount->single, ino)) {
384 ext2fs_unmark_inode_bitmap(icount->single, ino);
385 if (icount->multiple)
386 ext2fs_unmark_inode_bitmap(icount->multiple, ino);
387 else {
388 el = get_icount_el(icount, ino, 0);
389 if (el)
390 el->count = 0;
391 }
392 if (ret)
393 *ret = 0;
394 return 0;
395 }
396
397 if (icount->multiple &&
398 !ext2fs_test_inode_bitmap(icount->multiple, ino))
399 return EXT2_ET_INVALID_ARGUMENT;
400
401 el = get_icount_el(icount, ino, 0);
402 if (!el || el->count == 0)
403 return EXT2_ET_INVALID_ARGUMENT;
404
405 el->count--;
406 if (el->count == 1)
407 ext2fs_mark_inode_bitmap(icount->single, ino);
408 if ((el->count == 0) && icount->multiple)
409 ext2fs_unmark_inode_bitmap(icount->multiple, ino);
410
411 if (ret)
412 *ret = el->count;
413 return 0;
414}
415
416errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
417 __u16 count)
418{
419 struct ext2_icount_el *el;
420
421 if (!ino || (ino > icount->num_inodes))
422 return EXT2_ET_INVALID_ARGUMENT;
423
424 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
425
426 if (count == 1) {
427 ext2fs_mark_inode_bitmap(icount->single, ino);
428 if (icount->multiple)
429 ext2fs_unmark_inode_bitmap(icount->multiple, ino);
430 return 0;
431 }
432 if (count == 0) {
433 ext2fs_unmark_inode_bitmap(icount->single, ino);
434 if (icount->multiple) {
435 /*
436 * If the icount->multiple bitmap is enabled,
437 * we can just clear both bitmaps and we're done
438 */
439 ext2fs_unmark_inode_bitmap(icount->multiple, ino);
440 } else {
441 el = get_icount_el(icount, ino, 0);
442 if (el)
443 el->count = 0;
444 }
445 return 0;
446 }
447
448 /*
449 * Get the icount element
450 */
451 el = get_icount_el(icount, ino, 1);
452 if (!el)
453 return EXT2_ET_NO_MEMORY;
454 el->count = count;
455 ext2fs_unmark_inode_bitmap(icount->single, ino);
456 if (icount->multiple)
457 ext2fs_mark_inode_bitmap(icount->multiple, ino);
458 return 0;
459}
460
461ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount)
462{
463 if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT)
464 return 0;
465
466 return icount->size;
467}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/imager.c b/e2fsprogs/old_e2fsprogs/ext2fs/imager.c
new file mode 100644
index 000000000..e82321efa
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/imager.c
@@ -0,0 +1,377 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * image.c --- writes out the critical parts of the filesystem as a
4 * flat file.
5 *
6 * Copyright (C) 2000 Theodore Ts'o.
7 *
8 * Note: this uses the POSIX IO interfaces, unlike most of the other
9 * functions in this library. So sue me.
10 *
11 * %Begin-Header%
12 * This file may be redistributed under the terms of the GNU Public
13 * License.
14 * %End-Header%
15 */
16
17#include <stdio.h>
18#include <string.h>
19#if HAVE_UNISTD_H
20#include <unistd.h>
21#endif
22#if HAVE_ERRNO_H
23#include <errno.h>
24#endif
25#include <fcntl.h>
26#include <time.h>
27#if HAVE_SYS_STAT_H
28#include <sys/stat.h>
29#endif
30#if HAVE_SYS_TYPES_H
31#include <sys/types.h>
32#endif
33
34#include "ext2_fs.h"
35#include "ext2fs.h"
36
37#ifndef HAVE_TYPE_SSIZE_T
38typedef int ssize_t;
39#endif
40
41/*
42 * This function returns 1 if the specified block is all zeros
43 */
44static int check_zero_block(char *buf, int blocksize)
45{
46 char *cp = buf;
47 int left = blocksize;
48
49 while (left > 0) {
50 if (*cp++)
51 return 0;
52 left--;
53 }
54 return 1;
55}
56
57/*
58 * Write the inode table out as a single block.
59 */
60#define BUF_BLOCKS 32
61
62errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
63{
64 unsigned int group, left, c, d;
65 char *buf, *cp;
66 blk_t blk;
67 ssize_t actual;
68 errcode_t retval;
69
70 buf = xmalloc(fs->blocksize * BUF_BLOCKS);
71
72 for (group = 0; group < fs->group_desc_count; group++) {
73 blk = fs->group_desc[(unsigned)group].bg_inode_table;
74 if (!blk)
75 return EXT2_ET_MISSING_INODE_TABLE;
76 left = fs->inode_blocks_per_group;
77 while (left) {
78 c = BUF_BLOCKS;
79 if (c > left)
80 c = left;
81 retval = io_channel_read_blk(fs->io, blk, c, buf);
82 if (retval)
83 goto errout;
84 cp = buf;
85 while (c) {
86 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
87 d = c;
88 goto skip_sparse;
89 }
90 /* Skip zero blocks */
91 if (check_zero_block(cp, fs->blocksize)) {
92 c--;
93 blk++;
94 left--;
95 cp += fs->blocksize;
96 lseek(fd, fs->blocksize, SEEK_CUR);
97 continue;
98 }
99 /* Find non-zero blocks */
100 for (d=1; d < c; d++) {
101 if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
102 break;
103 }
104 skip_sparse:
105 actual = write(fd, cp, fs->blocksize * d);
106 if (actual == -1) {
107 retval = errno;
108 goto errout;
109 }
110 if (actual != (ssize_t) (fs->blocksize * d)) {
111 retval = EXT2_ET_SHORT_WRITE;
112 goto errout;
113 }
114 blk += d;
115 left -= d;
116 cp += fs->blocksize * d;
117 c -= d;
118 }
119 }
120 }
121 retval = 0;
122
123errout:
124 free(buf);
125 return retval;
126}
127
128/*
129 * Read in the inode table and stuff it into place
130 */
131errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
132 int flags EXT2FS_ATTR((unused)))
133{
134 unsigned int group, c, left;
135 char *buf;
136 blk_t blk;
137 ssize_t actual;
138 errcode_t retval;
139
140 buf = xmalloc(fs->blocksize * BUF_BLOCKS);
141
142 for (group = 0; group < fs->group_desc_count; group++) {
143 blk = fs->group_desc[(unsigned)group].bg_inode_table;
144 if (!blk) {
145 retval = EXT2_ET_MISSING_INODE_TABLE;
146 goto errout;
147 }
148 left = fs->inode_blocks_per_group;
149 while (left) {
150 c = BUF_BLOCKS;
151 if (c > left)
152 c = left;
153 actual = read(fd, buf, fs->blocksize * c);
154 if (actual == -1) {
155 retval = errno;
156 goto errout;
157 }
158 if (actual != (ssize_t) (fs->blocksize * c)) {
159 retval = EXT2_ET_SHORT_READ;
160 goto errout;
161 }
162 retval = io_channel_write_blk(fs->io, blk, c, buf);
163 if (retval)
164 goto errout;
165
166 blk += c;
167 left -= c;
168 }
169 }
170 retval = ext2fs_flush_icache(fs);
171
172errout:
173 free(buf);
174 return retval;
175}
176
177/*
178 * Write out superblock and group descriptors
179 */
180errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
181 int flags EXT2FS_ATTR((unused)))
182{
183 char *buf, *cp;
184 ssize_t actual;
185 errcode_t retval;
186
187 buf = xmalloc(fs->blocksize);
188
189 /*
190 * Write out the superblock
191 */
192 memset(buf, 0, fs->blocksize);
193 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
194 actual = write(fd, buf, fs->blocksize);
195 if (actual == -1) {
196 retval = errno;
197 goto errout;
198 }
199 if (actual != (ssize_t) fs->blocksize) {
200 retval = EXT2_ET_SHORT_WRITE;
201 goto errout;
202 }
203
204 /*
205 * Now write out the block group descriptors
206 */
207 cp = (char *) fs->group_desc;
208 actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
209 if (actual == -1) {
210 retval = errno;
211 goto errout;
212 }
213 if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
214 retval = EXT2_ET_SHORT_WRITE;
215 goto errout;
216 }
217
218 retval = 0;
219
220errout:
221 free(buf);
222 return retval;
223}
224
225/*
226 * Read the superblock and group descriptors and overwrite them.
227 */
228errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
229 int flags EXT2FS_ATTR((unused)))
230{
231 char *buf;
232 ssize_t actual, size;
233 errcode_t retval;
234
235 size = fs->blocksize * (fs->group_desc_count + 1);
236 buf = xmalloc(size);
237
238 /*
239 * Read it all in.
240 */
241 actual = read(fd, buf, size);
242 if (actual == -1) {
243 retval = errno;
244 goto errout;
245 }
246 if (actual != size) {
247 retval = EXT2_ET_SHORT_READ;
248 goto errout;
249 }
250
251 /*
252 * Now copy in the superblock and group descriptors
253 */
254 memcpy(fs->super, buf, SUPERBLOCK_SIZE);
255
256 memcpy(fs->group_desc, buf + fs->blocksize,
257 fs->blocksize * fs->group_desc_count);
258
259 retval = 0;
260
261errout:
262 free(buf);
263 return retval;
264}
265
266/*
267 * Write the block/inode bitmaps.
268 */
269errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
270{
271 char *ptr;
272 int c, size;
273 char zero_buf[1024];
274 ssize_t actual;
275 errcode_t retval;
276
277 if (flags & IMAGER_FLAG_INODEMAP) {
278 if (!fs->inode_map) {
279 retval = ext2fs_read_inode_bitmap(fs);
280 if (retval)
281 return retval;
282 }
283 ptr = fs->inode_map->bitmap;
284 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
285 } else {
286 if (!fs->block_map) {
287 retval = ext2fs_read_block_bitmap(fs);
288 if (retval)
289 return retval;
290 }
291 ptr = fs->block_map->bitmap;
292 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
293 }
294 size = size * fs->group_desc_count;
295
296 actual = write(fd, ptr, size);
297 if (actual == -1) {
298 retval = errno;
299 goto errout;
300 }
301 if (actual != size) {
302 retval = EXT2_ET_SHORT_WRITE;
303 goto errout;
304 }
305 size = size % fs->blocksize;
306 memset(zero_buf, 0, sizeof(zero_buf));
307 if (size) {
308 size = fs->blocksize - size;
309 while (size) {
310 c = size;
311 if (c > (int) sizeof(zero_buf))
312 c = sizeof(zero_buf);
313 actual = write(fd, zero_buf, c);
314 if (actual == -1) {
315 retval = errno;
316 goto errout;
317 }
318 if (actual != c) {
319 retval = EXT2_ET_SHORT_WRITE;
320 goto errout;
321 }
322 size -= c;
323 }
324 }
325 retval = 0;
326errout:
327 return retval;
328}
329
330
331/*
332 * Read the block/inode bitmaps.
333 */
334errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
335{
336 char *ptr, *buf = 0;
337 int size;
338 ssize_t actual;
339 errcode_t retval;
340
341 if (flags & IMAGER_FLAG_INODEMAP) {
342 if (!fs->inode_map) {
343 retval = ext2fs_read_inode_bitmap(fs);
344 if (retval)
345 return retval;
346 }
347 ptr = fs->inode_map->bitmap;
348 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
349 } else {
350 if (!fs->block_map) {
351 retval = ext2fs_read_block_bitmap(fs);
352 if (retval)
353 return retval;
354 }
355 ptr = fs->block_map->bitmap;
356 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
357 }
358 size = size * fs->group_desc_count;
359
360 buf = xmalloc(size);
361
362 actual = read(fd, buf, size);
363 if (actual == -1) {
364 retval = errno;
365 goto errout;
366 }
367 if (actual != size) {
368 retval = EXT2_ET_SHORT_WRITE;
369 goto errout;
370 }
371 memcpy(ptr, buf, size);
372
373 retval = 0;
374errout:
375 free(buf);
376 return retval;
377}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c b/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c
new file mode 100644
index 000000000..c86a1c59a
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c
@@ -0,0 +1,71 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ind_block.c --- indirect block I/O routines
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
6 * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19
20#include "ext2_fs.h"
21#include "ext2fs.h"
22
23errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf)
24{
25 errcode_t retval;
26#if BB_BIG_ENDIAN
27 blk_t *block_nr;
28 int i;
29 int limit = fs->blocksize >> 2;
30#endif
31
32 if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
33 (fs->io != fs->image_io))
34 memset(buf, 0, fs->blocksize);
35 else {
36 retval = io_channel_read_blk(fs->io, blk, 1, buf);
37 if (retval)
38 return retval;
39 }
40#if BB_BIG_ENDIAN
41 if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_READ)) {
42 block_nr = (blk_t *) buf;
43 for (i = 0; i < limit; i++, block_nr++)
44 *block_nr = ext2fs_swab32(*block_nr);
45 }
46#endif
47 return 0;
48}
49
50errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf)
51{
52#if BB_BIG_ENDIAN
53 blk_t *block_nr;
54 int i;
55 int limit = fs->blocksize >> 2;
56#endif
57
58 if (fs->flags & EXT2_FLAG_IMAGE_FILE)
59 return 0;
60
61#if BB_BIG_ENDIAN
62 if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_WRITE)) {
63 block_nr = (blk_t *) buf;
64 for (i = 0; i < limit; i++, block_nr++)
65 *block_nr = ext2fs_swab32(*block_nr);
66 }
67#endif
68 return io_channel_write_blk(fs->io, blk, 1, buf);
69}
70
71
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c b/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c
new file mode 100644
index 000000000..ef1d34379
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c
@@ -0,0 +1,388 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * initialize.c --- initialize a filesystem handle given superblock
4 * parameters. Used by mke2fs when initializing a filesystem.
5 *
6 * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#include <fcntl.h>
20#include <time.h>
21#if HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#if HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27
28#include "ext2_fs.h"
29#include "ext2fs.h"
30
31#if defined(__linux__) && defined(EXT2_OS_LINUX)
32#define CREATOR_OS EXT2_OS_LINUX
33#else
34#if defined(__GNU__) && defined(EXT2_OS_HURD)
35#define CREATOR_OS EXT2_OS_HURD
36#else
37#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD)
38#define CREATOR_OS EXT2_OS_FREEBSD
39#else
40#if defined(LITES) && defined(EXT2_OS_LITES)
41#define CREATOR_OS EXT2_OS_LITES
42#else
43#define CREATOR_OS EXT2_OS_LINUX /* by default */
44#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
45#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
46#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */
47#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */
48
49/*
50 * Note we override the kernel include file's idea of what the default
51 * check interval (never) should be. It's a good idea to check at
52 * least *occasionally*, specially since servers will never rarely get
53 * to reboot, since Linux is so robust these days. :-)
54 *
55 * 180 days (six months) seems like a good value.
56 */
57#ifdef EXT2_DFL_CHECKINTERVAL
58#undef EXT2_DFL_CHECKINTERVAL
59#endif
60#define EXT2_DFL_CHECKINTERVAL (86400L * 180L)
61
62/*
63 * Calculate the number of GDT blocks to reserve for online filesystem growth.
64 * The absolute maximum number of GDT blocks we can reserve is determined by
65 * the number of block pointers that can fit into a single block.
66 */
67static int calc_reserved_gdt_blocks(ext2_filsys fs)
68{
69 struct ext2_super_block *sb = fs->super;
70 unsigned long bpg = sb->s_blocks_per_group;
71 unsigned int gdpb = fs->blocksize / sizeof(struct ext2_group_desc);
72 unsigned long max_blocks = 0xffffffff;
73 unsigned long rsv_groups;
74 int rsv_gdb;
75
76 /* We set it at 1024x the current filesystem size, or
77 * the upper block count limit (2^32), whichever is lower.
78 */
79 if (sb->s_blocks_count < max_blocks / 1024)
80 max_blocks = sb->s_blocks_count * 1024;
81 rsv_groups = (max_blocks - sb->s_first_data_block + bpg - 1) / bpg;
82 rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - fs->desc_blocks;
83 if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
84 rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
85#ifdef RES_GDT_DEBUG
86 printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %lu\n",
87 max_blocks, rsv_groups, rsv_gdb);
88#endif
89
90 return rsv_gdb;
91}
92
93errcode_t ext2fs_initialize(const char *name, int flags,
94 struct ext2_super_block *param,
95 io_manager manager, ext2_filsys *ret_fs)
96{
97 ext2_filsys fs;
98 errcode_t retval;
99 struct ext2_super_block *super;
100 int frags_per_block;
101 unsigned int rem;
102 unsigned int overhead = 0;
103 blk_t group_block;
104 unsigned int ipg;
105 dgrp_t i;
106 blk_t numblocks;
107 int rsv_gdt;
108 char *buf;
109
110 if (!param || !param->s_blocks_count)
111 return EXT2_ET_INVALID_ARGUMENT;
112
113 retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
114 if (retval)
115 return retval;
116
117 memset(fs, 0, sizeof(struct struct_ext2_filsys));
118 fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
119 fs->flags = flags | EXT2_FLAG_RW;
120 fs->umask = 022;
121#ifdef WORDS_BIGENDIAN
122 fs->flags |= EXT2_FLAG_SWAP_BYTES;
123#endif
124 retval = manager->open(name, IO_FLAG_RW, &fs->io);
125 if (retval)
126 goto cleanup;
127 fs->image_io = fs->io;
128 fs->io->app_data = fs;
129 retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
130 if (retval)
131 goto cleanup;
132
133 strcpy(fs->device_name, name);
134 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
135 if (retval)
136 goto cleanup;
137 fs->super = super;
138
139 memset(super, 0, SUPERBLOCK_SIZE);
140
141#define set_field(field, default) (super->field = param->field ? \
142 param->field : (default))
143
144 super->s_magic = EXT2_SUPER_MAGIC;
145 super->s_state = EXT2_VALID_FS;
146
147 set_field(s_log_block_size, 0); /* default blocksize: 1024 bytes */
148 set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
149 set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
150 set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
151 set_field(s_errors, EXT2_ERRORS_DEFAULT);
152 set_field(s_feature_compat, 0);
153 set_field(s_feature_incompat, 0);
154 set_field(s_feature_ro_compat, 0);
155 set_field(s_first_meta_bg, 0);
156 if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
157 retval = EXT2_ET_UNSUPP_FEATURE;
158 goto cleanup;
159 }
160 if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
161 retval = EXT2_ET_RO_UNSUPP_FEATURE;
162 goto cleanup;
163 }
164
165 set_field(s_rev_level, EXT2_GOOD_OLD_REV);
166 if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
167 set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
168 set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
169 }
170
171 set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
172 super->s_mkfs_time = super->s_lastcheck = time(NULL);
173
174 super->s_creator_os = CREATOR_OS;
175
176 fs->blocksize = EXT2_BLOCK_SIZE(super);
177 fs->fragsize = EXT2_FRAG_SIZE(super);
178 frags_per_block = fs->blocksize / fs->fragsize;
179
180 /* default: (fs->blocksize*8) blocks/group, up to 2^16 (GDT limit) */
181 set_field(s_blocks_per_group, fs->blocksize * 8);
182 if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
183 super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
184 super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
185
186 super->s_blocks_count = param->s_blocks_count;
187 super->s_r_blocks_count = param->s_r_blocks_count;
188 if (super->s_r_blocks_count >= param->s_blocks_count) {
189 retval = EXT2_ET_INVALID_ARGUMENT;
190 goto cleanup;
191 }
192
193 /*
194 * If we're creating an external journal device, we don't need
195 * to bother with the rest.
196 */
197 if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
198 fs->group_desc_count = 0;
199 ext2fs_mark_super_dirty(fs);
200 *ret_fs = fs;
201 return 0;
202 }
203
204retry:
205 fs->group_desc_count = (super->s_blocks_count -
206 super->s_first_data_block +
207 EXT2_BLOCKS_PER_GROUP(super) - 1)
208 / EXT2_BLOCKS_PER_GROUP(super);
209 if (fs->group_desc_count == 0) {
210 retval = EXT2_ET_TOOSMALL;
211 goto cleanup;
212 }
213 fs->desc_blocks = (fs->group_desc_count +
214 EXT2_DESC_PER_BLOCK(super) - 1)
215 / EXT2_DESC_PER_BLOCK(super);
216
217 i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
218 set_field(s_inodes_count, super->s_blocks_count / i);
219
220 /*
221 * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
222 * that we have enough inodes for the filesystem(!)
223 */
224 if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
225 super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
226
227 /*
228 * There should be at least as many inodes as the user
229 * requested. Figure out how many inodes per group that
230 * should be. But make sure that we don't allocate more than
231 * one bitmap's worth of inodes each group.
232 */
233 ipg = (super->s_inodes_count + fs->group_desc_count - 1) /
234 fs->group_desc_count;
235 if (ipg > fs->blocksize * 8) {
236 if (super->s_blocks_per_group >= 256) {
237 /* Try again with slightly different parameters */
238 super->s_blocks_per_group -= 8;
239 super->s_blocks_count = param->s_blocks_count;
240 super->s_frags_per_group = super->s_blocks_per_group *
241 frags_per_block;
242 goto retry;
243 } else
244 return EXT2_ET_TOO_MANY_INODES;
245 }
246
247 if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
248 ipg = EXT2_MAX_INODES_PER_GROUP(super);
249
250 super->s_inodes_per_group = ipg;
251 if (super->s_inodes_count > ipg * fs->group_desc_count)
252 super->s_inodes_count = ipg * fs->group_desc_count;
253
254 /*
255 * Make sure the number of inodes per group completely fills
256 * the inode table blocks in the descriptor. If not, add some
257 * additional inodes/group. Waste not, want not...
258 */
259 fs->inode_blocks_per_group = (((super->s_inodes_per_group *
260 EXT2_INODE_SIZE(super)) +
261 EXT2_BLOCK_SIZE(super) - 1) /
262 EXT2_BLOCK_SIZE(super));
263 super->s_inodes_per_group = ((fs->inode_blocks_per_group *
264 EXT2_BLOCK_SIZE(super)) /
265 EXT2_INODE_SIZE(super));
266 /*
267 * Finally, make sure the number of inodes per group is a
268 * multiple of 8. This is needed to simplify the bitmap
269 * splicing code.
270 */
271 super->s_inodes_per_group &= ~7;
272 fs->inode_blocks_per_group = (((super->s_inodes_per_group *
273 EXT2_INODE_SIZE(super)) +
274 EXT2_BLOCK_SIZE(super) - 1) /
275 EXT2_BLOCK_SIZE(super));
276
277 /*
278 * adjust inode count to reflect the adjusted inodes_per_group
279 */
280 super->s_inodes_count = super->s_inodes_per_group *
281 fs->group_desc_count;
282 super->s_free_inodes_count = super->s_inodes_count;
283
284 /*
285 * check the number of reserved group descriptor table blocks
286 */
287 if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)
288 rsv_gdt = calc_reserved_gdt_blocks(fs);
289 else
290 rsv_gdt = 0;
291 set_field(s_reserved_gdt_blocks, rsv_gdt);
292 if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
293 retval = EXT2_ET_RES_GDT_BLOCKS;
294 goto cleanup;
295 }
296
297 /*
298 * Overhead is the number of bookkeeping blocks per group. It
299 * includes the superblock backup, the group descriptor
300 * backups, the inode bitmap, the block bitmap, and the inode
301 * table.
302 */
303
304 overhead = (int) (2 + fs->inode_blocks_per_group);
305
306 if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
307 overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
308
309 /* This can only happen if the user requested too many inodes */
310 if (overhead > super->s_blocks_per_group)
311 return EXT2_ET_TOO_MANY_INODES;
312
313 /*
314 * See if the last group is big enough to support the
315 * necessary data structures. If not, we need to get rid of
316 * it.
317 */
318 rem = ((super->s_blocks_count - super->s_first_data_block) %
319 super->s_blocks_per_group);
320 if ((fs->group_desc_count == 1) && rem && (rem < overhead))
321 return EXT2_ET_TOOSMALL;
322 if (rem && (rem < overhead+50)) {
323 super->s_blocks_count -= rem;
324 goto retry;
325 }
326
327 /*
328 * At this point we know how big the filesystem will be. So
329 * we can do any and all allocations that depend on the block
330 * count.
331 */
332
333 retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
334 if (retval)
335 goto cleanup;
336
337 sprintf(buf, "block bitmap for %s", fs->device_name);
338 retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
339 if (retval)
340 goto cleanup;
341
342 sprintf(buf, "inode bitmap for %s", fs->device_name);
343 retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
344 if (retval)
345 goto cleanup;
346
347 ext2fs_free_mem(&buf);
348
349 retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
350 &fs->group_desc);
351 if (retval)
352 goto cleanup;
353
354 memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);
355
356 /*
357 * Reserve the superblock and group descriptors for each
358 * group, and fill in the correct group statistics for group.
359 * Note that although the block bitmap, inode bitmap, and
360 * inode table have not been allocated (and in fact won't be
361 * by this routine), they are accounted for nevertheless.
362 */
363 group_block = super->s_first_data_block;
364 super->s_free_blocks_count = 0;
365 for (i = 0; i < fs->group_desc_count; i++) {
366 numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
367
368 super->s_free_blocks_count += numblocks;
369 fs->group_desc[i].bg_free_blocks_count = numblocks;
370 fs->group_desc[i].bg_free_inodes_count =
371 fs->super->s_inodes_per_group;
372 fs->group_desc[i].bg_used_dirs_count = 0;
373
374 group_block += super->s_blocks_per_group;
375 }
376
377 ext2fs_mark_super_dirty(fs);
378 ext2fs_mark_bb_dirty(fs);
379 ext2fs_mark_ib_dirty(fs);
380
381 io_channel_set_blksize(fs->io, fs->blocksize);
382
383 *ret_fs = fs;
384 return 0;
385cleanup:
386 ext2fs_free(fs);
387 return retval;
388}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/inline.c b/e2fsprogs/old_e2fsprogs/ext2fs/inline.c
new file mode 100644
index 000000000..9b620a772
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/inline.c
@@ -0,0 +1,33 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * inline.c --- Includes the inlined functions defined in the header
4 * files as standalone functions, in case the application program
5 * is compiled with inlining turned off.
6 *
7 * Copyright (C) 1993, 1994 Theodore Ts'o.
8 *
9 * %Begin-Header%
10 * This file may be redistributed under the terms of the GNU Public
11 * License.
12 * %End-Header%
13 */
14
15
16#include <stdio.h>
17#include <string.h>
18#if HAVE_UNISTD_H
19#include <unistd.h>
20#endif
21#include <fcntl.h>
22#include <time.h>
23#if HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#if HAVE_SYS_TYPES_H
27#include <sys/types.h>
28#endif
29
30#include "ext2_fs.h"
31#define INCLUDE_INLINE_FUNCS
32#include "ext2fs.h"
33
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/inode.c b/e2fsprogs/old_e2fsprogs/ext2fs/inode.c
new file mode 100644
index 000000000..2ff9fe6ca
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/inode.c
@@ -0,0 +1,768 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * inode.c --- utility routines to read and write inodes
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#if HAVE_ERRNO_H
19#include <errno.h>
20#endif
21#if HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#if HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27
28#include "ext2_fs.h"
29#include "ext2fsP.h"
30#include "e2image.h"
31
32struct ext2_struct_inode_scan {
33 errcode_t magic;
34 ext2_filsys fs;
35 ext2_ino_t current_inode;
36 blk_t current_block;
37 dgrp_t current_group;
38 ext2_ino_t inodes_left;
39 blk_t blocks_left;
40 dgrp_t groups_left;
41 blk_t inode_buffer_blocks;
42 char * inode_buffer;
43 int inode_size;
44 char * ptr;
45 int bytes_left;
46 char *temp_buffer;
47 errcode_t (*done_group)(ext2_filsys fs,
48 dgrp_t group,
49 void * priv_data);
50 void * done_group_data;
51 int bad_block_ptr;
52 int scan_flags;
53 int reserved[6];
54};
55
56/*
57 * This routine flushes the icache, if it exists.
58 */
59errcode_t ext2fs_flush_icache(ext2_filsys fs)
60{
61 int i;
62
63 if (!fs->icache)
64 return 0;
65
66 for (i=0; i < fs->icache->cache_size; i++)
67 fs->icache->cache[i].ino = 0;
68
69 fs->icache->buffer_blk = 0;
70 return 0;
71}
72
73static errcode_t create_icache(ext2_filsys fs)
74{
75 errcode_t retval;
76
77 if (fs->icache)
78 return 0;
79 retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache);
80 if (retval)
81 return retval;
82
83 memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
84 retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
85 if (retval) {
86 ext2fs_free_mem(&fs->icache);
87 return retval;
88 }
89 fs->icache->buffer_blk = 0;
90 fs->icache->cache_last = -1;
91 fs->icache->cache_size = 4;
92 fs->icache->refcount = 1;
93 retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent)
94 * fs->icache->cache_size,
95 &fs->icache->cache);
96 if (retval) {
97 ext2fs_free_mem(&fs->icache->buffer);
98 ext2fs_free_mem(&fs->icache);
99 return retval;
100 }
101 ext2fs_flush_icache(fs);
102 return 0;
103}
104
105errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
106 ext2_inode_scan *ret_scan)
107{
108 ext2_inode_scan scan;
109 errcode_t retval;
110 errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
111
112 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
113
114 /*
115 * If fs->badblocks isn't set, then set it --- since the inode
116 * scanning functions require it.
117 */
118 if (fs->badblocks == 0) {
119 /*
120 * Temporarly save fs->get_blocks and set it to zero,
121 * for compatibility with old e2fsck's.
122 */
123 save_get_blocks = fs->get_blocks;
124 fs->get_blocks = 0;
125 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
126 if (retval) {
127 ext2fs_badblocks_list_free(fs->badblocks);
128 fs->badblocks = 0;
129 }
130 fs->get_blocks = save_get_blocks;
131 }
132
133 retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan);
134 if (retval)
135 return retval;
136 memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
137
138 scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
139 scan->fs = fs;
140 scan->inode_size = EXT2_INODE_SIZE(fs->super);
141 scan->bytes_left = 0;
142 scan->current_group = 0;
143 scan->groups_left = fs->group_desc_count - 1;
144 scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
145 scan->current_block = scan->fs->
146 group_desc[scan->current_group].bg_inode_table;
147 scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
148 scan->blocks_left = scan->fs->inode_blocks_per_group;
149 retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks *
150 fs->blocksize),
151 &scan->inode_buffer);
152 scan->done_group = 0;
153 scan->done_group_data = 0;
154 scan->bad_block_ptr = 0;
155 if (retval) {
156 ext2fs_free_mem(&scan);
157 return retval;
158 }
159 retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer);
160 if (retval) {
161 ext2fs_free_mem(&scan->inode_buffer);
162 ext2fs_free_mem(&scan);
163 return retval;
164 }
165 if (scan->fs->badblocks && scan->fs->badblocks->num)
166 scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
167 *ret_scan = scan;
168 return 0;
169}
170
171void ext2fs_close_inode_scan(ext2_inode_scan scan)
172{
173 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
174 return;
175
176 ext2fs_free_mem(&scan->inode_buffer);
177 scan->inode_buffer = NULL;
178 ext2fs_free_mem(&scan->temp_buffer);
179 scan->temp_buffer = NULL;
180 ext2fs_free_mem(&scan);
181 return;
182}
183
184void ext2fs_set_inode_callback(ext2_inode_scan scan,
185 errcode_t (*done_group)(ext2_filsys fs,
186 dgrp_t group,
187 void * priv_data),
188 void *done_group_data)
189{
190 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
191 return;
192
193 scan->done_group = done_group;
194 scan->done_group_data = done_group_data;
195}
196
197int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
198 int clear_flags)
199{
200 int old_flags;
201
202 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
203 return 0;
204
205 old_flags = scan->scan_flags;
206 scan->scan_flags &= ~clear_flags;
207 scan->scan_flags |= set_flags;
208 return old_flags;
209}
210
211/*
212 * This function is called by ext2fs_get_next_inode when it needs to
213 * get ready to read in a new blockgroup.
214 */
215static errcode_t get_next_blockgroup(ext2_inode_scan scan)
216{
217 scan->current_group++;
218 scan->groups_left--;
219
220 scan->current_block = scan->fs->
221 group_desc[scan->current_group].bg_inode_table;
222
223 scan->current_inode = scan->current_group *
224 EXT2_INODES_PER_GROUP(scan->fs->super);
225
226 scan->bytes_left = 0;
227 scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
228 scan->blocks_left = scan->fs->inode_blocks_per_group;
229 return 0;
230}
231
232errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
233 int group)
234{
235 scan->current_group = group - 1;
236 scan->groups_left = scan->fs->group_desc_count - group;
237 return get_next_blockgroup(scan);
238}
239
240/*
241 * This function is called by get_next_blocks() to check for bad
242 * blocks in the inode table.
243 *
244 * This function assumes that badblocks_list->list is sorted in
245 * increasing order.
246 */
247static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
248 blk_t *num_blocks)
249{
250 blk_t blk = scan->current_block;
251 badblocks_list bb = scan->fs->badblocks;
252
253 /*
254 * If the inode table is missing, then obviously there are no
255 * bad blocks. :-)
256 */
257 if (blk == 0)
258 return 0;
259
260 /*
261 * If the current block is greater than the bad block listed
262 * in the bad block list, then advance the pointer until this
263 * is no longer the case. If we run out of bad blocks, then
264 * we don't need to do any more checking!
265 */
266 while (blk > bb->list[scan->bad_block_ptr]) {
267 if (++scan->bad_block_ptr >= bb->num) {
268 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
269 return 0;
270 }
271 }
272
273 /*
274 * If the current block is equal to the bad block listed in
275 * the bad block list, then handle that one block specially.
276 * (We could try to handle runs of bad blocks, but that
277 * only increases CPU efficiency by a small amount, at the
278 * expense of a huge expense of code complexity, and for an
279 * uncommon case at that.)
280 */
281 if (blk == bb->list[scan->bad_block_ptr]) {
282 scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
283 *num_blocks = 1;
284 if (++scan->bad_block_ptr >= bb->num)
285 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
286 return 0;
287 }
288
289 /*
290 * If there is a bad block in the range that we're about to
291 * read in, adjust the number of blocks to read so that we we
292 * don't read in the bad block. (Then the next block to read
293 * will be the bad block, which is handled in the above case.)
294 */
295 if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
296 *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
297
298 return 0;
299}
300
301/*
302 * This function is called by ext2fs_get_next_inode when it needs to
303 * read in more blocks from the current blockgroup's inode table.
304 */
305static errcode_t get_next_blocks(ext2_inode_scan scan)
306{
307 blk_t num_blocks;
308 errcode_t retval;
309
310 /*
311 * Figure out how many blocks to read; we read at most
312 * inode_buffer_blocks, and perhaps less if there aren't that
313 * many blocks left to read.
314 */
315 num_blocks = scan->inode_buffer_blocks;
316 if (num_blocks > scan->blocks_left)
317 num_blocks = scan->blocks_left;
318
319 /*
320 * If the past block "read" was a bad block, then mark the
321 * left-over extra bytes as also being bad.
322 */
323 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
324 if (scan->bytes_left)
325 scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
326 scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
327 }
328
329 /*
330 * Do inode bad block processing, if necessary.
331 */
332 if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
333 retval = check_for_inode_bad_blocks(scan, &num_blocks);
334 if (retval)
335 return retval;
336 }
337
338 if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
339 (scan->current_block == 0)) {
340 memset(scan->inode_buffer, 0,
341 (size_t) num_blocks * scan->fs->blocksize);
342 } else {
343 retval = io_channel_read_blk(scan->fs->io,
344 scan->current_block,
345 (int) num_blocks,
346 scan->inode_buffer);
347 if (retval)
348 return EXT2_ET_NEXT_INODE_READ;
349 }
350 scan->ptr = scan->inode_buffer;
351 scan->bytes_left = num_blocks * scan->fs->blocksize;
352
353 scan->blocks_left -= num_blocks;
354 if (scan->current_block)
355 scan->current_block += num_blocks;
356 return 0;
357}
358
359errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
360 struct ext2_inode *inode, int bufsize)
361{
362 errcode_t retval;
363 int extra_bytes = 0;
364
365 EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
366
367 /*
368 * Do we need to start reading a new block group?
369 */
370 if (scan->inodes_left <= 0) {
371 force_new_group:
372 if (scan->done_group) {
373 retval = (scan->done_group)
374 (scan->fs, scan->current_group,
375 scan->done_group_data);
376 if (retval)
377 return retval;
378 }
379 if (scan->groups_left <= 0) {
380 *ino = 0;
381 return 0;
382 }
383 retval = get_next_blockgroup(scan);
384 if (retval)
385 return retval;
386 }
387 /*
388 * This is done outside the above if statement so that the
389 * check can be done for block group #0.
390 */
391 if (scan->current_block == 0) {
392 if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
393 goto force_new_group;
394 } else
395 return EXT2_ET_MISSING_INODE_TABLE;
396 }
397
398
399 /*
400 * Have we run out of space in the inode buffer? If so, we
401 * need to read in more blocks.
402 */
403 if (scan->bytes_left < scan->inode_size) {
404 memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
405 extra_bytes = scan->bytes_left;
406
407 retval = get_next_blocks(scan);
408 if (retval)
409 return retval;
410#if 0
411 /*
412 * XXX test Need check for used inode somehow.
413 * (Note: this is hard.)
414 */
415 if (is_empty_scan(scan))
416 goto force_new_group;
417#endif
418 }
419
420 retval = 0;
421 if (extra_bytes) {
422 memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
423 scan->inode_size - extra_bytes);
424 scan->ptr += scan->inode_size - extra_bytes;
425 scan->bytes_left -= scan->inode_size - extra_bytes;
426
427#if BB_BIG_ENDIAN
428 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
429 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
430 ext2fs_swap_inode_full(scan->fs,
431 (struct ext2_inode_large *) inode,
432 (struct ext2_inode_large *) scan->temp_buffer,
433 0, bufsize);
434 else
435#endif
436 *inode = *((struct ext2_inode *) scan->temp_buffer);
437 if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
438 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
439 scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
440 } else {
441#if BB_BIG_ENDIAN
442 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
443 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
444 ext2fs_swap_inode_full(scan->fs,
445 (struct ext2_inode_large *) inode,
446 (struct ext2_inode_large *) scan->ptr,
447 0, bufsize);
448 else
449#endif
450 memcpy(inode, scan->ptr, bufsize);
451 scan->ptr += scan->inode_size;
452 scan->bytes_left -= scan->inode_size;
453 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
454 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
455 }
456
457 scan->inodes_left--;
458 scan->current_inode++;
459 *ino = scan->current_inode;
460 return retval;
461}
462
463errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
464 struct ext2_inode *inode)
465{
466 return ext2fs_get_next_inode_full(scan, ino, inode,
467 sizeof(struct ext2_inode));
468}
469
470/*
471 * Functions to read and write a single inode.
472 */
473errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
474 struct ext2_inode * inode, int bufsize)
475{
476 unsigned long group, block, block_nr, offset;
477 char *ptr;
478 errcode_t retval;
479 int clen, i, inodes_per_block, length;
480 io_channel io;
481
482 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
483
484 /* Check to see if user has an override function */
485 if (fs->read_inode) {
486 retval = (fs->read_inode)(fs, ino, inode);
487 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
488 return retval;
489 }
490 /* Create inode cache if not present */
491 if (!fs->icache) {
492 retval = create_icache(fs);
493 if (retval)
494 return retval;
495 }
496 /* Check to see if it's in the inode cache */
497 if (bufsize == sizeof(struct ext2_inode)) {
498 /* only old good inode can be retrieve from the cache */
499 for (i=0; i < fs->icache->cache_size; i++) {
500 if (fs->icache->cache[i].ino == ino) {
501 *inode = fs->icache->cache[i].inode;
502 return 0;
503 }
504 }
505 }
506 if ((ino == 0) || (ino > fs->super->s_inodes_count))
507 return EXT2_ET_BAD_INODE_NUM;
508 if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
509 inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
510 block_nr = fs->image_header->offset_inode / fs->blocksize;
511 block_nr += (ino - 1) / inodes_per_block;
512 offset = ((ino - 1) % inodes_per_block) *
513 EXT2_INODE_SIZE(fs->super);
514 io = fs->image_io;
515 } else {
516 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
517 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
518 EXT2_INODE_SIZE(fs->super);
519 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
520 if (!fs->group_desc[(unsigned)group].bg_inode_table)
521 return EXT2_ET_MISSING_INODE_TABLE;
522 block_nr = fs->group_desc[(unsigned)group].bg_inode_table +
523 block;
524 io = fs->io;
525 }
526 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
527
528 length = EXT2_INODE_SIZE(fs->super);
529 if (bufsize < length)
530 length = bufsize;
531
532 ptr = (char *) inode;
533 while (length) {
534 clen = length;
535 if ((offset + length) > fs->blocksize)
536 clen = fs->blocksize - offset;
537
538 if (block_nr != fs->icache->buffer_blk) {
539 retval = io_channel_read_blk(io, block_nr, 1,
540 fs->icache->buffer);
541 if (retval)
542 return retval;
543 fs->icache->buffer_blk = block_nr;
544 }
545
546 memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
547 clen);
548
549 offset = 0;
550 length -= clen;
551 ptr += clen;
552 block_nr++;
553 }
554
555#if BB_BIG_ENDIAN
556 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
557 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
558 ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode,
559 (struct ext2_inode_large *) inode,
560 0, length);
561#endif
562
563 /* Update the inode cache */
564 fs->icache->cache_last = (fs->icache->cache_last + 1) %
565 fs->icache->cache_size;
566 fs->icache->cache[fs->icache->cache_last].ino = ino;
567 fs->icache->cache[fs->icache->cache_last].inode = *inode;
568
569 return 0;
570}
571
572errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
573 struct ext2_inode * inode)
574{
575 return ext2fs_read_inode_full(fs, ino, inode,
576 sizeof(struct ext2_inode));
577}
578
579errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
580 struct ext2_inode * inode, int bufsize)
581{
582 unsigned long group, block, block_nr, offset;
583 errcode_t retval = 0;
584 struct ext2_inode_large temp_inode, *w_inode;
585 char *ptr;
586 int clen, i, length;
587
588 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
589
590 /* Check to see if user provided an override function */
591 if (fs->write_inode) {
592 retval = (fs->write_inode)(fs, ino, inode);
593 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
594 return retval;
595 }
596
597 /* Check to see if the inode cache needs to be updated */
598 if (fs->icache) {
599 for (i=0; i < fs->icache->cache_size; i++) {
600 if (fs->icache->cache[i].ino == ino) {
601 fs->icache->cache[i].inode = *inode;
602 break;
603 }
604 }
605 } else {
606 retval = create_icache(fs);
607 if (retval)
608 return retval;
609 }
610
611 if (!(fs->flags & EXT2_FLAG_RW))
612 return EXT2_ET_RO_FILSYS;
613
614 if ((ino == 0) || (ino > fs->super->s_inodes_count))
615 return EXT2_ET_BAD_INODE_NUM;
616
617 length = bufsize;
618 if (length < EXT2_INODE_SIZE(fs->super))
619 length = EXT2_INODE_SIZE(fs->super);
620
621 if (length > (int) sizeof(struct ext2_inode_large)) {
622 w_inode = xmalloc(length);
623 } else
624 w_inode = &temp_inode;
625 memset(w_inode, 0, length);
626
627#if BB_BIG_ENDIAN
628 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
629 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
630 ext2fs_swap_inode_full(fs, w_inode,
631 (struct ext2_inode_large *) inode,
632 1, bufsize);
633 else
634#endif
635 memcpy(w_inode, inode, bufsize);
636
637 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
638 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
639 EXT2_INODE_SIZE(fs->super);
640 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
641 if (!fs->group_desc[(unsigned) group].bg_inode_table)
642 return EXT2_ET_MISSING_INODE_TABLE;
643 block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
644
645 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
646
647 length = EXT2_INODE_SIZE(fs->super);
648 if (length > bufsize)
649 length = bufsize;
650
651 ptr = (char *) w_inode;
652
653 while (length) {
654 clen = length;
655 if ((offset + length) > fs->blocksize)
656 clen = fs->blocksize - offset;
657
658 if (fs->icache->buffer_blk != block_nr) {
659 retval = io_channel_read_blk(fs->io, block_nr, 1,
660 fs->icache->buffer);
661 if (retval)
662 goto errout;
663 fs->icache->buffer_blk = block_nr;
664 }
665
666
667 memcpy((char *) fs->icache->buffer + (unsigned) offset,
668 ptr, clen);
669
670 retval = io_channel_write_blk(fs->io, block_nr, 1,
671 fs->icache->buffer);
672 if (retval)
673 goto errout;
674
675 offset = 0;
676 ptr += clen;
677 length -= clen;
678 block_nr++;
679 }
680
681 fs->flags |= EXT2_FLAG_CHANGED;
682errout:
683 if (w_inode && w_inode != &temp_inode)
684 free(w_inode);
685 return retval;
686}
687
688errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
689 struct ext2_inode *inode)
690{
691 return ext2fs_write_inode_full(fs, ino, inode,
692 sizeof(struct ext2_inode));
693}
694
695/*
696 * This function should be called when writing a new inode. It makes
697 * sure that extra part of large inodes is initialized properly.
698 */
699errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
700 struct ext2_inode *inode)
701{
702 struct ext2_inode *buf;
703 int size = EXT2_INODE_SIZE(fs->super);
704 struct ext2_inode_large *large_inode;
705
706 if (size == sizeof(struct ext2_inode))
707 return ext2fs_write_inode_full(fs, ino, inode,
708 sizeof(struct ext2_inode));
709
710 buf = xmalloc(size);
711
712 memset(buf, 0, size);
713 *buf = *inode;
714
715 large_inode = (struct ext2_inode_large *) buf;
716 large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
717 EXT2_GOOD_OLD_INODE_SIZE;
718
719 return ext2fs_write_inode_full(fs, ino, buf, size);
720}
721
722
723errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
724{
725 struct ext2_inode inode;
726 int i;
727 errcode_t retval;
728
729 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
730
731 if (ino > fs->super->s_inodes_count)
732 return EXT2_ET_BAD_INODE_NUM;
733
734 if (fs->get_blocks) {
735 if (!(*fs->get_blocks)(fs, ino, blocks))
736 return 0;
737 }
738 retval = ext2fs_read_inode(fs, ino, &inode);
739 if (retval)
740 return retval;
741 for (i=0; i < EXT2_N_BLOCKS; i++)
742 blocks[i] = inode.i_block[i];
743 return 0;
744}
745
746errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
747{
748 struct ext2_inode inode;
749 errcode_t retval;
750
751 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
752
753 if (ino > fs->super->s_inodes_count)
754 return EXT2_ET_BAD_INODE_NUM;
755
756 if (fs->check_directory) {
757 retval = (fs->check_directory)(fs, ino);
758 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
759 return retval;
760 }
761 retval = ext2fs_read_inode(fs, ino, &inode);
762 if (retval)
763 return retval;
764 if (!LINUX_S_ISDIR(inode.i_mode))
765 return EXT2_ET_NO_DIRECTORY;
766 return 0;
767}
768
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c b/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c
new file mode 100644
index 000000000..4bfa93aef
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c
@@ -0,0 +1,271 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * inode_io.c --- This is allows an inode in an ext2 filesystem image
4 * to be accessed via the I/O manager interface.
5 *
6 * Copyright (C) 2002 Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#if HAVE_ERRNO_H
20#include <errno.h>
21#endif
22#include <time.h>
23
24#include "ext2_fs.h"
25#include "ext2fs.h"
26
27/*
28 * For checking structure magic numbers...
29 */
30
31#define EXT2_CHECK_MAGIC(struct, code) \
32 if ((struct)->magic != (code)) return (code)
33
34struct inode_private_data {
35 int magic;
36 char name[32];
37 ext2_file_t file;
38 ext2_filsys fs;
39 ext2_ino_t ino;
40 struct ext2_inode inode;
41 int flags;
42 struct inode_private_data *next;
43};
44
45#define CHANNEL_HAS_INODE 0x8000
46
47static struct inode_private_data *top_intern;
48static int ino_unique = 0;
49
50static errcode_t inode_open(const char *name, int flags, io_channel *channel);
51static errcode_t inode_close(io_channel channel);
52static errcode_t inode_set_blksize(io_channel channel, int blksize);
53static errcode_t inode_read_blk(io_channel channel, unsigned long block,
54 int count, void *data);
55static errcode_t inode_write_blk(io_channel channel, unsigned long block,
56 int count, const void *data);
57static errcode_t inode_flush(io_channel channel);
58static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
59 int size, const void *data);
60
61static struct struct_io_manager struct_inode_manager = {
62 EXT2_ET_MAGIC_IO_MANAGER,
63 "Inode I/O Manager",
64 inode_open,
65 inode_close,
66 inode_set_blksize,
67 inode_read_blk,
68 inode_write_blk,
69 inode_flush,
70 inode_write_byte
71};
72
73io_manager inode_io_manager = &struct_inode_manager;
74
75errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
76 struct ext2_inode *inode,
77 char **name)
78{
79 struct inode_private_data *data;
80 errcode_t retval;
81
82 if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
83 &data)))
84 return retval;
85 data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
86 sprintf(data->name, "%u:%d", ino, ino_unique++);
87 data->file = 0;
88 data->fs = fs;
89 data->ino = ino;
90 data->flags = 0;
91 if (inode) {
92 memcpy(&data->inode, inode, sizeof(struct ext2_inode));
93 data->flags |= CHANNEL_HAS_INODE;
94 }
95 data->next = top_intern;
96 top_intern = data;
97 *name = data->name;
98 return 0;
99}
100
101errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
102 char **name)
103{
104 return ext2fs_inode_io_intern2(fs, ino, NULL, name);
105}
106
107
108static errcode_t inode_open(const char *name, int flags, io_channel *channel)
109{
110 io_channel io = NULL;
111 struct inode_private_data *prev, *data = NULL;
112 errcode_t retval;
113 int open_flags;
114
115 if (name == 0)
116 return EXT2_ET_BAD_DEVICE_NAME;
117
118 for (data = top_intern, prev = NULL; data;
119 prev = data, data = data->next)
120 if (strcmp(name, data->name) == 0)
121 break;
122 if (!data)
123 return ENOENT;
124 if (prev)
125 prev->next = data->next;
126 else
127 top_intern = data->next;
128
129 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
130 if (retval)
131 goto cleanup;
132 memset(io, 0, sizeof(struct struct_io_channel));
133
134 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
135 io->manager = inode_io_manager;
136 retval = ext2fs_get_mem(strlen(name)+1, &io->name);
137 if (retval)
138 goto cleanup;
139
140 strcpy(io->name, name);
141 io->private_data = data;
142 io->block_size = 1024;
143 io->read_error = 0;
144 io->write_error = 0;
145 io->refcount = 1;
146
147 open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
148 retval = ext2fs_file_open2(data->fs, data->ino,
149 (data->flags & CHANNEL_HAS_INODE) ?
150 &data->inode : 0, open_flags,
151 &data->file);
152 if (retval)
153 goto cleanup;
154
155 *channel = io;
156 return 0;
157
158cleanup:
159 if (data) {
160 ext2fs_free_mem(&data);
161 }
162 if (io)
163 ext2fs_free_mem(&io);
164 return retval;
165}
166
167static errcode_t inode_close(io_channel channel)
168{
169 struct inode_private_data *data;
170 errcode_t retval = 0;
171
172 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
173 data = (struct inode_private_data *) channel->private_data;
174 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
175
176 if (--channel->refcount > 0)
177 return 0;
178
179 retval = ext2fs_file_close(data->file);
180
181 ext2fs_free_mem(&channel->private_data);
182 if (channel->name)
183 ext2fs_free_mem(&channel->name);
184 ext2fs_free_mem(&channel);
185 return retval;
186}
187
188static errcode_t inode_set_blksize(io_channel channel, int blksize)
189{
190 struct inode_private_data *data;
191
192 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
193 data = (struct inode_private_data *) channel->private_data;
194 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
195
196 channel->block_size = blksize;
197 return 0;
198}
199
200
201static errcode_t inode_read_blk(io_channel channel, unsigned long block,
202 int count, void *buf)
203{
204 struct inode_private_data *data;
205 errcode_t retval;
206
207 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
208 data = (struct inode_private_data *) channel->private_data;
209 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
210
211 if ((retval = ext2fs_file_lseek(data->file,
212 block * channel->block_size,
213 EXT2_SEEK_SET, 0)))
214 return retval;
215
216 count = (count < 0) ? -count : (count * channel->block_size);
217
218 return ext2fs_file_read(data->file, buf, count, 0);
219}
220
221static errcode_t inode_write_blk(io_channel channel, unsigned long block,
222 int count, const void *buf)
223{
224 struct inode_private_data *data;
225 errcode_t retval;
226
227 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
228 data = (struct inode_private_data *) channel->private_data;
229 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
230
231 if ((retval = ext2fs_file_lseek(data->file,
232 block * channel->block_size,
233 EXT2_SEEK_SET, 0)))
234 return retval;
235
236 count = (count < 0) ? -count : (count * channel->block_size);
237
238 return ext2fs_file_write(data->file, buf, count, 0);
239}
240
241static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
242 int size, const void *buf)
243{
244 struct inode_private_data *data;
245 errcode_t retval = 0;
246
247 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
248 data = (struct inode_private_data *) channel->private_data;
249 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
250
251 if ((retval = ext2fs_file_lseek(data->file, offset,
252 EXT2_SEEK_SET, 0)))
253 return retval;
254
255 return ext2fs_file_write(data->file, buf, size, 0);
256}
257
258/*
259 * Flush data buffers to disk.
260 */
261static errcode_t inode_flush(io_channel channel)
262{
263 struct inode_private_data *data;
264
265 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
266 data = (struct inode_private_data *) channel->private_data;
267 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
268
269 return ext2fs_file_flush(data->file);
270}
271
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/io_manager.c b/e2fsprogs/old_e2fsprogs/ext2fs/io_manager.c
new file mode 100644
index 000000000..b47038602
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/io_manager.c
@@ -0,0 +1,70 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * io_manager.c --- the I/O manager abstraction
4 */
5
6#include <stdio.h>
7#include <string.h>
8#if HAVE_UNISTD_H
9#include <unistd.h>
10#endif
11#include <fcntl.h>
12#include <time.h>
13#if HAVE_SYS_STAT_H
14#include <sys/stat.h>
15#endif
16#if HAVE_SYS_TYPES_H
17#include <sys/types.h>
18#endif
19
20#include "ext2_fs.h"
21#include "ext2fs.h"
22
23errcode_t io_channel_set_options(io_channel channel, const char *opts)
24{
25 errcode_t retval = 0;
26 char *next, *ptr, *options, *arg;
27
28 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
29
30 if (!opts)
31 return 0;
32
33 if (!channel->manager->set_option)
34 return EXT2_ET_INVALID_ARGUMENT;
35
36 options = malloc(strlen(opts)+1);
37 if (!options)
38 return EXT2_ET_NO_MEMORY;
39 strcpy(options, opts);
40 ptr = options;
41
42 while (ptr && *ptr) {
43 next = strchr(ptr, '&');
44 if (next)
45 *next++ = 0;
46
47 arg = strchr(ptr, '=');
48 if (arg)
49 *arg++ = 0;
50
51 retval = (channel->manager->set_option)(channel, ptr, arg);
52 if (retval)
53 break;
54 ptr = next;
55 }
56 free(options);
57 return retval;
58}
59
60errcode_t io_channel_write_byte(io_channel channel, unsigned long offset,
61 int count, const void *data)
62{
63 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
64
65 if (channel->manager->write_byte)
66 return channel->manager->write_byte(channel, offset,
67 count, data);
68
69 return EXT2_ET_UNIMPLEMENTED;
70}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/irel.h b/e2fsprogs/old_e2fsprogs/ext2fs/irel.h
new file mode 100644
index 000000000..91d1d89d5
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/irel.h
@@ -0,0 +1,115 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * irel.h
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13struct ext2_inode_reference {
14 blk_t block;
15 __u16 offset;
16};
17
18struct ext2_inode_relocate_entry {
19 ext2_ino_t new;
20 ext2_ino_t orig;
21 __u16 flags;
22 __u16 max_refs;
23};
24
25typedef struct ext2_inode_relocation_table *ext2_irel;
26
27struct ext2_inode_relocation_table {
28 __u32 magic;
29 char *name;
30 ext2_ino_t current;
31 void *priv_data;
32
33 /*
34 * Add an inode relocation entry.
35 */
36 errcode_t (*put)(ext2_irel irel, ext2_ino_t old,
37 struct ext2_inode_relocate_entry *ent);
38 /*
39 * Get an inode relocation entry.
40 */
41 errcode_t (*get)(ext2_irel irel, ext2_ino_t old,
42 struct ext2_inode_relocate_entry *ent);
43
44 /*
45 * Get an inode relocation entry by its original inode number
46 */
47 errcode_t (*get_by_orig)(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
48 struct ext2_inode_relocate_entry *ent);
49
50 /*
51 * Initialize for iterating over the inode relocation entries.
52 */
53 errcode_t (*start_iter)(ext2_irel irel);
54
55 /*
56 * The iterator function for the inode relocation entries.
57 * Returns an inode number of 0 when out of entries.
58 */
59 errcode_t (*next)(ext2_irel irel, ext2_ino_t *old,
60 struct ext2_inode_relocate_entry *ent);
61
62 /*
63 * Add an inode reference (i.e., note the fact that a
64 * particular block/offset contains a reference to an inode)
65 */
66 errcode_t (*add_ref)(ext2_irel irel, ext2_ino_t ino,
67 struct ext2_inode_reference *ref);
68
69 /*
70 * Initialize for iterating over the inode references for a
71 * particular inode.
72 */
73 errcode_t (*start_iter_ref)(ext2_irel irel, ext2_ino_t ino);
74
75 /*
76 * The iterator function for the inode references for an
77 * inode. The references for only one inode can be interator
78 * over at a time, as the iterator state is stored in ext2_irel.
79 */
80 errcode_t (*next_ref)(ext2_irel irel,
81 struct ext2_inode_reference *ref);
82
83 /*
84 * Move the inode relocation table from one inode number to
85 * another. Note that the inode references also must move.
86 */
87 errcode_t (*move)(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
88
89 /*
90 * Remove an inode relocation entry, along with all of the
91 * inode references.
92 */
93 errcode_t (*delete)(ext2_irel irel, ext2_ino_t old);
94
95 /*
96 * Free the inode relocation table.
97 */
98 errcode_t (*free)(ext2_irel irel);
99};
100
101errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
102 ext2_irel *irel);
103
104#define ext2fs_irel_put(irel, old, ent) ((irel)->put((irel), old, ent))
105#define ext2fs_irel_get(irel, old, ent) ((irel)->get((irel), old, ent))
106#define ext2fs_irel_get_by_orig(irel, orig, old, ent) \
107 ((irel)->get_by_orig((irel), orig, old, ent))
108#define ext2fs_irel_start_iter(irel) ((irel)->start_iter((irel)))
109#define ext2fs_irel_next(irel, old, ent) ((irel)->next((irel), old, ent))
110#define ext2fs_irel_add_ref(irel, ino, ref) ((irel)->add_ref((irel), ino, ref))
111#define ext2fs_irel_start_iter_ref(irel, ino) ((irel)->start_iter_ref((irel), ino))
112#define ext2fs_irel_next_ref(irel, ref) ((irel)->next_ref((irel), ref))
113#define ext2fs_irel_move(irel, old, new) ((irel)->move((irel), old, new))
114#define ext2fs_irel_delete(irel, old) ((irel)->delete((irel), old))
115#define ext2fs_irel_free(irel) ((irel)->free((irel)))
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/irel_ma.c b/e2fsprogs/old_e2fsprogs/ext2fs/irel_ma.c
new file mode 100644
index 000000000..c871b1891
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/irel_ma.c
@@ -0,0 +1,367 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * irel_ma.c
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <fcntl.h>
14#include <stdio.h>
15#include <string.h>
16#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#if HAVE_ERRNO_H
20#include <errno.h>
21#endif
22
23#include "ext2_fs.h"
24#include "ext2fs.h"
25#include "irel.h"
26
27static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
28 struct ext2_inode_relocate_entry *ent);
29static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
30 struct ext2_inode_relocate_entry *ent);
31static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
32 struct ext2_inode_relocate_entry *ent);
33static errcode_t ima_start_iter(ext2_irel irel);
34static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
35 struct ext2_inode_relocate_entry *ent);
36static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
37 struct ext2_inode_reference *ref);
38static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino);
39static errcode_t ima_next_ref(ext2_irel irel, struct ext2_inode_reference *ref);
40static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
41static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old);
42static errcode_t ima_free(ext2_irel irel);
43
44/*
45 * This data structure stores the array of inode references; there is
46 * a structure for each inode.
47 */
48struct inode_reference_entry {
49 __u16 num;
50 struct ext2_inode_reference *refs;
51};
52
53struct irel_ma {
54 __u32 magic;
55 ext2_ino_t max_inode;
56 ext2_ino_t ref_current;
57 int ref_iter;
58 ext2_ino_t *orig_map;
59 struct ext2_inode_relocate_entry *entries;
60 struct inode_reference_entry *ref_entries;
61};
62
63errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
64 ext2_irel *new_irel)
65{
66 ext2_irel irel = 0;
67 errcode_t retval;
68 struct irel_ma *ma = 0;
69 size_t size;
70
71 *new_irel = 0;
72
73 /*
74 * Allocate memory structures
75 */
76 retval = ext2fs_get_mem(sizeof(struct ext2_inode_relocation_table),
77 &irel);
78 if (retval)
79 goto errout;
80 memset(irel, 0, sizeof(struct ext2_inode_relocation_table));
81
82 retval = ext2fs_get_mem(strlen(name)+1, &irel->name);
83 if (retval)
84 goto errout;
85 strcpy(irel->name, name);
86
87 retval = ext2fs_get_mem(sizeof(struct irel_ma), &ma);
88 if (retval)
89 goto errout;
90 memset(ma, 0, sizeof(struct irel_ma));
91 irel->priv_data = ma;
92
93 size = (size_t) (sizeof(ext2_ino_t) * (max_inode+1));
94 retval = ext2fs_get_mem(size, &ma->orig_map);
95 if (retval)
96 goto errout;
97 memset(ma->orig_map, 0, size);
98
99 size = (size_t) (sizeof(struct ext2_inode_relocate_entry) *
100 (max_inode+1));
101 retval = ext2fs_get_mem(size, &ma->entries);
102 if (retval)
103 goto errout;
104 memset(ma->entries, 0, size);
105
106 size = (size_t) (sizeof(struct inode_reference_entry) *
107 (max_inode+1));
108 retval = ext2fs_get_mem(size, &ma->ref_entries);
109 if (retval)
110 goto errout;
111 memset(ma->ref_entries, 0, size);
112 ma->max_inode = max_inode;
113
114 /*
115 * Fill in the irel data structure
116 */
117 irel->put = ima_put;
118 irel->get = ima_get;
119 irel->get_by_orig = ima_get_by_orig;
120 irel->start_iter = ima_start_iter;
121 irel->next = ima_next;
122 irel->add_ref = ima_add_ref;
123 irel->start_iter_ref = ima_start_iter_ref;
124 irel->next_ref = ima_next_ref;
125 irel->move = ima_move;
126 irel->delete = ima_delete;
127 irel->free = ima_free;
128
129 *new_irel = irel;
130 return 0;
131
132errout:
133 ima_free(irel);
134 return retval;
135}
136
137static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
138 struct ext2_inode_relocate_entry *ent)
139{
140 struct inode_reference_entry *ref_ent;
141 struct irel_ma *ma;
142 errcode_t retval;
143 size_t size, old_size;
144
145 ma = irel->priv_data;
146 if (old > ma->max_inode)
147 return EXT2_ET_INVALID_ARGUMENT;
148
149 /*
150 * Force the orig field to the correct value; the application
151 * program shouldn't be messing with this field.
152 */
153 if (ma->entries[(unsigned) old].new == 0)
154 ent->orig = old;
155 else
156 ent->orig = ma->entries[(unsigned) old].orig;
157
158 /*
159 * If max_refs has changed, reallocate the refs array
160 */
161 ref_ent = ma->ref_entries + (unsigned) old;
162 if (ref_ent->refs && ent->max_refs !=
163 ma->entries[(unsigned) old].max_refs) {
164 size = (sizeof(struct ext2_inode_reference) * ent->max_refs);
165 old_size = (sizeof(struct ext2_inode_reference) *
166 ma->entries[(unsigned) old].max_refs);
167 retval = ext2fs_resize_mem(old_size, size, &ref_ent->refs);
168 if (retval)
169 return retval;
170 }
171
172 ma->entries[(unsigned) old] = *ent;
173 ma->orig_map[(unsigned) ent->orig] = old;
174 return 0;
175}
176
177static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
178 struct ext2_inode_relocate_entry *ent)
179{
180 struct irel_ma *ma;
181
182 ma = irel->priv_data;
183 if (old > ma->max_inode)
184 return EXT2_ET_INVALID_ARGUMENT;
185 if (ma->entries[(unsigned) old].new == 0)
186 return ENOENT;
187 *ent = ma->entries[(unsigned) old];
188 return 0;
189}
190
191static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
192 struct ext2_inode_relocate_entry *ent)
193{
194 struct irel_ma *ma;
195 ext2_ino_t ino;
196
197 ma = irel->priv_data;
198 if (orig > ma->max_inode)
199 return EXT2_ET_INVALID_ARGUMENT;
200 ino = ma->orig_map[(unsigned) orig];
201 if (ino == 0)
202 return ENOENT;
203 *old = ino;
204 *ent = ma->entries[(unsigned) ino];
205 return 0;
206}
207
208static errcode_t ima_start_iter(ext2_irel irel)
209{
210 irel->current = 0;
211 return 0;
212}
213
214static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
215 struct ext2_inode_relocate_entry *ent)
216{
217 struct irel_ma *ma;
218
219 ma = irel->priv_data;
220 while (++irel->current < ma->max_inode) {
221 if (ma->entries[(unsigned) irel->current].new == 0)
222 continue;
223 *old = irel->current;
224 *ent = ma->entries[(unsigned) irel->current];
225 return 0;
226 }
227 *old = 0;
228 return 0;
229}
230
231static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
232 struct ext2_inode_reference *ref)
233{
234 struct irel_ma *ma;
235 size_t size;
236 struct inode_reference_entry *ref_ent;
237 struct ext2_inode_relocate_entry *ent;
238 errcode_t retval;
239
240 ma = irel->priv_data;
241 if (ino > ma->max_inode)
242 return EXT2_ET_INVALID_ARGUMENT;
243
244 ref_ent = ma->ref_entries + (unsigned) ino;
245 ent = ma->entries + (unsigned) ino;
246
247 /*
248 * If the inode reference array doesn't exist, create it.
249 */
250 if (ref_ent->refs == 0) {
251 size = (size_t) ((sizeof(struct ext2_inode_reference) *
252 ent->max_refs));
253 retval = ext2fs_get_mem(size, &ref_ent->refs);
254 if (retval)
255 return retval;
256 memset(ref_ent->refs, 0, size);
257 ref_ent->num = 0;
258 }
259
260 if (ref_ent->num >= ent->max_refs)
261 return EXT2_ET_TOO_MANY_REFS;
262
263 ref_ent->refs[(unsigned) ref_ent->num++] = *ref;
264 return 0;
265}
266
267static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino)
268{
269 struct irel_ma *ma;
270
271 ma = irel->priv_data;
272 if (ino > ma->max_inode)
273 return EXT2_ET_INVALID_ARGUMENT;
274 if (ma->entries[(unsigned) ino].new == 0)
275 return ENOENT;
276 ma->ref_current = ino;
277 ma->ref_iter = 0;
278 return 0;
279}
280
281static errcode_t ima_next_ref(ext2_irel irel,
282 struct ext2_inode_reference *ref)
283{
284 struct irel_ma *ma;
285 struct inode_reference_entry *ref_ent;
286
287 ma = irel->priv_data;
288
289 ref_ent = ma->ref_entries + ma->ref_current;
290
291 if ((ref_ent->refs == NULL) ||
292 (ma->ref_iter >= ref_ent->num)) {
293 ref->block = 0;
294 ref->offset = 0;
295 return 0;
296 }
297 *ref = ref_ent->refs[ma->ref_iter++];
298 return 0;
299}
300
301
302static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new)
303{
304 struct irel_ma *ma;
305
306 ma = irel->priv_data;
307 if ((old > ma->max_inode) || (new > ma->max_inode))
308 return EXT2_ET_INVALID_ARGUMENT;
309 if (ma->entries[(unsigned) old].new == 0)
310 return ENOENT;
311
312 ma->entries[(unsigned) new] = ma->entries[(unsigned) old];
313 ext2fs_free_mem(&ma->ref_entries[(unsigned) new].refs);
314 ma->ref_entries[(unsigned) new] = ma->ref_entries[(unsigned) old];
315
316 ma->entries[(unsigned) old].new = 0;
317 ma->ref_entries[(unsigned) old].num = 0;
318 ma->ref_entries[(unsigned) old].refs = 0;
319
320 ma->orig_map[ma->entries[new].orig] = new;
321 return 0;
322}
323
324static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old)
325{
326 struct irel_ma *ma;
327
328 ma = irel->priv_data;
329 if (old > ma->max_inode)
330 return EXT2_ET_INVALID_ARGUMENT;
331 if (ma->entries[(unsigned) old].new == 0)
332 return ENOENT;
333
334 ma->entries[old].new = 0;
335 ext2fs_free_mem(&ma->ref_entries[(unsigned) old].refs);
336 ma->orig_map[ma->entries[(unsigned) old].orig] = 0;
337
338 ma->ref_entries[(unsigned) old].num = 0;
339 ma->ref_entries[(unsigned) old].refs = 0;
340 return 0;
341}
342
343static errcode_t ima_free(ext2_irel irel)
344{
345 struct irel_ma *ma;
346 ext2_ino_t ino;
347
348 if (!irel)
349 return 0;
350
351 ma = irel->priv_data;
352
353 if (ma) {
354 ext2fs_free_mem(&ma->orig_map);
355 ext2fs_free_mem(&ma->entries);
356 if (ma->ref_entries) {
357 for (ino = 0; ino <= ma->max_inode; ino++) {
358 ext2fs_free_mem(&ma->ref_entries[(unsigned) ino].refs);
359 }
360 ext2fs_free_mem(&ma->ref_entries);
361 }
362 ext2fs_free_mem(&ma);
363 }
364 ext2fs_free_mem(&irel->name);
365 ext2fs_free_mem(&irel);
366 return 0;
367}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c b/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c
new file mode 100644
index 000000000..d943f1185
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c
@@ -0,0 +1,357 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ismounted.c --- Check to see if the filesystem was mounted
4 *
5 * Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#if HAVE_ERRNO_H
18#include <errno.h>
19#endif
20#include <fcntl.h>
21#ifdef HAVE_LINUX_FD_H
22#include <linux/fd.h>
23#endif
24#ifdef HAVE_MNTENT_H
25#include <mntent.h>
26#endif
27#ifdef HAVE_GETMNTINFO
28#include <paths.h>
29#include <sys/param.h>
30#include <sys/mount.h>
31#endif /* HAVE_GETMNTINFO */
32#include <string.h>
33#include <sys/stat.h>
34
35#include "ext2_fs.h"
36#include "ext2fs.h"
37
38#ifdef HAVE_MNTENT_H
39/*
40 * Helper function which checks a file in /etc/mtab format to see if a
41 * filesystem is mounted. Returns an error if the file doesn't exist
42 * or can't be opened.
43 */
44static errcode_t check_mntent_file(const char *mtab_file, const char *file,
45 int *mount_flags, char *mtpt, int mtlen)
46{
47 struct mntent *mnt;
48 struct stat st_buf;
49 errcode_t retval = 0;
50 dev_t file_dev=0, file_rdev=0;
51 ino_t file_ino=0;
52 FILE *f;
53 int fd;
54
55 *mount_flags = 0;
56 if ((f = setmntent (mtab_file, "r")) == NULL)
57 return errno;
58 if (stat(file, &st_buf) == 0) {
59 if (S_ISBLK(st_buf.st_mode)) {
60#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
61 file_rdev = st_buf.st_rdev;
62#endif /* __GNU__ */
63 } else {
64 file_dev = st_buf.st_dev;
65 file_ino = st_buf.st_ino;
66 }
67 }
68 while ((mnt = getmntent (f)) != NULL) {
69 if (strcmp(file, mnt->mnt_fsname) == 0)
70 break;
71 if (stat(mnt->mnt_fsname, &st_buf) == 0) {
72 if (S_ISBLK(st_buf.st_mode)) {
73#ifndef __GNU__
74 if (file_rdev && (file_rdev == st_buf.st_rdev))
75 break;
76#endif /* __GNU__ */
77 } else {
78 if (file_dev && ((file_dev == st_buf.st_dev) &&
79 (file_ino == st_buf.st_ino)))
80 break;
81 }
82 }
83 }
84
85 if (mnt == 0) {
86#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
87 /*
88 * Do an extra check to see if this is the root device. We
89 * can't trust /etc/mtab, and /proc/mounts will only list
90 * /dev/root for the root filesystem. Argh. Instead we
91 * check if the given device has the same major/minor number
92 * as the device that the root directory is on.
93 */
94 if (file_rdev && stat("/", &st_buf) == 0) {
95 if (st_buf.st_dev == file_rdev) {
96 *mount_flags = EXT2_MF_MOUNTED;
97 if (mtpt)
98 strncpy(mtpt, "/", mtlen);
99 goto is_root;
100 }
101 }
102#endif /* __GNU__ */
103 goto errout;
104 }
105#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
106 /* Validate the entry in case /etc/mtab is out of date */
107 /*
108 * We need to be paranoid, because some broken distributions
109 * (read: Slackware) don't initialize /etc/mtab before checking
110 * all of the non-root filesystems on the disk.
111 */
112 if (stat(mnt->mnt_dir, &st_buf) < 0) {
113 retval = errno;
114 if (retval == ENOENT) {
115#ifdef DEBUG
116 printf("Bogus entry in %s! (%s does not exist)\n",
117 mtab_file, mnt->mnt_dir);
118#endif /* DEBUG */
119 retval = 0;
120 }
121 goto errout;
122 }
123 if (file_rdev && (st_buf.st_dev != file_rdev)) {
124#ifdef DEBUG
125 printf("Bogus entry in %s! (%s not mounted on %s)\n",
126 mtab_file, file, mnt->mnt_dir);
127#endif /* DEBUG */
128 goto errout;
129 }
130#endif /* __GNU__ */
131 *mount_flags = EXT2_MF_MOUNTED;
132
133#ifdef MNTOPT_RO
134 /* Check to see if the ro option is set */
135 if (hasmntopt(mnt, MNTOPT_RO))
136 *mount_flags |= EXT2_MF_READONLY;
137#endif
138
139 if (mtpt)
140 strncpy(mtpt, mnt->mnt_dir, mtlen);
141 /*
142 * Check to see if we're referring to the root filesystem.
143 * If so, do a manual check to see if we can open /etc/mtab
144 * read/write, since if the root is mounted read/only, the
145 * contents of /etc/mtab may not be accurate.
146 */
147 if (LONE_CHAR(mnt->mnt_dir, '/')) {
148is_root:
149#define TEST_FILE "/.ismount-test-file"
150 *mount_flags |= EXT2_MF_ISROOT;
151 fd = open(TEST_FILE, O_RDWR|O_CREAT);
152 if (fd < 0) {
153 if (errno == EROFS)
154 *mount_flags |= EXT2_MF_READONLY;
155 } else
156 close(fd);
157 (void) unlink(TEST_FILE);
158 }
159 retval = 0;
160errout:
161 endmntent (f);
162 return retval;
163}
164
165static errcode_t check_mntent(const char *file, int *mount_flags,
166 char *mtpt, int mtlen)
167{
168 errcode_t retval;
169
170#ifdef DEBUG
171 retval = check_mntent_file("/tmp/mtab", file, mount_flags,
172 mtpt, mtlen);
173 if (retval == 0)
174 return 0;
175#endif /* DEBUG */
176#ifdef __linux__
177 retval = check_mntent_file("/proc/mounts", file, mount_flags,
178 mtpt, mtlen);
179 if (retval == 0 && (*mount_flags != 0))
180 return 0;
181#endif /* __linux__ */
182#if defined(MOUNTED) || defined(_PATH_MOUNTED)
183#ifndef MOUNTED
184#define MOUNTED _PATH_MOUNTED
185#endif /* MOUNTED */
186 retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen);
187 return retval;
188#else
189 *mount_flags = 0;
190 return 0;
191#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
192}
193
194#else
195#if defined(HAVE_GETMNTINFO)
196
197static errcode_t check_getmntinfo(const char *file, int *mount_flags,
198 char *mtpt, int mtlen)
199{
200 struct statfs *mp;
201 int len, n;
202 const char *s1;
203 char *s2;
204
205 n = getmntinfo(&mp, MNT_NOWAIT);
206 if (n == 0)
207 return errno;
208
209 len = sizeof(_PATH_DEV) - 1;
210 s1 = file;
211 if (strncmp(_PATH_DEV, s1, len) == 0)
212 s1 += len;
213
214 *mount_flags = 0;
215 while (--n >= 0) {
216 s2 = mp->f_mntfromname;
217 if (strncmp(_PATH_DEV, s2, len) == 0) {
218 s2 += len - 1;
219 *s2 = 'r';
220 }
221 if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
222 *mount_flags = EXT2_MF_MOUNTED;
223 break;
224 }
225 ++mp;
226 }
227 if (mtpt)
228 strncpy(mtpt, mp->f_mntonname, mtlen);
229 return 0;
230}
231#endif /* HAVE_GETMNTINFO */
232#endif /* HAVE_MNTENT_H */
233
234/*
235 * Check to see if we're dealing with the swap device.
236 */
237static int is_swap_device(const char *file)
238{
239 FILE *f;
240 char buf[1024], *cp;
241 dev_t file_dev;
242 struct stat st_buf;
243 int ret = 0;
244
245 file_dev = 0;
246#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
247 if ((stat(file, &st_buf) == 0) &&
248 S_ISBLK(st_buf.st_mode))
249 file_dev = st_buf.st_rdev;
250#endif /* __GNU__ */
251
252 if (!(f = fopen("/proc/swaps", "r")))
253 return 0;
254 /* Skip the first line */
255 fgets(buf, sizeof(buf), f);
256 while (!feof(f)) {
257 if (!fgets(buf, sizeof(buf), f))
258 break;
259 if ((cp = strchr(buf, ' ')) != NULL)
260 *cp = 0;
261 if ((cp = strchr(buf, '\t')) != NULL)
262 *cp = 0;
263 if (strcmp(buf, file) == 0) {
264 ret++;
265 break;
266 }
267#ifndef __GNU__
268 if (file_dev && (stat(buf, &st_buf) == 0) &&
269 S_ISBLK(st_buf.st_mode) &&
270 file_dev == st_buf.st_rdev) {
271 ret++;
272 break;
273 }
274#endif /* __GNU__ */
275 }
276 fclose(f);
277 return ret;
278}
279
280
281/*
282 * ext2fs_check_mount_point() returns 1 if the device is mounted, 0
283 * otherwise. If mtpt is non-NULL, the directory where the device is
284 * mounted is copied to where mtpt is pointing, up to mtlen
285 * characters.
286 */
287#ifdef __TURBOC__
288# pragma argsused
289#endif
290errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
291 char *mtpt, int mtlen)
292{
293 if (is_swap_device(device)) {
294 *mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP;
295 strncpy(mtpt, "<swap>", mtlen);
296 return 0;
297 }
298#ifdef HAVE_MNTENT_H
299 return check_mntent(device, mount_flags, mtpt, mtlen);
300#else
301#ifdef HAVE_GETMNTINFO
302 return check_getmntinfo(device, mount_flags, mtpt, mtlen);
303#else
304#ifdef __GNUC__
305 #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
306#endif
307 *mount_flags = 0;
308 return 0;
309#endif /* HAVE_GETMNTINFO */
310#endif /* HAVE_MNTENT_H */
311}
312
313/*
314 * ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED,
315 * EXT2_MF_READONLY, and EXT2_MF_ROOT
316 *
317 */
318errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags)
319{
320 return ext2fs_check_mount_point(file, mount_flags, NULL, 0);
321}
322
323#ifdef DEBUG
324int main(int argc, char **argv)
325{
326 int retval, mount_flags;
327 char mntpt[80];
328
329 if (argc < 2) {
330 fprintf(stderr, "Usage: %s device\n", argv[0]);
331 exit(1);
332 }
333
334 mntpt[0] = 0;
335 retval = ext2fs_check_mount_point(argv[1], &mount_flags,
336 mntpt, sizeof(mntpt));
337 if (retval) {
338 com_err(argv[0], retval,
339 "while calling ext2fs_check_if_mounted");
340 exit(1);
341 }
342 printf("Device %s reports flags %02x\n", argv[1], mount_flags);
343 if (mount_flags & EXT2_MF_BUSY)
344 printf("\t%s is apparently in use.\n", argv[1]);
345 if (mount_flags & EXT2_MF_MOUNTED)
346 printf("\t%s is mounted.\n", argv[1]);
347 if (mount_flags & EXT2_MF_SWAP)
348 printf("\t%s is a swap device.\n", argv[1]);
349 if (mount_flags & EXT2_MF_READONLY)
350 printf("\t%s is read-only.\n", argv[1]);
351 if (mount_flags & EXT2_MF_ISROOT)
352 printf("\t%s is the root filesystem.\n", argv[1]);
353 if (mntpt[0])
354 printf("\t%s is mounted on %s.\n", argv[1], mntpt);
355 exit(0);
356}
357#endif /* DEBUG */
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h b/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h
new file mode 100644
index 000000000..136635de0
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h
@@ -0,0 +1,65 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * jfs_dat.h --- stripped down header file which only contains the JFS
4 * on-disk data structures
5 */
6
7#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
8
9/*
10 * On-disk structures
11 */
12
13/*
14 * Descriptor block types:
15 */
16
17#define JFS_DESCRIPTOR_BLOCK 1
18#define JFS_COMMIT_BLOCK 2
19#define JFS_SUPERBLOCK 3
20
21/*
22 * Standard header for all descriptor blocks:
23 */
24typedef struct journal_header_s
25{
26 __u32 h_magic;
27 __u32 h_blocktype;
28 __u32 h_sequence;
29} journal_header_t;
30
31
32/*
33 * The block tag: used to describe a single buffer in the journal
34 */
35typedef struct journal_block_tag_s
36{
37 __u32 t_blocknr; /* The on-disk block number */
38 __u32 t_flags; /* See below */
39} journal_block_tag_t;
40
41/* Definitions for the journal tag flags word: */
42#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */
43#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */
44#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */
45#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
46
47
48/*
49 * The journal superblock
50 */
51typedef struct journal_superblock_s
52{
53 journal_header_t s_header;
54
55 /* Static information describing the journal */
56 __u32 s_blocksize; /* journal device blocksize */
57 __u32 s_maxlen; /* total blocks in journal file */
58 __u32 s_first; /* first block of log information */
59
60 /* Dynamic information describing the current state of the log */
61 __u32 s_sequence; /* first commit ID expected in log */
62 __u32 s_start; /* blocknr of start of log */
63
64} journal_superblock_t;
65
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h b/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h
new file mode 100644
index 000000000..4c6c7dedd
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/kernel-jbd.h
@@ -0,0 +1,236 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * linux/include/linux/jbd.h
4 *
5 * Written by Stephen C. Tweedie <sct@redhat.com>
6 *
7 * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
8 *
9 * This file is part of the Linux kernel and is made available under
10 * the terms of the GNU General Public License, version 2, or at your
11 * option, any later version, incorporated herein by reference.
12 *
13 * Definitions for transaction data structures for the buffer cache
14 * filesystem journaling support.
15 */
16
17#ifndef _LINUX_JBD_H
18#define _LINUX_JBD_H
19
20#include <sys/types.h>
21#include <linux/types.h>
22#include "ext2fs.h"
23
24/*
25 * Standard header for all descriptor blocks:
26 */
27
28typedef struct journal_header_s
29{
30 __u32 h_magic;
31 __u32 h_blocktype;
32 __u32 h_sequence;
33} journal_header_t;
34
35/*
36 * This is the global e2fsck structure.
37 */
38typedef struct e2fsck_struct *e2fsck_t;
39
40
41struct inode {
42 e2fsck_t i_ctx;
43 ext2_ino_t i_ino;
44 struct ext2_inode i_ext2;
45};
46
47
48/*
49 * The journal superblock. All fields are in big-endian byte order.
50 */
51typedef struct journal_superblock_s
52{
53/* 0x0000 */
54 journal_header_t s_header;
55
56/* 0x000C */
57 /* Static information describing the journal */
58 __u32 s_blocksize; /* journal device blocksize */
59 __u32 s_maxlen; /* total blocks in journal file */
60 __u32 s_first; /* first block of log information */
61
62/* 0x0018 */
63 /* Dynamic information describing the current state of the log */
64 __u32 s_sequence; /* first commit ID expected in log */
65 __u32 s_start; /* blocknr of start of log */
66
67/* 0x0020 */
68 /* Error value, as set by journal_abort(). */
69 __s32 s_errno;
70
71/* 0x0024 */
72 /* Remaining fields are only valid in a version-2 superblock */
73 __u32 s_feature_compat; /* compatible feature set */
74 __u32 s_feature_incompat; /* incompatible feature set */
75 __u32 s_feature_ro_compat; /* readonly-compatible feature set */
76/* 0x0030 */
77 __u8 s_uuid[16]; /* 128-bit uuid for journal */
78
79/* 0x0040 */
80 __u32 s_nr_users; /* Nr of filesystems sharing log */
81
82 __u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/
83
84/* 0x0048 */
85 __u32 s_max_transaction; /* Limit of journal blocks per trans.*/
86 __u32 s_max_trans_data; /* Limit of data blocks per trans. */
87
88/* 0x0050 */
89 __u32 s_padding[44];
90
91/* 0x0100 */
92 __u8 s_users[16*48]; /* ids of all fs'es sharing the log */
93/* 0x0400 */
94} journal_superblock_t;
95
96
97extern int journal_blocks_per_page(struct inode *inode);
98extern int jbd_blocks_per_page(struct inode *inode);
99
100#define JFS_MIN_JOURNAL_BLOCKS 1024
101
102
103/*
104 * Internal structures used by the logging mechanism:
105 */
106
107#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
108
109/*
110 * Descriptor block types:
111 */
112
113#define JFS_DESCRIPTOR_BLOCK 1
114#define JFS_COMMIT_BLOCK 2
115#define JFS_SUPERBLOCK_V1 3
116#define JFS_SUPERBLOCK_V2 4
117#define JFS_REVOKE_BLOCK 5
118
119/*
120 * The block tag: used to describe a single buffer in the journal
121 */
122typedef struct journal_block_tag_s
123{
124 __u32 t_blocknr; /* The on-disk block number */
125 __u32 t_flags; /* See below */
126} journal_block_tag_t;
127
128/*
129 * The revoke descriptor: used on disk to describe a series of blocks to
130 * be revoked from the log
131 */
132typedef struct journal_revoke_header_s
133{
134 journal_header_t r_header;
135 int r_count; /* Count of bytes used in the block */
136} journal_revoke_header_t;
137
138
139/* Definitions for the journal tag flags word: */
140#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */
141#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */
142#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */
143#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
144
145
146
147
148#define JFS_HAS_COMPAT_FEATURE(j,mask) \
149 ((j)->j_format_version >= 2 && \
150 ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
151#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \
152 ((j)->j_format_version >= 2 && \
153 ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
154#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \
155 ((j)->j_format_version >= 2 && \
156 ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
157
158#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001
159
160/* Features known to this kernel version: */
161#define JFS_KNOWN_COMPAT_FEATURES 0
162#define JFS_KNOWN_ROCOMPAT_FEATURES 0
163#define JFS_KNOWN_INCOMPAT_FEATURES JFS_FEATURE_INCOMPAT_REVOKE
164
165/* Comparison functions for transaction IDs: perform comparisons using
166 * modulo arithmetic so that they work over sequence number wraps. */
167
168
169/*
170 * Definitions which augment the buffer_head layer
171 */
172
173/* journaling buffer types */
174#define BJ_None 0 /* Not journaled */
175#define BJ_SyncData 1 /* Normal data: flush before commit */
176#define BJ_AsyncData 2 /* writepage data: wait on it before commit */
177#define BJ_Metadata 3 /* Normal journaled metadata */
178#define BJ_Forget 4 /* Buffer superceded by this transaction */
179#define BJ_IO 5 /* Buffer is for temporary IO use */
180#define BJ_Shadow 6 /* Buffer contents being shadowed to the log */
181#define BJ_LogCtl 7 /* Buffer contains log descriptors */
182#define BJ_Reserved 8 /* Buffer is reserved for access by journal */
183#define BJ_Types 9
184
185
186struct kdev_s {
187 e2fsck_t k_ctx;
188 int k_dev;
189};
190
191typedef struct kdev_s *kdev_t;
192typedef unsigned int tid_t;
193
194struct journal_s
195{
196 unsigned long j_flags;
197 int j_errno;
198 struct buffer_head * j_sb_buffer;
199 struct journal_superblock_s *j_superblock;
200 int j_format_version;
201 unsigned long j_head;
202 unsigned long j_tail;
203 unsigned long j_free;
204 unsigned long j_first, j_last;
205 kdev_t j_dev;
206 kdev_t j_fs_dev;
207 int j_blocksize;
208 unsigned int j_blk_offset;
209 unsigned int j_maxlen;
210 struct inode * j_inode;
211 tid_t j_tail_sequence;
212 tid_t j_transaction_sequence;
213 __u8 j_uuid[16];
214 struct jbd_revoke_table_s *j_revoke;
215};
216
217typedef struct journal_s journal_t;
218
219extern int journal_recover (journal_t *journal);
220extern int journal_skip_recovery (journal_t *);
221
222/* Primary revoke support */
223extern int journal_init_revoke(journal_t *, int);
224extern void journal_destroy_revoke_caches(void);
225extern int journal_init_revoke_caches(void);
226
227/* Recovery revoke support */
228extern int journal_set_revoke(journal_t *, unsigned long, tid_t);
229extern int journal_test_revoke(journal_t *, unsigned long, tid_t);
230extern void journal_clear_revoke(journal_t *);
231extern void journal_brelse_array(struct buffer_head *b[], int n);
232
233extern void journal_destroy_revoke(journal_t *);
234
235
236#endif /* _LINUX_JBD_H */
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h b/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h
new file mode 100644
index 000000000..3392596ca
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/kernel-list.h
@@ -0,0 +1,113 @@
1/* vi: set sw=4 ts=4: */
2#ifndef _LINUX_LIST_H
3#define _LINUX_LIST_H
4
5/*
6 * Simple doubly linked list implementation.
7 *
8 * Some of the internal functions ("__xxx") are useful when
9 * manipulating whole lists rather than single entries, as
10 * sometimes we already know the next/prev entries and we can
11 * generate better code by using them directly rather than
12 * using the generic single-entry routines.
13 */
14
15struct list_head {
16 struct list_head *next, *prev;
17};
18
19#define LIST_HEAD_INIT(name) { &(name), &(name) }
20
21#define LIST_HEAD(name) \
22 struct list_head name = { &name, &name }
23
24#define INIT_LIST_HEAD(ptr) do { \
25 (ptr)->next = (ptr); (ptr)->prev = (ptr); \
26} while (0)
27
28#if (!defined(__GNUC__) && !defined(__WATCOMC__))
29#define __inline__
30#endif
31
32/*
33 * Insert a new entry between two known consecutive entries.
34 *
35 * This is only for internal list manipulation where we know
36 * the prev/next entries already!
37 */
38static __inline__ void __list_add(struct list_head * new,
39 struct list_head * prev,
40 struct list_head * next)
41{
42 next->prev = new;
43 new->next = next;
44 new->prev = prev;
45 prev->next = new;
46}
47
48/*
49 * Insert a new entry after the specified head..
50 */
51static __inline__ void list_add(struct list_head *new, struct list_head *head)
52{
53 __list_add(new, head, head->next);
54}
55
56/*
57 * Insert a new entry at the tail
58 */
59static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
60{
61 __list_add(new, head->prev, head);
62}
63
64/*
65 * Delete a list entry by making the prev/next entries
66 * point to each other.
67 *
68 * This is only for internal list manipulation where we know
69 * the prev/next entries already!
70 */
71static __inline__ void __list_del(struct list_head * prev,
72 struct list_head * next)
73{
74 next->prev = prev;
75 prev->next = next;
76}
77
78static __inline__ void list_del(struct list_head *entry)
79{
80 __list_del(entry->prev, entry->next);
81}
82
83static __inline__ int list_empty(struct list_head *head)
84{
85 return head->next == head;
86}
87
88/*
89 * Splice in "list" into "head"
90 */
91static __inline__ void list_splice(struct list_head *list, struct list_head *head)
92{
93 struct list_head *first = list->next;
94
95 if (first != list) {
96 struct list_head *last = list->prev;
97 struct list_head *at = head->next;
98
99 first->prev = head;
100 head->next = first;
101
102 last->next = at;
103 at->prev = last;
104 }
105}
106
107#define list_entry(ptr, type, member) \
108 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
109
110#define list_for_each(pos, head) \
111 for (pos = (head)->next; pos != (head); pos = pos->next)
112
113#endif
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/link.c b/e2fsprogs/old_e2fsprogs/ext2fs/link.c
new file mode 100644
index 000000000..08b2e9673
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/link.c
@@ -0,0 +1,135 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * link.c --- create links in a ext2fs directory
4 *
5 * Copyright (C) 1993, 1994 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22struct link_struct {
23 const char *name;
24 int namelen;
25 ext2_ino_t inode;
26 int flags;
27 int done;
28 struct ext2_super_block *sb;
29};
30
31static int link_proc(struct ext2_dir_entry *dirent,
32 int offset,
33 int blocksize,
34 char *buf,
35 void *priv_data)
36{
37 struct link_struct *ls = (struct link_struct *) priv_data;
38 struct ext2_dir_entry *next;
39 int rec_len, min_rec_len;
40 int ret = 0;
41
42 rec_len = EXT2_DIR_REC_LEN(ls->namelen);
43
44 /*
45 * See if the following directory entry (if any) is unused;
46 * if so, absorb it into this one.
47 */
48 next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len);
49 if ((offset + dirent->rec_len < blocksize - 8) &&
50 (next->inode == 0) &&
51 (offset + dirent->rec_len + next->rec_len <= blocksize)) {
52 dirent->rec_len += next->rec_len;
53 ret = DIRENT_CHANGED;
54 }
55
56 /*
57 * If the directory entry is used, see if we can split the
58 * directory entry to make room for the new name. If so,
59 * truncate it and return.
60 */
61 if (dirent->inode) {
62 min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
63 if (dirent->rec_len < (min_rec_len + rec_len))
64 return ret;
65 rec_len = dirent->rec_len - min_rec_len;
66 dirent->rec_len = min_rec_len;
67 next = (struct ext2_dir_entry *) (buf + offset +
68 dirent->rec_len);
69 next->inode = 0;
70 next->name_len = 0;
71 next->rec_len = rec_len;
72 return DIRENT_CHANGED;
73 }
74
75 /*
76 * If we get this far, then the directory entry is not used.
77 * See if we can fit the request entry in. If so, do it.
78 */
79 if (dirent->rec_len < rec_len)
80 return ret;
81 dirent->inode = ls->inode;
82 dirent->name_len = ls->namelen;
83 strncpy(dirent->name, ls->name, ls->namelen);
84 if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
85 dirent->name_len |= (ls->flags & 0x7) << 8;
86
87 ls->done++;
88 return DIRENT_ABORT|DIRENT_CHANGED;
89}
90
91/*
92 * Note: the low 3 bits of the flags field are used as the directory
93 * entry filetype.
94 */
95#ifdef __TURBOC__
96# pragma argsused
97#endif
98errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
99 ext2_ino_t ino, int flags)
100{
101 errcode_t retval;
102 struct link_struct ls;
103 struct ext2_inode inode;
104
105 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
106
107 if (!(fs->flags & EXT2_FLAG_RW))
108 return EXT2_ET_RO_FILSYS;
109
110 ls.name = name;
111 ls.namelen = name ? strlen(name) : 0;
112 ls.inode = ino;
113 ls.flags = flags;
114 ls.done = 0;
115 ls.sb = fs->super;
116
117 retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
118 0, link_proc, &ls);
119 if (retval)
120 return retval;
121
122 if (!ls.done)
123 return EXT2_ET_DIR_NO_SPACE;
124
125 if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
126 return retval;
127
128 if (inode.i_flags & EXT2_INDEX_FL) {
129 inode.i_flags &= ~EXT2_INDEX_FL;
130 if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)
131 return retval;
132 }
133
134 return 0;
135}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c b/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c
new file mode 100644
index 000000000..31b30a182
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c
@@ -0,0 +1,70 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * lookup.c --- ext2fs directory lookup operations
4 *
5 * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22struct lookup_struct {
23 const char *name;
24 int len;
25 ext2_ino_t *inode;
26 int found;
27};
28
29#ifdef __TURBOC__
30# pragma argsused
31#endif
32static int lookup_proc(struct ext2_dir_entry *dirent,
33 int offset EXT2FS_ATTR((unused)),
34 int blocksize EXT2FS_ATTR((unused)),
35 char *buf EXT2FS_ATTR((unused)),
36 void *priv_data)
37{
38 struct lookup_struct *ls = (struct lookup_struct *) priv_data;
39
40 if (ls->len != (dirent->name_len & 0xFF))
41 return 0;
42 if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF)))
43 return 0;
44 *ls->inode = dirent->inode;
45 ls->found++;
46 return DIRENT_ABORT;
47}
48
49
50errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
51 int namelen, char *buf, ext2_ino_t *inode)
52{
53 errcode_t retval;
54 struct lookup_struct ls;
55
56 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
57
58 ls.name = name;
59 ls.len = namelen;
60 ls.inode = inode;
61 ls.found = 0;
62
63 retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls);
64 if (retval)
65 return retval;
66
67 return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND;
68}
69
70
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c b/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c
new file mode 100644
index 000000000..b63c5d7a6
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c
@@ -0,0 +1,142 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mkdir.c --- make a directory in the filesystem
4 *
5 * Copyright (C) 1994, 1995 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29
30#ifndef EXT2_FT_DIR
31#define EXT2_FT_DIR 2
32#endif
33
34errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
35 const char *name)
36{
37 errcode_t retval;
38 struct ext2_inode parent_inode, inode;
39 ext2_ino_t ino = inum;
40 ext2_ino_t scratch_ino;
41 blk_t blk;
42 char *block = 0;
43
44 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
45
46 /*
47 * Allocate an inode, if necessary
48 */
49 if (!ino) {
50 retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755,
51 0, &ino);
52 if (retval)
53 goto cleanup;
54 }
55
56 /*
57 * Allocate a data block for the directory
58 */
59 retval = ext2fs_new_block(fs, 0, 0, &blk);
60 if (retval)
61 goto cleanup;
62
63 /*
64 * Create a scratch template for the directory
65 */
66 retval = ext2fs_new_dir_block(fs, ino, parent, &block);
67 if (retval)
68 goto cleanup;
69
70 /*
71 * Get the parent's inode, if necessary
72 */
73 if (parent != ino) {
74 retval = ext2fs_read_inode(fs, parent, &parent_inode);
75 if (retval)
76 goto cleanup;
77 } else
78 memset(&parent_inode, 0, sizeof(parent_inode));
79
80 /*
81 * Create the inode structure....
82 */
83 memset(&inode, 0, sizeof(struct ext2_inode));
84 inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
85 inode.i_uid = inode.i_gid = 0;
86 inode.i_blocks = fs->blocksize / 512;
87 inode.i_block[0] = blk;
88 inode.i_links_count = 2;
89 inode.i_ctime = inode.i_atime = inode.i_mtime = time(NULL);
90 inode.i_size = fs->blocksize;
91
92 /*
93 * Write out the inode and inode data block
94 */
95 retval = ext2fs_write_dir_block(fs, blk, block);
96 if (retval)
97 goto cleanup;
98 retval = ext2fs_write_new_inode(fs, ino, &inode);
99 if (retval)
100 goto cleanup;
101
102 /*
103 * Link the directory into the filesystem hierarchy
104 */
105 if (name) {
106 retval = ext2fs_lookup(fs, parent, name, strlen(name), 0,
107 &scratch_ino);
108 if (!retval) {
109 retval = EXT2_ET_DIR_EXISTS;
110 name = 0;
111 goto cleanup;
112 }
113 if (retval != EXT2_ET_FILE_NOT_FOUND)
114 goto cleanup;
115 retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR);
116 if (retval)
117 goto cleanup;
118 }
119
120 /*
121 * Update parent inode's counts
122 */
123 if (parent != ino) {
124 parent_inode.i_links_count++;
125 retval = ext2fs_write_inode(fs, parent, &parent_inode);
126 if (retval)
127 goto cleanup;
128 }
129
130 /*
131 * Update accounting....
132 */
133 ext2fs_block_alloc_stats(fs, blk, +1);
134 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
135
136cleanup:
137 ext2fs_free_mem(&block);
138 return retval;
139
140}
141
142
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c b/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c
new file mode 100644
index 000000000..5bdd34682
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c
@@ -0,0 +1,428 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mkjournal.c --- make a journal for a filesystem
4 *
5 * Copyright (C) 2000 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#if HAVE_ERRNO_H
19#include <errno.h>
20#endif
21#include <fcntl.h>
22#include <time.h>
23#if HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#if HAVE_SYS_TYPES_H
27#include <sys/types.h>
28#endif
29#if HAVE_SYS_IOCTL_H
30#include <sys/ioctl.h>
31#endif
32#if HAVE_NETINET_IN_H
33#include <netinet/in.h>
34#endif
35
36#include "ext2_fs.h"
37#include "../e2p/e2p.h"
38#include "../e2fsck.h"
39#include "ext2fs.h"
40#include "kernel-jbd.h"
41
42/*
43 * This function automatically sets up the journal superblock and
44 * returns it as an allocated block.
45 */
46errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
47 __u32 size, int flags,
48 char **ret_jsb)
49{
50 errcode_t retval;
51 journal_superblock_t *jsb;
52
53 if (size < 1024)
54 return EXT2_ET_JOURNAL_TOO_SMALL;
55
56 if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
57 return retval;
58
59 memset (jsb, 0, fs->blocksize);
60
61 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
62 if (flags & EXT2_MKJOURNAL_V1_SUPER)
63 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
64 else
65 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
66 jsb->s_blocksize = htonl(fs->blocksize);
67 jsb->s_maxlen = htonl(size);
68 jsb->s_nr_users = htonl(1);
69 jsb->s_first = htonl(1);
70 jsb->s_sequence = htonl(1);
71 memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
72 /*
73 * If we're creating an external journal device, we need to
74 * adjust these fields.
75 */
76 if (fs->super->s_feature_incompat &
77 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
78 jsb->s_nr_users = 0;
79 if (fs->blocksize == 1024)
80 jsb->s_first = htonl(3);
81 else
82 jsb->s_first = htonl(2);
83 }
84
85 *ret_jsb = (char *) jsb;
86 return 0;
87}
88
89/*
90 * This function writes a journal using POSIX routines. It is used
91 * for creating external journals and creating journals on live
92 * filesystems.
93 */
94static errcode_t write_journal_file(ext2_filsys fs, char *filename,
95 blk_t size, int flags)
96{
97 errcode_t retval;
98 char *buf = 0;
99 int fd, ret_size;
100 blk_t i;
101
102 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
103 return retval;
104
105 /* Open the device or journal file */
106 if ((fd = open(filename, O_WRONLY)) < 0) {
107 retval = errno;
108 goto errout;
109 }
110
111 /* Write the superblock out */
112 retval = EXT2_ET_SHORT_WRITE;
113 ret_size = write(fd, buf, fs->blocksize);
114 if (ret_size < 0) {
115 retval = errno;
116 goto errout;
117 }
118 if (ret_size != (int) fs->blocksize)
119 goto errout;
120 memset(buf, 0, fs->blocksize);
121
122 for (i = 1; i < size; i++) {
123 ret_size = write(fd, buf, fs->blocksize);
124 if (ret_size < 0) {
125 retval = errno;
126 goto errout;
127 }
128 if (ret_size != (int) fs->blocksize)
129 goto errout;
130 }
131 close(fd);
132
133 retval = 0;
134errout:
135 ext2fs_free_mem(&buf);
136 return retval;
137}
138
139/*
140 * Helper function for creating the journal using direct I/O routines
141 */
142struct mkjournal_struct {
143 int num_blocks;
144 int newblocks;
145 char *buf;
146 errcode_t err;
147};
148
149static int mkjournal_proc(ext2_filsys fs,
150 blk_t *blocknr,
151 e2_blkcnt_t blockcnt,
152 blk_t ref_block EXT2FS_ATTR((unused)),
153 int ref_offset EXT2FS_ATTR((unused)),
154 void *priv_data)
155{
156 struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
157 blk_t new_blk;
158 static blk_t last_blk = 0;
159 errcode_t retval;
160
161 if (*blocknr) {
162 last_blk = *blocknr;
163 return 0;
164 }
165 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
166 if (retval) {
167 es->err = retval;
168 return BLOCK_ABORT;
169 }
170 if (blockcnt > 0)
171 es->num_blocks--;
172
173 es->newblocks++;
174 retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
175
176 if (blockcnt == 0)
177 memset(es->buf, 0, fs->blocksize);
178
179 if (retval) {
180 es->err = retval;
181 return BLOCK_ABORT;
182 }
183 *blocknr = new_blk;
184 last_blk = new_blk;
185 ext2fs_block_alloc_stats(fs, new_blk, +1);
186
187 if (es->num_blocks == 0)
188 return (BLOCK_CHANGED | BLOCK_ABORT);
189 else
190 return BLOCK_CHANGED;
191
192}
193
194/*
195 * This function creates a journal using direct I/O routines.
196 */
197static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
198 blk_t size, int flags)
199{
200 char *buf;
201 errcode_t retval;
202 struct ext2_inode inode;
203 struct mkjournal_struct es;
204
205 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
206 return retval;
207
208 if ((retval = ext2fs_read_bitmaps(fs)))
209 return retval;
210
211 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
212 return retval;
213
214 if (inode.i_blocks > 0)
215 return EEXIST;
216
217 es.num_blocks = size;
218 es.newblocks = 0;
219 es.buf = buf;
220 es.err = 0;
221
222 retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
223 0, mkjournal_proc, &es);
224 if (es.err) {
225 retval = es.err;
226 goto errout;
227 }
228
229 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
230 goto errout;
231
232 inode.i_size += fs->blocksize * size;
233 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
234 inode.i_mtime = inode.i_ctime = time(0);
235 inode.i_links_count = 1;
236 inode.i_mode = LINUX_S_IFREG | 0600;
237
238 if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
239 goto errout;
240 retval = 0;
241
242 memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
243 fs->super->s_jnl_blocks[16] = inode.i_size;
244 fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
245 ext2fs_mark_super_dirty(fs);
246
247errout:
248 ext2fs_free_mem(&buf);
249 return retval;
250}
251
252/*
253 * This function adds a journal device to a filesystem
254 */
255errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
256{
257 struct stat st;
258 errcode_t retval;
259 char buf[1024];
260 journal_superblock_t *jsb;
261 int start;
262 __u32 i, nr_users;
263
264 /* Make sure the device exists and is a block device */
265 if (stat(journal_dev->device_name, &st) < 0)
266 return errno;
267
268 if (!S_ISBLK(st.st_mode))
269 return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
270
271 /* Get the journal superblock */
272 start = 1;
273 if (journal_dev->blocksize == 1024)
274 start++;
275 if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
276 return retval;
277
278 jsb = (journal_superblock_t *) buf;
279 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
280 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
281 return EXT2_ET_NO_JOURNAL_SB;
282
283 if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
284 return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
285
286 /* Check and see if this filesystem has already been added */
287 nr_users = ntohl(jsb->s_nr_users);
288 for (i=0; i < nr_users; i++) {
289 if (memcmp(fs->super->s_uuid,
290 &jsb->s_users[i*16], 16) == 0)
291 break;
292 }
293 if (i >= nr_users) {
294 memcpy(&jsb->s_users[nr_users*16],
295 fs->super->s_uuid, 16);
296 jsb->s_nr_users = htonl(nr_users+1);
297 }
298
299 /* Writeback the journal superblock */
300 if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
301 return retval;
302
303 fs->super->s_journal_inum = 0;
304 fs->super->s_journal_dev = st.st_rdev;
305 memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
306 sizeof(fs->super->s_journal_uuid));
307 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
308 ext2fs_mark_super_dirty(fs);
309 return 0;
310}
311
312/*
313 * This function adds a journal inode to a filesystem, using either
314 * POSIX routines if the filesystem is mounted, or using direct I/O
315 * functions if it is not.
316 */
317errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
318{
319 errcode_t retval;
320 ext2_ino_t journal_ino;
321 struct stat st;
322 char jfile[1024];
323 int fd, mount_flags, f;
324
325 retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
326 jfile, sizeof(jfile)-10);
327 if (retval)
328 return retval;
329
330 if (mount_flags & EXT2_MF_MOUNTED) {
331 strcat(jfile, "/.journal");
332
333 /*
334 * If .../.journal already exists, make sure any
335 * immutable or append-only flags are cleared.
336 */
337#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
338 (void) chflags (jfile, 0);
339#else
340#if HAVE_EXT2_IOCTLS
341 fd = open(jfile, O_RDONLY);
342 if (fd >= 0) {
343 f = 0;
344 ioctl(fd, EXT2_IOC_SETFLAGS, &f);
345 close(fd);
346 }
347#endif
348#endif
349
350 /* Create the journal file */
351 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
352 return errno;
353
354 if ((retval = write_journal_file(fs, jfile, size, flags)))
355 goto errout;
356
357 /* Get inode number of the journal file */
358 if (fstat(fd, &st) < 0)
359 goto errout;
360
361#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
362 retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
363#else
364#if HAVE_EXT2_IOCTLS
365 f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
366 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
367#endif
368#endif
369 if (retval)
370 goto errout;
371
372 close(fd);
373 journal_ino = st.st_ino;
374 } else {
375 journal_ino = EXT2_JOURNAL_INO;
376 if ((retval = write_journal_inode(fs, journal_ino,
377 size, flags)))
378 return retval;
379 }
380
381 fs->super->s_journal_inum = journal_ino;
382 fs->super->s_journal_dev = 0;
383 memset(fs->super->s_journal_uuid, 0,
384 sizeof(fs->super->s_journal_uuid));
385 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
386
387 ext2fs_mark_super_dirty(fs);
388 return 0;
389errout:
390 close(fd);
391 return retval;
392}
393
394#ifdef DEBUG
395main(int argc, char **argv)
396{
397 errcode_t retval;
398 char *device_name;
399 ext2_filsys fs;
400
401 if (argc < 2) {
402 fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
403 exit(1);
404 }
405 device_name = argv[1];
406
407 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
408 unix_io_manager, &fs);
409 if (retval) {
410 com_err(argv[0], retval, "while opening %s", device_name);
411 exit(1);
412 }
413
414 retval = ext2fs_add_journal_inode(fs, 1024);
415 if (retval) {
416 com_err(argv[0], retval, "while adding journal to %s",
417 device_name);
418 exit(1);
419 }
420 retval = ext2fs_flush(fs);
421 if (retval) {
422 printf("Warning, had trouble writing out superblocks.\n");
423 }
424 ext2fs_close(fs);
425 exit(0);
426
427}
428#endif
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/namei.c b/e2fsprogs/old_e2fsprogs/ext2fs/namei.c
new file mode 100644
index 000000000..988967009
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/namei.c
@@ -0,0 +1,205 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * namei.c --- ext2fs directory lookup operations
4 *
5 * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19/* #define NAMEI_DEBUG */
20
21#include "ext2_fs.h"
22#include "ext2fs.h"
23
24static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
25 const char *pathname, size_t pathlen, int follow,
26 int link_count, char *buf, ext2_ino_t *res_inode);
27
28static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
29 ext2_ino_t inode, int link_count,
30 char *buf, ext2_ino_t *res_inode)
31{
32 char *pathname;
33 char *buffer = 0;
34 errcode_t retval;
35 struct ext2_inode ei;
36
37#ifdef NAMEI_DEBUG
38 printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
39 root, dir, inode, link_count);
40
41#endif
42 retval = ext2fs_read_inode (fs, inode, &ei);
43 if (retval) return retval;
44 if (!LINUX_S_ISLNK (ei.i_mode)) {
45 *res_inode = inode;
46 return 0;
47 }
48 if (link_count++ > 5) {
49 return EXT2_ET_SYMLINK_LOOP;
50 }
51 if (ext2fs_inode_data_blocks(fs,&ei)) {
52 retval = ext2fs_get_mem(fs->blocksize, &buffer);
53 if (retval)
54 return retval;
55 retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
56 if (retval) {
57 ext2fs_free_mem(&buffer);
58 return retval;
59 }
60 pathname = buffer;
61 } else
62 pathname = (char *)&(ei.i_block[0]);
63 retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
64 link_count, buf, res_inode);
65 ext2fs_free_mem(&buffer);
66 return retval;
67}
68
69/*
70 * This routine interprets a pathname in the context of the current
71 * directory and the root directory, and returns the inode of the
72 * containing directory, and a pointer to the filename of the file
73 * (pointing into the pathname) and the length of the filename.
74 */
75static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
76 const char *pathname, int pathlen,
77 int link_count, char *buf,
78 const char **name, int *namelen,
79 ext2_ino_t *res_inode)
80{
81 char c;
82 const char *thisname;
83 int len;
84 ext2_ino_t inode;
85 errcode_t retval;
86
87 if ((c = *pathname) == '/') {
88 dir = root;
89 pathname++;
90 pathlen--;
91 }
92 while (1) {
93 thisname = pathname;
94 for (len=0; --pathlen >= 0;len++) {
95 c = *(pathname++);
96 if (c == '/')
97 break;
98 }
99 if (pathlen < 0)
100 break;
101 retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
102 if (retval) return retval;
103 retval = follow_link (fs, root, dir, inode,
104 link_count, buf, &dir);
105 if (retval) return retval;
106 }
107 *name = thisname;
108 *namelen = len;
109 *res_inode = dir;
110 return 0;
111}
112
113static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
114 const char *pathname, size_t pathlen, int follow,
115 int link_count, char *buf, ext2_ino_t *res_inode)
116{
117 const char *basename;
118 int namelen;
119 ext2_ino_t dir, inode;
120 errcode_t retval;
121
122#ifdef NAMEI_DEBUG
123 printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
124 root, base, pathlen, pathname, link_count);
125#endif
126 retval = dir_namei(fs, root, base, pathname, pathlen,
127 link_count, buf, &basename, &namelen, &dir);
128 if (retval) return retval;
129 if (!namelen) { /* special case: '/usr/' etc */
130 *res_inode=dir;
131 return 0;
132 }
133 retval = ext2fs_lookup (fs, dir, basename, namelen, buf, &inode);
134 if (retval)
135 return retval;
136 if (follow) {
137 retval = follow_link(fs, root, dir, inode, link_count,
138 buf, &inode);
139 if (retval)
140 return retval;
141 }
142#ifdef NAMEI_DEBUG
143 printf("open_namei: (link_count=%d) returns %lu\n",
144 link_count, inode);
145#endif
146 *res_inode = inode;
147 return 0;
148}
149
150errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
151 const char *name, ext2_ino_t *inode)
152{
153 char *buf;
154 errcode_t retval;
155
156 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
157
158 retval = ext2fs_get_mem(fs->blocksize, &buf);
159 if (retval)
160 return retval;
161
162 retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
163 buf, inode);
164
165 ext2fs_free_mem(&buf);
166 return retval;
167}
168
169errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
170 const char *name, ext2_ino_t *inode)
171{
172 char *buf;
173 errcode_t retval;
174
175 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
176
177 retval = ext2fs_get_mem(fs->blocksize, &buf);
178 if (retval)
179 return retval;
180
181 retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
182 buf, inode);
183
184 ext2fs_free_mem(&buf);
185 return retval;
186}
187
188errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
189 ext2_ino_t inode, ext2_ino_t *res_inode)
190{
191 char *buf;
192 errcode_t retval;
193
194 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
195
196 retval = ext2fs_get_mem(fs->blocksize, &buf);
197 if (retval)
198 return retval;
199
200 retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
201
202 ext2fs_free_mem(&buf);
203 return retval;
204}
205
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c b/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c
new file mode 100644
index 000000000..9470e7f56
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c
@@ -0,0 +1,73 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * newdir.c --- create a new directory block
4 *
5 * Copyright (C) 1994, 1995 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22#ifndef EXT2_FT_DIR
23#define EXT2_FT_DIR 2
24#endif
25
26/*
27 * Create new directory block
28 */
29errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
30 ext2_ino_t parent_ino, char **block)
31{
32 struct ext2_dir_entry *dir = NULL;
33 errcode_t retval;
34 char *buf;
35 int rec_len;
36 int filetype = 0;
37
38 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
39
40 retval = ext2fs_get_mem(fs->blocksize, &buf);
41 if (retval)
42 return retval;
43 memset(buf, 0, fs->blocksize);
44 dir = (struct ext2_dir_entry *) buf;
45 dir->rec_len = fs->blocksize;
46
47 if (dir_ino) {
48 if (fs->super->s_feature_incompat &
49 EXT2_FEATURE_INCOMPAT_FILETYPE)
50 filetype = EXT2_FT_DIR << 8;
51 /*
52 * Set up entry for '.'
53 */
54 dir->inode = dir_ino;
55 dir->name_len = 1 | filetype;
56 dir->name[0] = '.';
57 rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);
58 dir->rec_len = EXT2_DIR_REC_LEN(1);
59
60 /*
61 * Set up entry for '..'
62 */
63 dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
64 dir->rec_len = rec_len;
65 dir->inode = parent_ino;
66 dir->name_len = 2 | filetype;
67 dir->name[0] = '.';
68 dir->name[1] = '.';
69
70 }
71 *block = buf;
72 return 0;
73}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/openfs.c b/e2fsprogs/old_e2fsprogs/ext2fs/openfs.c
new file mode 100644
index 000000000..716be060f
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/openfs.c
@@ -0,0 +1,330 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * openfs.c --- open an ext2 filesystem
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28
29
30#include "ext2fs.h"
31#include "e2image.h"
32
33blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
34{
35 int bg;
36 int has_super = 0;
37 int ret_blk;
38
39 if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
40 (i < fs->super->s_first_meta_bg))
41 return (group_block + i + 1);
42
43 bg = (fs->blocksize / sizeof (struct ext2_group_desc)) * i;
44 if (ext2fs_bg_has_super(fs, bg))
45 has_super = 1;
46 ret_blk = (fs->super->s_first_data_block + has_super +
47 (bg * fs->super->s_blocks_per_group));
48 /*
49 * If group_block is not the normal value, we're trying to use
50 * the backup group descriptors and superblock --- so use the
51 * alternate location of the second block group in the
52 * metablock group. Ideally we should be testing each bg
53 * descriptor block individually for correctness, but we don't
54 * have the infrastructure in place to do that.
55 */
56 if (group_block != fs->super->s_first_data_block &&
57 ((ret_blk + fs->super->s_blocks_per_group) <
58 fs->super->s_blocks_count))
59 ret_blk += fs->super->s_blocks_per_group;
60 return ret_blk;
61}
62
63errcode_t ext2fs_open(const char *name, int flags, int superblock,
64 unsigned int block_size, io_manager manager,
65 ext2_filsys *ret_fs)
66{
67 return ext2fs_open2(name, 0, flags, superblock, block_size,
68 manager, ret_fs);
69}
70
71/*
72 * Note: if superblock is non-zero, block-size must also be non-zero.
73 * Superblock and block_size can be zero to use the default size.
74 *
75 * Valid flags for ext2fs_open()
76 *
77 * EXT2_FLAG_RW - Open the filesystem for read/write.
78 * EXT2_FLAG_FORCE - Open the filesystem even if some of the
79 * features aren't supported.
80 * EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
81 */
82errcode_t ext2fs_open2(const char *name, const char *io_options,
83 int flags, int superblock,
84 unsigned int block_size, io_manager manager,
85 ext2_filsys *ret_fs)
86{
87 ext2_filsys fs;
88 errcode_t retval;
89 unsigned long i;
90 int groups_per_block, blocks_per_group;
91 blk_t group_block, blk;
92 char *dest, *cp;
93#if BB_BIG_ENDIAN
94 int j;
95 struct ext2_group_desc *gdp;
96#endif
97
98 EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
99
100 retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
101 if (retval)
102 return retval;
103
104 memset(fs, 0, sizeof(struct struct_ext2_filsys));
105 fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
106 fs->flags = flags;
107 fs->umask = 022;
108 retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
109 if (retval)
110 goto cleanup;
111 strcpy(fs->device_name, name);
112 cp = strchr(fs->device_name, '?');
113 if (!io_options && cp) {
114 *cp++ = 0;
115 io_options = cp;
116 }
117
118 retval = manager->open(fs->device_name,
119 (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
120 &fs->io);
121 if (retval)
122 goto cleanup;
123 if (io_options &&
124 (retval = io_channel_set_options(fs->io, io_options)))
125 goto cleanup;
126 fs->image_io = fs->io;
127 fs->io->app_data = fs;
128 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
129 if (retval)
130 goto cleanup;
131 if (flags & EXT2_FLAG_IMAGE_FILE) {
132 retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
133 &fs->image_header);
134 if (retval)
135 goto cleanup;
136 retval = io_channel_read_blk(fs->io, 0,
137 -(int)sizeof(struct ext2_image_hdr),
138 fs->image_header);
139 if (retval)
140 goto cleanup;
141 if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE)
142 return EXT2_ET_MAGIC_E2IMAGE;
143 superblock = 1;
144 block_size = fs->image_header->fs_blocksize;
145 }
146
147 /*
148 * If the user specifies a specific block # for the
149 * superblock, then he/she must also specify the block size!
150 * Otherwise, read the master superblock located at offset
151 * SUPERBLOCK_OFFSET from the start of the partition.
152 *
153 * Note: we only save a backup copy of the superblock if we
154 * are reading the superblock from the primary superblock location.
155 */
156 if (superblock) {
157 if (!block_size) {
158 retval = EXT2_ET_INVALID_ARGUMENT;
159 goto cleanup;
160 }
161 io_channel_set_blksize(fs->io, block_size);
162 group_block = superblock;
163 fs->orig_super = 0;
164 } else {
165 io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
166 superblock = 1;
167 group_block = 0;
168 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
169 if (retval)
170 goto cleanup;
171 }
172 retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
173 fs->super);
174 if (retval)
175 goto cleanup;
176 if (fs->orig_super)
177 memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
178
179#if BB_BIG_ENDIAN
180 if ((fs->super->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ||
181 (fs->flags & EXT2_FLAG_SWAP_BYTES)) {
182 fs->flags |= EXT2_FLAG_SWAP_BYTES;
183
184 ext2fs_swap_super(fs->super);
185 }
186#endif
187
188 if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
189 retval = EXT2_ET_BAD_MAGIC;
190 goto cleanup;
191 }
192 if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
193 retval = EXT2_ET_REV_TOO_HIGH;
194 goto cleanup;
195 }
196
197 /*
198 * Check for feature set incompatibility
199 */
200 if (!(flags & EXT2_FLAG_FORCE)) {
201 if (fs->super->s_feature_incompat &
202 ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
203 retval = EXT2_ET_UNSUPP_FEATURE;
204 goto cleanup;
205 }
206 if ((flags & EXT2_FLAG_RW) &&
207 (fs->super->s_feature_ro_compat &
208 ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
209 retval = EXT2_ET_RO_UNSUPP_FEATURE;
210 goto cleanup;
211 }
212 if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
213 (fs->super->s_feature_incompat &
214 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
215 retval = EXT2_ET_UNSUPP_FEATURE;
216 goto cleanup;
217 }
218 }
219
220 fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
221 if (fs->blocksize == 0) {
222 retval = EXT2_ET_CORRUPT_SUPERBLOCK;
223 goto cleanup;
224 }
225 fs->fragsize = EXT2_FRAG_SIZE(fs->super);
226 fs->inode_blocks_per_group = ((fs->super->s_inodes_per_group *
227 EXT2_INODE_SIZE(fs->super) +
228 EXT2_BLOCK_SIZE(fs->super) - 1) /
229 EXT2_BLOCK_SIZE(fs->super));
230 if (block_size) {
231 if (block_size != fs->blocksize) {
232 retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
233 goto cleanup;
234 }
235 }
236 /*
237 * Set the blocksize to the filesystem's blocksize.
238 */
239 io_channel_set_blksize(fs->io, fs->blocksize);
240
241 /*
242 * If this is an external journal device, don't try to read
243 * the group descriptors, because they're not there.
244 */
245 if (fs->super->s_feature_incompat &
246 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
247 fs->group_desc_count = 0;
248 *ret_fs = fs;
249 return 0;
250 }
251
252 /*
253 * Read group descriptors
254 */
255 blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
256 if (blocks_per_group == 0 ||
257 blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
258 fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super)) {
259 retval = EXT2_ET_CORRUPT_SUPERBLOCK;
260 goto cleanup;
261 }
262 fs->group_desc_count = (fs->super->s_blocks_count -
263 fs->super->s_first_data_block +
264 blocks_per_group - 1) / blocks_per_group;
265 fs->desc_blocks = (fs->group_desc_count +
266 EXT2_DESC_PER_BLOCK(fs->super) - 1)
267 / EXT2_DESC_PER_BLOCK(fs->super);
268 retval = ext2fs_get_mem(fs->desc_blocks * fs->blocksize,
269 &fs->group_desc);
270 if (retval)
271 goto cleanup;
272 if (!group_block)
273 group_block = fs->super->s_first_data_block;
274 dest = (char *) fs->group_desc;
275 groups_per_block = fs->blocksize / sizeof(struct ext2_group_desc);
276 for (i=0 ; i < fs->desc_blocks; i++) {
277 blk = ext2fs_descriptor_block_loc(fs, group_block, i);
278 retval = io_channel_read_blk(fs->io, blk, 1, dest);
279 if (retval)
280 goto cleanup;
281#if BB_BIG_ENDIAN
282 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
283 gdp = (struct ext2_group_desc *) dest;
284 for (j=0; j < groups_per_block; j++)
285 ext2fs_swap_group_desc(gdp++);
286 }
287#endif
288 dest += fs->blocksize;
289 }
290
291 *ret_fs = fs;
292 return 0;
293cleanup:
294 ext2fs_free(fs);
295 return retval;
296}
297
298/*
299 * Set/get the filesystem data I/O channel.
300 *
301 * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
302 */
303errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io)
304{
305 if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
306 return EXT2_ET_NOT_IMAGE_FILE;
307 if (old_io) {
308 *old_io = (fs->image_io == fs->io) ? 0 : fs->io;
309 }
310 return 0;
311}
312
313errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
314{
315 if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
316 return EXT2_ET_NOT_IMAGE_FILE;
317 fs->io = new_io ? new_io : fs->image_io;
318 return 0;
319}
320
321errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
322{
323 if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
324 return EXT2_ET_NOT_IMAGE_FILE;
325 fs->io = fs->image_io = new_io;
326 fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW |
327 EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
328 fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
329 return 0;
330}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c b/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c
new file mode 100644
index 000000000..4766157c2
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c
@@ -0,0 +1,98 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * read_bb --- read the bad blocks inode
4 *
5 * Copyright (C) 1994 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29
30struct read_bb_record {
31 ext2_badblocks_list bb_list;
32 errcode_t err;
33};
34
35/*
36 * Helper function for ext2fs_read_bb_inode()
37 */
38#ifdef __TURBOC__
39# pragma argsused
40#endif
41static int mark_bad_block(ext2_filsys fs, blk_t *block_nr,
42 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
43 blk_t ref_block EXT2FS_ATTR((unused)),
44 int ref_offset EXT2FS_ATTR((unused)),
45 void *priv_data)
46{
47 struct read_bb_record *rb = (struct read_bb_record *) priv_data;
48
49 if (blockcnt < 0)
50 return 0;
51
52 if ((*block_nr < fs->super->s_first_data_block) ||
53 (*block_nr >= fs->super->s_blocks_count))
54 return 0; /* Ignore illegal blocks */
55
56 rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr);
57 if (rb->err)
58 return BLOCK_ABORT;
59 return 0;
60}
61
62/*
63 * Reads the current bad blocks from the bad blocks inode.
64 */
65errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list)
66{
67 errcode_t retval;
68 struct read_bb_record rb;
69 struct ext2_inode inode;
70 blk_t numblocks;
71
72 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
73
74 if (!*bb_list) {
75 retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
76 if (retval)
77 return retval;
78 if (inode.i_blocks < 500)
79 numblocks = (inode.i_blocks /
80 (fs->blocksize / 512)) + 20;
81 else
82 numblocks = 500;
83 retval = ext2fs_badblocks_list_create(bb_list, numblocks);
84 if (retval)
85 return retval;
86 }
87
88 rb.bb_list = *bb_list;
89 rb.err = 0;
90 retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, 0, 0,
91 mark_bad_block, &rb);
92 if (retval)
93 return retval;
94
95 return rb.err;
96}
97
98
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c b/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c
new file mode 100644
index 000000000..831adcc3a
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c
@@ -0,0 +1,98 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * read_bb_file.c --- read a list of bad blocks from a FILE *
4 *
5 * Copyright (C) 1994, 1995, 2000 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29
30/*
31 * Reads a list of bad blocks from a FILE *
32 */
33errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
34 ext2_badblocks_list *bb_list,
35 void *priv_data,
36 void (*invalid)(ext2_filsys fs,
37 blk_t blk,
38 char *badstr,
39 void *priv_data))
40{
41 errcode_t retval;
42 blk_t blockno;
43 int count;
44 char buf[128];
45
46 if (fs)
47 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
48
49 if (!*bb_list) {
50 retval = ext2fs_badblocks_list_create(bb_list, 10);
51 if (retval)
52 return retval;
53 }
54
55 while (!feof (f)) {
56 if (fgets(buf, sizeof(buf), f) == NULL)
57 break;
58 count = sscanf(buf, "%u", &blockno);
59 if (count <= 0)
60 continue;
61 if (fs &&
62 ((blockno < fs->super->s_first_data_block) ||
63 (blockno >= fs->super->s_blocks_count))) {
64 if (invalid)
65 (invalid)(fs, blockno, buf, priv_data);
66 continue;
67 }
68 retval = ext2fs_badblocks_list_add(*bb_list, blockno);
69 if (retval)
70 return retval;
71 }
72 return 0;
73}
74
75static void call_compat_invalid(ext2_filsys fs, blk_t blk,
76 char *badstr EXT2FS_ATTR((unused)),
77 void *priv_data)
78{
79 void (*invalid)(ext2_filsys, blk_t);
80
81 invalid = (void (*)(ext2_filsys, blk_t)) priv_data;
82 if (invalid)
83 invalid(fs, blk);
84}
85
86
87/*
88 * Reads a list of bad blocks from a FILE *
89 */
90errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
91 ext2_badblocks_list *bb_list,
92 void (*invalid)(ext2_filsys fs, blk_t blk))
93{
94 return ext2fs_read_bb_FILE2(fs, f, bb_list, (void *) invalid,
95 call_compat_invalid);
96}
97
98
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c b/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c
new file mode 100644
index 000000000..f7ee8b1fb
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c
@@ -0,0 +1,221 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * res_gdt.c --- reserve blocks for growing the group descriptor table
4 * during online resizing.
5 *
6 * Copyright (C) 2002 Andreas Dilger
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15#include <string.h>
16#include <time.h>
17#include "ext2_fs.h"
18#include "ext2fs.h"
19
20/*
21 * Iterate through the groups which hold BACKUP superblock/GDT copies in an
22 * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
23 * calling this for the first time. In a sparse filesystem it will be the
24 * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
25 * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
26 */
27static unsigned int list_backups(ext2_filsys fs, unsigned int *three,
28 unsigned int *five, unsigned int *seven)
29{
30 unsigned int *min = three;
31 int mult = 3;
32 unsigned int ret;
33
34 if (!(fs->super->s_feature_ro_compat &
35 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
36 ret = *min;
37 *min += 1;
38 return ret;
39 }
40
41 if (*five < *min) {
42 min = five;
43 mult = 5;
44 }
45 if (*seven < *min) {
46 min = seven;
47 mult = 7;
48 }
49
50 ret = *min;
51 *min *= mult;
52
53 return ret;
54}
55
56/*
57 * This code assumes that the reserved blocks have already been marked in-use
58 * during ext2fs_initialize(), so that they are not allocated for other
59 * uses before we can add them to the resize inode (which has to come
60 * after the creation of the inode table).
61 */
62errcode_t ext2fs_create_resize_inode(ext2_filsys fs)
63{
64 errcode_t retval, retval2;
65 struct ext2_super_block *sb;
66 struct ext2_inode inode;
67 __u32 *dindir_buf, *gdt_buf;
68 int rsv_add;
69 unsigned long long apb, inode_size;
70 blk_t dindir_blk, rsv_off, gdt_off, gdt_blk;
71 int dindir_dirty = 0, inode_dirty = 0;
72
73 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
74
75 sb = fs->super;
76
77 retval = ext2fs_get_mem(2 * fs->blocksize, (void *)&dindir_buf);
78 if (retval)
79 goto out_free;
80 gdt_buf = (__u32 *)((char *)dindir_buf + fs->blocksize);
81
82 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
83 if (retval)
84 goto out_free;
85
86 /* Maximum possible file size (we donly use the dindirect blocks) */
87 apb = EXT2_ADDR_PER_BLOCK(sb);
88 rsv_add = fs->blocksize / 512;
89 if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) {
90#ifdef RES_GDT_DEBUG
91 printf("reading GDT dindir %u\n", dindir_blk);
92#endif
93 retval = ext2fs_read_ind_block(fs, dindir_blk, dindir_buf);
94 if (retval)
95 goto out_inode;
96 } else {
97 blk_t goal = 3 + sb->s_reserved_gdt_blocks +
98 fs->desc_blocks + fs->inode_blocks_per_group;
99
100 retval = ext2fs_alloc_block(fs, goal, 0, &dindir_blk);
101 if (retval)
102 goto out_free;
103 inode.i_mode = LINUX_S_IFREG | 0600;
104 inode.i_links_count = 1;
105 inode.i_block[EXT2_DIND_BLOCK] = dindir_blk;
106 inode.i_blocks = rsv_add;
107 memset(dindir_buf, 0, fs->blocksize);
108#ifdef RES_GDT_DEBUG
109 printf("allocated GDT dindir %u\n", dindir_blk);
110#endif
111 dindir_dirty = inode_dirty = 1;
112 inode_size = apb*apb + apb + EXT2_NDIR_BLOCKS;
113 inode_size *= fs->blocksize;
114 inode.i_size = inode_size & 0xFFFFFFFF;
115 inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF;
116 if(inode.i_size_high) {
117 sb->s_feature_ro_compat |=
118 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
119 }
120 inode.i_ctime = time(0);
121 }
122
123 for (rsv_off = 0, gdt_off = fs->desc_blocks,
124 gdt_blk = sb->s_first_data_block + 1 + fs->desc_blocks;
125 rsv_off < sb->s_reserved_gdt_blocks;
126 rsv_off++, gdt_off++, gdt_blk++) {
127 unsigned int three = 1, five = 5, seven = 7;
128 unsigned int grp, last = 0;
129 int gdt_dirty = 0;
130
131 gdt_off %= apb;
132 if (!dindir_buf[gdt_off]) {
133 /* FIXME XXX XXX
134 blk_t new_blk;
135
136 retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk);
137 if (retval)
138 goto out_free;
139 if (new_blk != gdt_blk) {
140 // XXX free block
141 retval = -1; // XXX
142 }
143 */
144 gdt_dirty = dindir_dirty = inode_dirty = 1;
145 memset(gdt_buf, 0, fs->blocksize);
146 dindir_buf[gdt_off] = gdt_blk;
147 inode.i_blocks += rsv_add;
148#ifdef RES_GDT_DEBUG
149 printf("added primary GDT block %u at %u[%u]\n",
150 gdt_blk, dindir_blk, gdt_off);
151#endif
152 } else if (dindir_buf[gdt_off] == gdt_blk) {
153#ifdef RES_GDT_DEBUG
154 printf("reading primary GDT block %u\n", gdt_blk);
155#endif
156 retval = ext2fs_read_ind_block(fs, gdt_blk, gdt_buf);
157 if (retval)
158 goto out_dindir;
159 } else {
160#ifdef RES_GDT_DEBUG
161 printf("bad primary GDT %u != %u at %u[%u]\n",
162 dindir_buf[gdt_off], gdt_blk,dindir_blk,gdt_off);
163#endif
164 retval = EXT2_ET_RESIZE_INODE_CORRUPT;
165 goto out_dindir;
166 }
167
168 while ((grp = list_backups(fs, &three, &five, &seven)) <
169 fs->group_desc_count) {
170 blk_t expect = gdt_blk + grp * sb->s_blocks_per_group;
171
172 if (!gdt_buf[last]) {
173#ifdef RES_GDT_DEBUG
174 printf("added backup GDT %u grp %u@%u[%u]\n",
175 expect, grp, gdt_blk, last);
176#endif
177 gdt_buf[last] = expect;
178 inode.i_blocks += rsv_add;
179 gdt_dirty = inode_dirty = 1;
180 } else if (gdt_buf[last] != expect) {
181#ifdef RES_GDT_DEBUG
182 printf("bad backup GDT %u != %u at %u[%u]\n",
183 gdt_buf[last], expect, gdt_blk, last);
184#endif
185 retval = EXT2_ET_RESIZE_INODE_CORRUPT;
186 goto out_dindir;
187 }
188 last++;
189 }
190 if (gdt_dirty) {
191#ifdef RES_GDT_DEBUG
192 printf("writing primary GDT block %u\n", gdt_blk);
193#endif
194 retval = ext2fs_write_ind_block(fs, gdt_blk, gdt_buf);
195 if (retval)
196 goto out_dindir;
197 }
198 }
199
200out_dindir:
201 if (dindir_dirty) {
202 retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf);
203 if (!retval)
204 retval = retval2;
205 }
206out_inode:
207#ifdef RES_GDT_DEBUG
208 printf("inode.i_blocks = %u, i_size = %u\n", inode.i_blocks,
209 inode.i_size);
210#endif
211 if (inode_dirty) {
212 inode.i_atime = inode.i_mtime = time(0);
213 retval2 = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
214 if (!retval)
215 retval = retval2;
216 }
217out_free:
218 ext2fs_free_mem((void *)&dindir_buf);
219 return retval;
220}
221
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c b/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c
new file mode 100644
index 000000000..e932b3c9d
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c
@@ -0,0 +1,107 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * rs_bitmap.c --- routine for changing the size of a bitmap
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#ifdef HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#ifdef HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29
30errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, __u32 new_real_end,
31 ext2fs_generic_bitmap bmap)
32{
33 errcode_t retval;
34 size_t size, new_size;
35 __u32 bitno;
36
37 if (!bmap)
38 return EXT2_ET_INVALID_ARGUMENT;
39
40 EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP);
41
42 /*
43 * If we're expanding the bitmap, make sure all of the new
44 * parts of the bitmap are zero.
45 */
46 if (new_end > bmap->end) {
47 bitno = bmap->real_end;
48 if (bitno > new_end)
49 bitno = new_end;
50 for (; bitno > bmap->end; bitno--)
51 ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
52 }
53 if (new_real_end == bmap->real_end) {
54 bmap->end = new_end;
55 return 0;
56 }
57
58 size = ((bmap->real_end - bmap->start) / 8) + 1;
59 new_size = ((new_real_end - bmap->start) / 8) + 1;
60
61 if (size != new_size) {
62 retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap);
63 if (retval)
64 return retval;
65 }
66 if (new_size > size)
67 memset(bmap->bitmap + size, 0, new_size - size);
68
69 bmap->end = new_end;
70 bmap->real_end = new_real_end;
71 return 0;
72}
73
74errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
75 ext2fs_inode_bitmap bmap)
76{
77 errcode_t retval;
78
79 if (!bmap)
80 return EXT2_ET_INVALID_ARGUMENT;
81
82 EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_INODE_BITMAP);
83
84 bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
85 retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
86 bmap);
87 bmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
88 return retval;
89}
90
91errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
92 ext2fs_block_bitmap bmap)
93{
94 errcode_t retval;
95
96 if (!bmap)
97 return EXT2_ET_INVALID_ARGUMENT;
98
99 EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
100
101 bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
102 retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
103 bmap);
104 bmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
105 return retval;
106}
107
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c b/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c
new file mode 100644
index 000000000..a5782db95
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c
@@ -0,0 +1,296 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * rw_bitmaps.c --- routines to read and write the inode and block bitmaps.
4 *
5 * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#ifdef HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#ifdef HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29#include "e2image.h"
30
31#if defined(__powerpc__) && BB_BIG_ENDIAN
32/*
33 * On the PowerPC, the big-endian variant of the ext2 filesystem
34 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
35 * of each word. Thus a bitmap with only bit 0 set would be, as
36 * a string of bytes, 00 00 00 01 00 ...
37 * To cope with this, we byte-reverse each word of a bitmap if
38 * we have a big-endian filesystem, that is, if we are *not*
39 * byte-swapping other word-sized numbers.
40 */
41#define EXT2_BIG_ENDIAN_BITMAPS
42#endif
43
44#ifdef EXT2_BIG_ENDIAN_BITMAPS
45static void ext2fs_swap_bitmap(ext2_filsys fs, char *bitmap, int nbytes)
46{
47 __u32 *p = (__u32 *) bitmap;
48 int n;
49
50 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
51 *p = ext2fs_swab32(*p);
52}
53#endif
54
55errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
56{
57 dgrp_t i;
58 size_t nbytes;
59 errcode_t retval;
60 char * inode_bitmap = fs->inode_map->bitmap;
61 char * bitmap_block = NULL;
62 blk_t blk;
63
64 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
65
66 if (!(fs->flags & EXT2_FLAG_RW))
67 return EXT2_ET_RO_FILSYS;
68 if (!inode_bitmap)
69 return 0;
70 nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
71
72 retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
73 if (retval)
74 return retval;
75 memset(bitmap_block, 0xff, fs->blocksize);
76 for (i = 0; i < fs->group_desc_count; i++) {
77 memcpy(bitmap_block, inode_bitmap, nbytes);
78 blk = fs->group_desc[i].bg_inode_bitmap;
79 if (blk) {
80#ifdef EXT2_BIG_ENDIAN_BITMAPS
81 if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
82 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
83 ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
84#endif
85 retval = io_channel_write_blk(fs->io, blk, 1,
86 bitmap_block);
87 if (retval)
88 return EXT2_ET_INODE_BITMAP_WRITE;
89 }
90 inode_bitmap += nbytes;
91 }
92 fs->flags &= ~EXT2_FLAG_IB_DIRTY;
93 ext2fs_free_mem(&bitmap_block);
94 return 0;
95}
96
97errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
98{
99 dgrp_t i;
100 unsigned int j;
101 int nbytes;
102 unsigned int nbits;
103 errcode_t retval;
104 char * block_bitmap = fs->block_map->bitmap;
105 char * bitmap_block = NULL;
106 blk_t blk;
107
108 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
109
110 if (!(fs->flags & EXT2_FLAG_RW))
111 return EXT2_ET_RO_FILSYS;
112 if (!block_bitmap)
113 return 0;
114 nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
115 retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
116 if (retval)
117 return retval;
118 memset(bitmap_block, 0xff, fs->blocksize);
119 for (i = 0; i < fs->group_desc_count; i++) {
120 memcpy(bitmap_block, block_bitmap, nbytes);
121 if (i == fs->group_desc_count - 1) {
122 /* Force bitmap padding for the last group */
123 nbits = ((fs->super->s_blocks_count
124 - fs->super->s_first_data_block)
125 % EXT2_BLOCKS_PER_GROUP(fs->super));
126 if (nbits)
127 for (j = nbits; j < fs->blocksize * 8; j++)
128 ext2fs_set_bit(j, bitmap_block);
129 }
130 blk = fs->group_desc[i].bg_block_bitmap;
131 if (blk) {
132#ifdef EXT2_BIG_ENDIAN_BITMAPS
133 if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
134 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
135 ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
136#endif
137 retval = io_channel_write_blk(fs->io, blk, 1,
138 bitmap_block);
139 if (retval)
140 return EXT2_ET_BLOCK_BITMAP_WRITE;
141 }
142 block_bitmap += nbytes;
143 }
144 fs->flags &= ~EXT2_FLAG_BB_DIRTY;
145 ext2fs_free_mem(&bitmap_block);
146 return 0;
147}
148
149static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
150{
151 dgrp_t i;
152 char *block_bitmap = 0, *inode_bitmap = 0;
153 char *buf;
154 errcode_t retval;
155 int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
156 int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
157 blk_t blk;
158
159 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
160
161 fs->write_bitmaps = ext2fs_write_bitmaps;
162
163 retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
164 if (retval)
165 return retval;
166 if (do_block) {
167 ext2fs_free_block_bitmap(fs->block_map);
168 sprintf(buf, "block bitmap for %s", fs->device_name);
169 retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
170 if (retval)
171 goto cleanup;
172 block_bitmap = fs->block_map->bitmap;
173 }
174 if (do_inode) {
175 ext2fs_free_inode_bitmap(fs->inode_map);
176 sprintf(buf, "inode bitmap for %s", fs->device_name);
177 retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
178 if (retval)
179 goto cleanup;
180 inode_bitmap = fs->inode_map->bitmap;
181 }
182 ext2fs_free_mem(&buf);
183
184 if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
185 if (inode_bitmap) {
186 blk = (fs->image_header->offset_inodemap /
187 fs->blocksize);
188 retval = io_channel_read_blk(fs->image_io, blk,
189 -(inode_nbytes * fs->group_desc_count),
190 inode_bitmap);
191 if (retval)
192 goto cleanup;
193 }
194 if (block_bitmap) {
195 blk = (fs->image_header->offset_blockmap /
196 fs->blocksize);
197 retval = io_channel_read_blk(fs->image_io, blk,
198 -(block_nbytes * fs->group_desc_count),
199 block_bitmap);
200 if (retval)
201 goto cleanup;
202 }
203 return 0;
204 }
205
206 for (i = 0; i < fs->group_desc_count; i++) {
207 if (block_bitmap) {
208 blk = fs->group_desc[i].bg_block_bitmap;
209 if (blk) {
210 retval = io_channel_read_blk(fs->io, blk,
211 -block_nbytes, block_bitmap);
212 if (retval) {
213 retval = EXT2_ET_BLOCK_BITMAP_READ;
214 goto cleanup;
215 }
216#ifdef EXT2_BIG_ENDIAN_BITMAPS
217 if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
218 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
219 ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes);
220#endif
221 } else
222 memset(block_bitmap, 0, block_nbytes);
223 block_bitmap += block_nbytes;
224 }
225 if (inode_bitmap) {
226 blk = fs->group_desc[i].bg_inode_bitmap;
227 if (blk) {
228 retval = io_channel_read_blk(fs->io, blk,
229 -inode_nbytes, inode_bitmap);
230 if (retval) {
231 retval = EXT2_ET_INODE_BITMAP_READ;
232 goto cleanup;
233 }
234#ifdef EXT2_BIG_ENDIAN_BITMAPS
235 if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
236 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
237 ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes);
238#endif
239 } else
240 memset(inode_bitmap, 0, inode_nbytes);
241 inode_bitmap += inode_nbytes;
242 }
243 }
244 return 0;
245
246cleanup:
247 if (do_block) {
248 ext2fs_free_mem(&fs->block_map);
249 }
250 if (do_inode) {
251 ext2fs_free_mem(&fs->inode_map);
252 }
253 ext2fs_free_mem(&buf);
254 return retval;
255}
256
257errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs)
258{
259 return read_bitmaps(fs, 1, 0);
260}
261
262errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
263{
264 return read_bitmaps(fs, 0, 1);
265}
266
267errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
268{
269
270 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
271
272 if (fs->inode_map && fs->block_map)
273 return 0;
274
275 return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
276}
277
278errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
279{
280 errcode_t retval;
281
282 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
283
284 if (fs->block_map && ext2fs_test_bb_dirty(fs)) {
285 retval = ext2fs_write_block_bitmap(fs);
286 if (retval)
287 return retval;
288 }
289 if (fs->inode_map && ext2fs_test_ib_dirty(fs)) {
290 retval = ext2fs_write_inode_bitmap(fs);
291 if (retval)
292 return retval;
293 }
294 return 0;
295}
296
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/sparse.c b/e2fsprogs/old_e2fsprogs/ext2fs/sparse.c
new file mode 100644
index 000000000..b3d3071e9
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/sparse.c
@@ -0,0 +1,79 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * sparse.c --- find the groups in an ext2 filesystem with metadata backups
4 *
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6 * Copyright (C) 2002 Andreas Dilger.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include <stdio.h>
15
16#include "ext2_fs.h"
17#include "ext2fsP.h"
18
19static int test_root(int a, int b)
20{
21 if (a == 0)
22 return 1;
23 while (1) {
24 if (a == 1)
25 return 1;
26 if (a % b)
27 return 0;
28 a = a / b;
29 }
30}
31
32int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
33{
34 if (!(fs->super->s_feature_ro_compat &
35 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
36 return 1;
37
38 if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
39 test_root(group_block, 7))
40 return 1;
41
42 return 0;
43}
44
45/*
46 * Iterate through the groups which hold BACKUP superblock/GDT copies in an
47 * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
48 * calling this for the first time. In a sparse filesystem it will be the
49 * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
50 * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
51 */
52unsigned int ext2fs_list_backups(ext2_filsys fs, unsigned int *three,
53 unsigned int *five, unsigned int *seven)
54{
55 unsigned int *min = three;
56 int mult = 3;
57 unsigned int ret;
58
59 if (!(fs->super->s_feature_ro_compat &
60 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
61 ret = *min;
62 *min += 1;
63 return ret;
64 }
65
66 if (*five < *min) {
67 min = five;
68 mult = 5;
69 }
70 if (*seven < *min) {
71 min = seven;
72 mult = 7;
73 }
74
75 ret = *min;
76 *min *= mult;
77
78 return ret;
79}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c b/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c
new file mode 100644
index 000000000..2fca3cfbb
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c
@@ -0,0 +1,236 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * swapfs.c --- swap ext2 filesystem data structures
4 *
5 * Copyright (C) 1995, 1996, 2002 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <unistd.h>
15#include <string.h>
16#include <time.h>
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20#include "ext2_ext_attr.h"
21
22#if BB_BIG_ENDIAN
23void ext2fs_swap_super(struct ext2_super_block * sb)
24{
25 int i;
26 sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count);
27 sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count);
28 sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count);
29 sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count);
30 sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count);
31 sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block);
32 sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size);
33 sb->s_log_frag_size = ext2fs_swab32(sb->s_log_frag_size);
34 sb->s_blocks_per_group = ext2fs_swab32(sb->s_blocks_per_group);
35 sb->s_frags_per_group = ext2fs_swab32(sb->s_frags_per_group);
36 sb->s_inodes_per_group = ext2fs_swab32(sb->s_inodes_per_group);
37 sb->s_mtime = ext2fs_swab32(sb->s_mtime);
38 sb->s_wtime = ext2fs_swab32(sb->s_wtime);
39 sb->s_mnt_count = ext2fs_swab16(sb->s_mnt_count);
40 sb->s_max_mnt_count = ext2fs_swab16(sb->s_max_mnt_count);
41 sb->s_magic = ext2fs_swab16(sb->s_magic);
42 sb->s_state = ext2fs_swab16(sb->s_state);
43 sb->s_errors = ext2fs_swab16(sb->s_errors);
44 sb->s_minor_rev_level = ext2fs_swab16(sb->s_minor_rev_level);
45 sb->s_lastcheck = ext2fs_swab32(sb->s_lastcheck);
46 sb->s_checkinterval = ext2fs_swab32(sb->s_checkinterval);
47 sb->s_creator_os = ext2fs_swab32(sb->s_creator_os);
48 sb->s_rev_level = ext2fs_swab32(sb->s_rev_level);
49 sb->s_def_resuid = ext2fs_swab16(sb->s_def_resuid);
50 sb->s_def_resgid = ext2fs_swab16(sb->s_def_resgid);
51 sb->s_first_ino = ext2fs_swab32(sb->s_first_ino);
52 sb->s_inode_size = ext2fs_swab16(sb->s_inode_size);
53 sb->s_block_group_nr = ext2fs_swab16(sb->s_block_group_nr);
54 sb->s_feature_compat = ext2fs_swab32(sb->s_feature_compat);
55 sb->s_feature_incompat = ext2fs_swab32(sb->s_feature_incompat);
56 sb->s_feature_ro_compat = ext2fs_swab32(sb->s_feature_ro_compat);
57 sb->s_algorithm_usage_bitmap = ext2fs_swab32(sb->s_algorithm_usage_bitmap);
58 sb->s_reserved_gdt_blocks = ext2fs_swab16(sb->s_reserved_gdt_blocks);
59 sb->s_journal_inum = ext2fs_swab32(sb->s_journal_inum);
60 sb->s_journal_dev = ext2fs_swab32(sb->s_journal_dev);
61 sb->s_last_orphan = ext2fs_swab32(sb->s_last_orphan);
62 sb->s_default_mount_opts = ext2fs_swab32(sb->s_default_mount_opts);
63 sb->s_first_meta_bg = ext2fs_swab32(sb->s_first_meta_bg);
64 sb->s_mkfs_time = ext2fs_swab32(sb->s_mkfs_time);
65 for (i=0; i < 4; i++)
66 sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]);
67 for (i=0; i < 17; i++)
68 sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]);
69
70}
71
72void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)
73{
74 gdp->bg_block_bitmap = ext2fs_swab32(gdp->bg_block_bitmap);
75 gdp->bg_inode_bitmap = ext2fs_swab32(gdp->bg_inode_bitmap);
76 gdp->bg_inode_table = ext2fs_swab32(gdp->bg_inode_table);
77 gdp->bg_free_blocks_count = ext2fs_swab16(gdp->bg_free_blocks_count);
78 gdp->bg_free_inodes_count = ext2fs_swab16(gdp->bg_free_inodes_count);
79 gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
80}
81
82void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
83{
84 struct ext2_ext_attr_header *from_header =
85 (struct ext2_ext_attr_header *)from;
86 struct ext2_ext_attr_header *to_header =
87 (struct ext2_ext_attr_header *)to;
88 struct ext2_ext_attr_entry *from_entry, *to_entry;
89 char *from_end = (char *)from_header + bufsize;
90 int n;
91
92 if (to_header != from_header)
93 memcpy(to_header, from_header, bufsize);
94
95 from_entry = (struct ext2_ext_attr_entry *)from_header;
96 to_entry = (struct ext2_ext_attr_entry *)to_header;
97
98 if (has_header) {
99 to_header->h_magic = ext2fs_swab32(from_header->h_magic);
100 to_header->h_blocks = ext2fs_swab32(from_header->h_blocks);
101 to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
102 for (n=0; n<4; n++)
103 to_header->h_reserved[n] =
104 ext2fs_swab32(from_header->h_reserved[n]);
105 from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
106 to_entry = (struct ext2_ext_attr_entry *)(to_header+1);
107 }
108
109 while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
110 to_entry->e_value_offs =
111 ext2fs_swab16(from_entry->e_value_offs);
112 to_entry->e_value_block =
113 ext2fs_swab32(from_entry->e_value_block);
114 to_entry->e_value_size =
115 ext2fs_swab32(from_entry->e_value_size);
116 from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
117 to_entry = EXT2_EXT_ATTR_NEXT(to_entry);
118 }
119}
120
121void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
122 struct ext2_inode_large *f, int hostorder,
123 int bufsize)
124{
125 unsigned i;
126 int islnk = 0;
127 __u32 *eaf, *eat;
128
129 if (hostorder && LINUX_S_ISLNK(f->i_mode))
130 islnk = 1;
131 t->i_mode = ext2fs_swab16(f->i_mode);
132 if (!hostorder && LINUX_S_ISLNK(t->i_mode))
133 islnk = 1;
134 t->i_uid = ext2fs_swab16(f->i_uid);
135 t->i_size = ext2fs_swab32(f->i_size);
136 t->i_atime = ext2fs_swab32(f->i_atime);
137 t->i_ctime = ext2fs_swab32(f->i_ctime);
138 t->i_mtime = ext2fs_swab32(f->i_mtime);
139 t->i_dtime = ext2fs_swab32(f->i_dtime);
140 t->i_gid = ext2fs_swab16(f->i_gid);
141 t->i_links_count = ext2fs_swab16(f->i_links_count);
142 t->i_blocks = ext2fs_swab32(f->i_blocks);
143 t->i_flags = ext2fs_swab32(f->i_flags);
144 t->i_file_acl = ext2fs_swab32(f->i_file_acl);
145 t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
146 if (!islnk || ext2fs_inode_data_blocks(fs, (struct ext2_inode *)t)) {
147 for (i = 0; i < EXT2_N_BLOCKS; i++)
148 t->i_block[i] = ext2fs_swab32(f->i_block[i]);
149 } else if (t != f) {
150 for (i = 0; i < EXT2_N_BLOCKS; i++)
151 t->i_block[i] = f->i_block[i];
152 }
153 t->i_generation = ext2fs_swab32(f->i_generation);
154 t->i_faddr = ext2fs_swab32(f->i_faddr);
155
156 switch (fs->super->s_creator_os) {
157 case EXT2_OS_LINUX:
158 t->osd1.linux1.l_i_reserved1 =
159 ext2fs_swab32(f->osd1.linux1.l_i_reserved1);
160 t->osd2.linux2.l_i_frag = f->osd2.linux2.l_i_frag;
161 t->osd2.linux2.l_i_fsize = f->osd2.linux2.l_i_fsize;
162 t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1);
163 t->osd2.linux2.l_i_uid_high =
164 ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
165 t->osd2.linux2.l_i_gid_high =
166 ext2fs_swab16 (f->osd2.linux2.l_i_gid_high);
167 t->osd2.linux2.l_i_reserved2 =
168 ext2fs_swab32(f->osd2.linux2.l_i_reserved2);
169 break;
170 case EXT2_OS_HURD:
171 t->osd1.hurd1.h_i_translator =
172 ext2fs_swab32 (f->osd1.hurd1.h_i_translator);
173 t->osd2.hurd2.h_i_frag = f->osd2.hurd2.h_i_frag;
174 t->osd2.hurd2.h_i_fsize = f->osd2.hurd2.h_i_fsize;
175 t->osd2.hurd2.h_i_mode_high =
176 ext2fs_swab16 (f->osd2.hurd2.h_i_mode_high);
177 t->osd2.hurd2.h_i_uid_high =
178 ext2fs_swab16 (f->osd2.hurd2.h_i_uid_high);
179 t->osd2.hurd2.h_i_gid_high =
180 ext2fs_swab16 (f->osd2.hurd2.h_i_gid_high);
181 t->osd2.hurd2.h_i_author =
182 ext2fs_swab32 (f->osd2.hurd2.h_i_author);
183 break;
184 case EXT2_OS_MASIX:
185 t->osd1.masix1.m_i_reserved1 =
186 ext2fs_swab32(f->osd1.masix1.m_i_reserved1);
187 t->osd2.masix2.m_i_frag = f->osd2.masix2.m_i_frag;
188 t->osd2.masix2.m_i_fsize = f->osd2.masix2.m_i_fsize;
189 t->osd2.masix2.m_pad1 = ext2fs_swab16(f->osd2.masix2.m_pad1);
190 t->osd2.masix2.m_i_reserved2[0] =
191 ext2fs_swab32(f->osd2.masix2.m_i_reserved2[0]);
192 t->osd2.masix2.m_i_reserved2[1] =
193 ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]);
194 break;
195 }
196
197 if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
198 return; /* no i_extra_isize field */
199
200 t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
201 if (t->i_extra_isize > EXT2_INODE_SIZE(fs->super) -
202 sizeof(struct ext2_inode)) {
203 /* this is error case: i_extra_size is too large */
204 return;
205 }
206
207 i = sizeof(struct ext2_inode) + t->i_extra_isize + sizeof(__u32);
208 if (bufsize < (int) i)
209 return; /* no space for EA magic */
210
211 eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
212 f->i_extra_isize);
213
214 if (ext2fs_swab32(*eaf) != EXT2_EXT_ATTR_MAGIC)
215 return; /* it seems no magic here */
216
217 eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
218 f->i_extra_isize);
219 *eat = ext2fs_swab32(*eaf);
220
221 /* convert EA(s) */
222 ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
223 bufsize - sizeof(struct ext2_inode) -
224 t->i_extra_isize - sizeof(__u32), 0);
225
226}
227
228void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
229 struct ext2_inode *f, int hostorder)
230{
231 ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
232 (struct ext2_inode_large *) f, hostorder,
233 sizeof(struct ext2_inode));
234}
235
236#endif
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/test_io.c b/e2fsprogs/old_e2fsprogs/ext2fs/test_io.c
new file mode 100644
index 000000000..bd74225c0
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/test_io.c
@@ -0,0 +1,380 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * test_io.c --- This is the Test I/O interface.
4 *
5 * Copyright (C) 1996 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19#include <time.h>
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29
30/*
31 * For checking structure magic numbers...
32 */
33
34#define EXT2_CHECK_MAGIC(struct, code) \
35 if ((struct)->magic != (code)) return (code)
36
37struct test_private_data {
38 int magic;
39 io_channel real;
40 int flags;
41 FILE *outfile;
42 unsigned long block;
43 int read_abort_count, write_abort_count;
44 void (*read_blk)(unsigned long block, int count, errcode_t err);
45 void (*write_blk)(unsigned long block, int count, errcode_t err);
46 void (*set_blksize)(int blksize, errcode_t err);
47 void (*write_byte)(unsigned long block, int count, errcode_t err);
48};
49
50static errcode_t test_open(const char *name, int flags, io_channel *channel);
51static errcode_t test_close(io_channel channel);
52static errcode_t test_set_blksize(io_channel channel, int blksize);
53static errcode_t test_read_blk(io_channel channel, unsigned long block,
54 int count, void *data);
55static errcode_t test_write_blk(io_channel channel, unsigned long block,
56 int count, const void *data);
57static errcode_t test_flush(io_channel channel);
58static errcode_t test_write_byte(io_channel channel, unsigned long offset,
59 int count, const void *buf);
60static errcode_t test_set_option(io_channel channel, const char *option,
61 const char *arg);
62
63static struct struct_io_manager struct_test_manager = {
64 EXT2_ET_MAGIC_IO_MANAGER,
65 "Test I/O Manager",
66 test_open,
67 test_close,
68 test_set_blksize,
69 test_read_blk,
70 test_write_blk,
71 test_flush,
72 test_write_byte,
73 test_set_option
74};
75
76io_manager test_io_manager = &struct_test_manager;
77
78/*
79 * These global variable can be set by the test program as
80 * necessary *before* calling test_open
81 */
82io_manager test_io_backing_manager = 0;
83void (*test_io_cb_read_blk)
84 (unsigned long block, int count, errcode_t err) = 0;
85void (*test_io_cb_write_blk)
86 (unsigned long block, int count, errcode_t err) = 0;
87void (*test_io_cb_set_blksize)
88 (int blksize, errcode_t err) = 0;
89void (*test_io_cb_write_byte)
90 (unsigned long block, int count, errcode_t err) = 0;
91
92/*
93 * Test flags
94 */
95#define TEST_FLAG_READ 0x01
96#define TEST_FLAG_WRITE 0x02
97#define TEST_FLAG_SET_BLKSIZE 0x04
98#define TEST_FLAG_FLUSH 0x08
99#define TEST_FLAG_DUMP 0x10
100#define TEST_FLAG_SET_OPTION 0x20
101
102static void test_dump_block(io_channel channel,
103 struct test_private_data *data,
104 unsigned long block, const void *buf)
105{
106 const unsigned char *cp;
107 FILE *f = data->outfile;
108 int i;
109 unsigned long cksum = 0;
110
111 for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
112 cksum += *cp;
113 }
114 fprintf(f, "Contents of block %lu, checksum %08lu:\n", block, cksum);
115 for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
116 if ((i % 16) == 0)
117 fprintf(f, "%04x: ", i);
118 fprintf(f, "%02x%c", *cp, ((i % 16) == 15) ? '\n' : ' ');
119 }
120}
121
122static void test_abort(io_channel channel, unsigned long block)
123{
124 struct test_private_data *data;
125 FILE *f;
126
127 data = (struct test_private_data *) channel->private_data;
128 f = data->outfile;
129 test_flush(channel);
130
131 fprintf(f, "Aborting due to I/O to block %lu\n", block);
132 fflush(f);
133 abort();
134}
135
136static errcode_t test_open(const char *name, int flags, io_channel *channel)
137{
138 io_channel io = NULL;
139 struct test_private_data *data = NULL;
140 errcode_t retval;
141 char *value;
142
143 if (name == 0)
144 return EXT2_ET_BAD_DEVICE_NAME;
145 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
146 if (retval)
147 return retval;
148 memset(io, 0, sizeof(struct struct_io_channel));
149 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
150 retval = ext2fs_get_mem(sizeof(struct test_private_data), &data);
151 if (retval) {
152 retval = EXT2_ET_NO_MEMORY;
153 goto cleanup;
154 }
155 io->manager = test_io_manager;
156 retval = ext2fs_get_mem(strlen(name)+1, &io->name);
157 if (retval)
158 goto cleanup;
159
160 strcpy(io->name, name);
161 io->private_data = data;
162 io->block_size = 1024;
163 io->read_error = 0;
164 io->write_error = 0;
165 io->refcount = 1;
166
167 memset(data, 0, sizeof(struct test_private_data));
168 data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL;
169 if (test_io_backing_manager) {
170 retval = test_io_backing_manager->open(name, flags,
171 &data->real);
172 if (retval)
173 goto cleanup;
174 } else
175 data->real = 0;
176 data->read_blk = test_io_cb_read_blk;
177 data->write_blk = test_io_cb_write_blk;
178 data->set_blksize = test_io_cb_set_blksize;
179 data->write_byte = test_io_cb_write_byte;
180
181 data->outfile = NULL;
182 if ((value = getenv("TEST_IO_LOGFILE")) != NULL)
183 data->outfile = fopen(value, "w");
184 if (!data->outfile)
185 data->outfile = stderr;
186
187 data->flags = 0;
188 if ((value = getenv("TEST_IO_FLAGS")) != NULL)
189 data->flags = strtoul(value, NULL, 0);
190
191 data->block = 0;
192 if ((value = getenv("TEST_IO_BLOCK")) != NULL)
193 data->block = strtoul(value, NULL, 0);
194
195 data->read_abort_count = 0;
196 if ((value = getenv("TEST_IO_READ_ABORT")) != NULL)
197 data->read_abort_count = strtoul(value, NULL, 0);
198
199 data->write_abort_count = 0;
200 if ((value = getenv("TEST_IO_WRITE_ABORT")) != NULL)
201 data->write_abort_count = strtoul(value, NULL, 0);
202
203 *channel = io;
204 return 0;
205
206cleanup:
207 ext2fs_free_mem(&io);
208 ext2fs_free_mem(&data);
209 return retval;
210}
211
212static errcode_t test_close(io_channel channel)
213{
214 struct test_private_data *data;
215 errcode_t retval = 0;
216
217 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
218 data = (struct test_private_data *) channel->private_data;
219 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
220
221 if (--channel->refcount > 0)
222 return 0;
223
224 if (data->real)
225 retval = io_channel_close(data->real);
226
227 if (data->outfile && data->outfile != stderr)
228 fclose(data->outfile);
229
230 ext2fs_free_mem(&channel->private_data);
231 ext2fs_free_mem(&channel->name);
232 ext2fs_free_mem(&channel);
233 return retval;
234}
235
236static errcode_t test_set_blksize(io_channel channel, int blksize)
237{
238 struct test_private_data *data;
239 errcode_t retval = 0;
240
241 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
242 data = (struct test_private_data *) channel->private_data;
243 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
244
245 if (data->real)
246 retval = io_channel_set_blksize(data->real, blksize);
247 if (data->set_blksize)
248 data->set_blksize(blksize, retval);
249 if (data->flags & TEST_FLAG_SET_BLKSIZE)
250 fprintf(data->outfile,
251 "Test_io: set_blksize(%d) returned %s\n",
252 blksize, retval ? error_message(retval) : "OK");
253 channel->block_size = blksize;
254 return retval;
255}
256
257
258static errcode_t test_read_blk(io_channel channel, unsigned long block,
259 int count, void *buf)
260{
261 struct test_private_data *data;
262 errcode_t retval = 0;
263
264 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
265 data = (struct test_private_data *) channel->private_data;
266 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
267
268 if (data->real)
269 retval = io_channel_read_blk(data->real, block, count, buf);
270 if (data->read_blk)
271 data->read_blk(block, count, retval);
272 if (data->flags & TEST_FLAG_READ)
273 fprintf(data->outfile,
274 "Test_io: read_blk(%lu, %d) returned %s\n",
275 block, count, retval ? error_message(retval) : "OK");
276 if (data->block && data->block == block) {
277 if (data->flags & TEST_FLAG_DUMP)
278 test_dump_block(channel, data, block, buf);
279 if (--data->read_abort_count == 0)
280 test_abort(channel, block);
281 }
282 return retval;
283}
284
285static errcode_t test_write_blk(io_channel channel, unsigned long block,
286 int count, const void *buf)
287{
288 struct test_private_data *data;
289 errcode_t retval = 0;
290
291 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
292 data = (struct test_private_data *) channel->private_data;
293 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
294
295 if (data->real)
296 retval = io_channel_write_blk(data->real, block, count, buf);
297 if (data->write_blk)
298 data->write_blk(block, count, retval);
299 if (data->flags & TEST_FLAG_WRITE)
300 fprintf(data->outfile,
301 "Test_io: write_blk(%lu, %d) returned %s\n",
302 block, count, retval ? error_message(retval) : "OK");
303 if (data->block && data->block == block) {
304 if (data->flags & TEST_FLAG_DUMP)
305 test_dump_block(channel, data, block, buf);
306 if (--data->write_abort_count == 0)
307 test_abort(channel, block);
308 }
309 return retval;
310}
311
312static errcode_t test_write_byte(io_channel channel, unsigned long offset,
313 int count, const void *buf)
314{
315 struct test_private_data *data;
316 errcode_t retval = 0;
317
318 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
319 data = (struct test_private_data *) channel->private_data;
320 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
321
322 if (data->real && data->real->manager->write_byte)
323 retval = io_channel_write_byte(data->real, offset, count, buf);
324 if (data->write_byte)
325 data->write_byte(offset, count, retval);
326 if (data->flags & TEST_FLAG_WRITE)
327 fprintf(data->outfile,
328 "Test_io: write_byte(%lu, %d) returned %s\n",
329 offset, count, retval ? error_message(retval) : "OK");
330 return retval;
331}
332
333/*
334 * Flush data buffers to disk.
335 */
336static errcode_t test_flush(io_channel channel)
337{
338 struct test_private_data *data;
339 errcode_t retval = 0;
340
341 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
342 data = (struct test_private_data *) channel->private_data;
343 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
344
345 if (data->real)
346 retval = io_channel_flush(data->real);
347
348 if (data->flags & TEST_FLAG_FLUSH)
349 fprintf(data->outfile, "Test_io: flush() returned %s\n",
350 retval ? error_message(retval) : "OK");
351
352 return retval;
353}
354
355static errcode_t test_set_option(io_channel channel, const char *option,
356 const char *arg)
357{
358 struct test_private_data *data;
359 errcode_t retval = 0;
360
361 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
362 data = (struct test_private_data *) channel->private_data;
363 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
364
365
366 if (data->flags & TEST_FLAG_SET_OPTION)
367 fprintf(data->outfile, "Test_io: set_option(%s, %s) ",
368 option, arg);
369 if (data->real && data->real->manager->set_option) {
370 retval = (data->real->manager->set_option)(data->real,
371 option, arg);
372 if (data->flags & TEST_FLAG_SET_OPTION)
373 fprintf(data->outfile, "returned %s\n",
374 retval ? error_message(retval) : "OK");
375 } else {
376 if (data->flags & TEST_FLAG_SET_OPTION)
377 fprintf(data->outfile, "not implemented\n");
378 }
379 return retval;
380}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c b/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c
new file mode 100644
index 000000000..474f07340
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c
@@ -0,0 +1,703 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * unix_io.c --- This is the Unix (well, really POSIX) implementation
4 * of the I/O manager.
5 *
6 * Implements a one-block write-through cache.
7 *
8 * Includes support for Windows NT support under Cygwin.
9 *
10 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
11 * 2002 by Theodore Ts'o.
12 *
13 * %Begin-Header%
14 * This file may be redistributed under the terms of the GNU Public
15 * License.
16 * %End-Header%
17 */
18
19#include <stdio.h>
20#include <string.h>
21#if HAVE_UNISTD_H
22#include <unistd.h>
23#endif
24#if HAVE_ERRNO_H
25#include <errno.h>
26#endif
27#include <fcntl.h>
28#include <time.h>
29#ifdef __linux__
30#include <sys/utsname.h>
31#endif
32#if HAVE_SYS_STAT_H
33#include <sys/stat.h>
34#endif
35#if HAVE_SYS_TYPES_H
36#include <sys/types.h>
37#endif
38#include <sys/resource.h>
39
40#include "ext2_fs.h"
41#include "ext2fs.h"
42
43/*
44 * For checking structure magic numbers...
45 */
46
47#define EXT2_CHECK_MAGIC(struct, code) \
48 if ((struct)->magic != (code)) return (code)
49
50struct unix_cache {
51 char *buf;
52 unsigned long block;
53 int access_time;
54 unsigned dirty:1;
55 unsigned in_use:1;
56};
57
58#define CACHE_SIZE 8
59#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */
60#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */
61
62struct unix_private_data {
63 int magic;
64 int dev;
65 int flags;
66 int access_time;
67 ext2_loff_t offset;
68 struct unix_cache cache[CACHE_SIZE];
69};
70
71static errcode_t unix_open(const char *name, int flags, io_channel *channel);
72static errcode_t unix_close(io_channel channel);
73static errcode_t unix_set_blksize(io_channel channel, int blksize);
74static errcode_t unix_read_blk(io_channel channel, unsigned long block,
75 int count, void *data);
76static errcode_t unix_write_blk(io_channel channel, unsigned long block,
77 int count, const void *data);
78static errcode_t unix_flush(io_channel channel);
79static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
80 int size, const void *data);
81static errcode_t unix_set_option(io_channel channel, const char *option,
82 const char *arg);
83
84static void reuse_cache(io_channel channel, struct unix_private_data *data,
85 struct unix_cache *cache, unsigned long block);
86
87/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
88 * does not know buffered block devices - everything is raw. */
89#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
90#define NEED_BOUNCE_BUFFER
91#else
92#undef NEED_BOUNCE_BUFFER
93#endif
94
95static struct struct_io_manager struct_unix_manager = {
96 EXT2_ET_MAGIC_IO_MANAGER,
97 "Unix I/O Manager",
98 unix_open,
99 unix_close,
100 unix_set_blksize,
101 unix_read_blk,
102 unix_write_blk,
103 unix_flush,
104#ifdef NEED_BOUNCE_BUFFER
105 0,
106#else
107 unix_write_byte,
108#endif
109 unix_set_option
110};
111
112io_manager unix_io_manager = &struct_unix_manager;
113
114/*
115 * Here are the raw I/O functions
116 */
117#ifndef NEED_BOUNCE_BUFFER
118static errcode_t raw_read_blk(io_channel channel,
119 struct unix_private_data *data,
120 unsigned long block,
121 int count, void *buf)
122{
123 errcode_t retval;
124 ssize_t size;
125 ext2_loff_t location;
126 int actual = 0;
127
128 size = (count < 0) ? -count : count * channel->block_size;
129 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
130 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
131 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
132 goto error_out;
133 }
134 actual = read(data->dev, buf, size);
135 if (actual != size) {
136 if (actual < 0)
137 actual = 0;
138 retval = EXT2_ET_SHORT_READ;
139 goto error_out;
140 }
141 return 0;
142
143error_out:
144 memset((char *) buf+actual, 0, size-actual);
145 if (channel->read_error)
146 retval = (channel->read_error)(channel, block, count, buf,
147 size, actual, retval);
148 return retval;
149}
150#else /* NEED_BOUNCE_BUFFER */
151/*
152 * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
153 */
154static errcode_t raw_read_blk(io_channel channel,
155 struct unix_private_data *data,
156 unsigned long block,
157 int count, void *buf)
158{
159 errcode_t retval;
160 size_t size, alignsize, fragment;
161 ext2_loff_t location;
162 int total = 0, actual;
163#define BLOCKALIGN 512
164 char sector[BLOCKALIGN];
165
166 size = (count < 0) ? -count : count * channel->block_size;
167 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
168#ifdef DEBUG
169 printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
170 count, size, block, channel->block_size, location);
171#endif
172 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
173 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
174 goto error_out;
175 }
176 fragment = size % BLOCKALIGN;
177 alignsize = size - fragment;
178 if (alignsize) {
179 actual = read(data->dev, buf, alignsize);
180 if (actual != alignsize)
181 goto short_read;
182 }
183 if (fragment) {
184 actual = read(data->dev, sector, BLOCKALIGN);
185 if (actual != BLOCKALIGN)
186 goto short_read;
187 memcpy(buf+alignsize, sector, fragment);
188 }
189 return 0;
190
191short_read:
192 if (actual>0)
193 total += actual;
194 retval = EXT2_ET_SHORT_READ;
195
196error_out:
197 memset((char *) buf+total, 0, size-actual);
198 if (channel->read_error)
199 retval = (channel->read_error)(channel, block, count, buf,
200 size, actual, retval);
201 return retval;
202}
203#endif
204
205static errcode_t raw_write_blk(io_channel channel,
206 struct unix_private_data *data,
207 unsigned long block,
208 int count, const void *buf)
209{
210 ssize_t size;
211 ext2_loff_t location;
212 int actual = 0;
213 errcode_t retval;
214
215 if (count == 1)
216 size = channel->block_size;
217 else {
218 if (count < 0)
219 size = -count;
220 else
221 size = count * channel->block_size;
222 }
223
224 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
225 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
226 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
227 goto error_out;
228 }
229
230 actual = write(data->dev, buf, size);
231 if (actual != size) {
232 retval = EXT2_ET_SHORT_WRITE;
233 goto error_out;
234 }
235 return 0;
236
237error_out:
238 if (channel->write_error)
239 retval = (channel->write_error)(channel, block, count, buf,
240 size, actual, retval);
241 return retval;
242}
243
244
245/*
246 * Here we implement the cache functions
247 */
248
249/* Allocate the cache buffers */
250static errcode_t alloc_cache(io_channel channel,
251 struct unix_private_data *data)
252{
253 errcode_t retval;
254 struct unix_cache *cache;
255 int i;
256
257 data->access_time = 0;
258 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
259 cache->block = 0;
260 cache->access_time = 0;
261 cache->dirty = 0;
262 cache->in_use = 0;
263 if ((retval = ext2fs_get_mem(channel->block_size,
264 &cache->buf)))
265 return retval;
266 }
267 return 0;
268}
269
270/* Free the cache buffers */
271static void free_cache(struct unix_private_data *data)
272{
273 struct unix_cache *cache;
274 int i;
275
276 data->access_time = 0;
277 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
278 cache->block = 0;
279 cache->access_time = 0;
280 cache->dirty = 0;
281 cache->in_use = 0;
282 ext2fs_free_mem(&cache->buf);
283 cache->buf = 0;
284 }
285}
286
287#ifndef NO_IO_CACHE
288/*
289 * Try to find a block in the cache. If the block is not found, and
290 * eldest is a non-zero pointer, then fill in eldest with the cache
291 * entry to that should be reused.
292 */
293static struct unix_cache *find_cached_block(struct unix_private_data *data,
294 unsigned long block,
295 struct unix_cache **eldest)
296{
297 struct unix_cache *cache, *unused_cache, *oldest_cache;
298 int i;
299
300 unused_cache = oldest_cache = 0;
301 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
302 if (!cache->in_use) {
303 if (!unused_cache)
304 unused_cache = cache;
305 continue;
306 }
307 if (cache->block == block) {
308 cache->access_time = ++data->access_time;
309 return cache;
310 }
311 if (!oldest_cache ||
312 (cache->access_time < oldest_cache->access_time))
313 oldest_cache = cache;
314 }
315 if (eldest)
316 *eldest = (unused_cache) ? unused_cache : oldest_cache;
317 return 0;
318}
319
320/*
321 * Reuse a particular cache entry for another block.
322 */
323static void reuse_cache(io_channel channel, struct unix_private_data *data,
324 struct unix_cache *cache, unsigned long block)
325{
326 if (cache->dirty && cache->in_use)
327 raw_write_blk(channel, data, cache->block, 1, cache->buf);
328
329 cache->in_use = 1;
330 cache->dirty = 0;
331 cache->block = block;
332 cache->access_time = ++data->access_time;
333}
334
335/*
336 * Flush all of the blocks in the cache
337 */
338static errcode_t flush_cached_blocks(io_channel channel,
339 struct unix_private_data *data,
340 int invalidate)
341
342{
343 struct unix_cache *cache;
344 errcode_t retval, retval2;
345 int i;
346
347 retval2 = 0;
348 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
349 if (!cache->in_use)
350 continue;
351
352 if (invalidate)
353 cache->in_use = 0;
354
355 if (!cache->dirty)
356 continue;
357
358 retval = raw_write_blk(channel, data,
359 cache->block, 1, cache->buf);
360 if (retval)
361 retval2 = retval;
362 else
363 cache->dirty = 0;
364 }
365 return retval2;
366}
367#endif /* NO_IO_CACHE */
368
369static errcode_t unix_open(const char *name, int flags, io_channel *channel)
370{
371 io_channel io = NULL;
372 struct unix_private_data *data = NULL;
373 errcode_t retval;
374 int open_flags;
375 struct stat st;
376#ifdef __linux__
377 struct utsname ut;
378#endif
379
380 if (name == 0)
381 return EXT2_ET_BAD_DEVICE_NAME;
382 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
383 if (retval)
384 return retval;
385 memset(io, 0, sizeof(struct struct_io_channel));
386 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
387 retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
388 if (retval)
389 goto cleanup;
390
391 io->manager = unix_io_manager;
392 retval = ext2fs_get_mem(strlen(name)+1, &io->name);
393 if (retval)
394 goto cleanup;
395
396 strcpy(io->name, name);
397 io->private_data = data;
398 io->block_size = 1024;
399 io->read_error = 0;
400 io->write_error = 0;
401 io->refcount = 1;
402
403 memset(data, 0, sizeof(struct unix_private_data));
404 data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
405
406 if ((retval = alloc_cache(io, data)))
407 goto cleanup;
408
409 open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
410#ifdef CONFIG_LFS
411 data->dev = open64(io->name, open_flags);
412#else
413 data->dev = open(io->name, open_flags);
414#endif
415 if (data->dev < 0) {
416 retval = errno;
417 goto cleanup;
418 }
419
420#ifdef __linux__
421#undef RLIM_INFINITY
422#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
423#define RLIM_INFINITY ((unsigned long)(~0UL>>1))
424#else
425#define RLIM_INFINITY (~0UL)
426#endif
427 /*
428 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
429 * block devices are wrongly getting hit by the filesize
430 * limit. This workaround isn't perfect, since it won't work
431 * if glibc wasn't built against 2.2 header files. (Sigh.)
432 *
433 */
434 if ((flags & IO_FLAG_RW) &&
435 (uname(&ut) == 0) &&
436 ((ut.release[0] == '2') && (ut.release[1] == '.') &&
437 (ut.release[2] == '4') && (ut.release[3] == '.') &&
438 (ut.release[4] == '1') && (ut.release[5] >= '0') &&
439 (ut.release[5] < '8')) &&
440 (fstat(data->dev, &st) == 0) &&
441 (S_ISBLK(st.st_mode))) {
442 struct rlimit rlim;
443
444 rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
445 setrlimit(RLIMIT_FSIZE, &rlim);
446 getrlimit(RLIMIT_FSIZE, &rlim);
447 if (((unsigned long) rlim.rlim_cur) <
448 ((unsigned long) rlim.rlim_max)) {
449 rlim.rlim_cur = rlim.rlim_max;
450 setrlimit(RLIMIT_FSIZE, &rlim);
451 }
452 }
453#endif
454 *channel = io;
455 return 0;
456
457cleanup:
458 if (data) {
459 free_cache(data);
460 ext2fs_free_mem(&data);
461 }
462 ext2fs_free_mem(&io);
463 return retval;
464}
465
466static errcode_t unix_close(io_channel channel)
467{
468 struct unix_private_data *data;
469 errcode_t retval = 0;
470
471 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
472 data = (struct unix_private_data *) channel->private_data;
473 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
474
475 if (--channel->refcount > 0)
476 return 0;
477
478#ifndef NO_IO_CACHE
479 retval = flush_cached_blocks(channel, data, 0);
480#endif
481
482 if (close(data->dev) < 0)
483 retval = errno;
484 free_cache(data);
485
486 ext2fs_free_mem(&channel->private_data);
487 ext2fs_free_mem(&channel->name);
488 ext2fs_free_mem(&channel);
489 return retval;
490}
491
492static errcode_t unix_set_blksize(io_channel channel, int blksize)
493{
494 struct unix_private_data *data;
495 errcode_t retval;
496
497 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
498 data = (struct unix_private_data *) channel->private_data;
499 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
500
501 if (channel->block_size != blksize) {
502#ifndef NO_IO_CACHE
503 if ((retval = flush_cached_blocks(channel, data, 0)))
504 return retval;
505#endif
506
507 channel->block_size = blksize;
508 free_cache(data);
509 if ((retval = alloc_cache(channel, data)))
510 return retval;
511 }
512 return 0;
513}
514
515
516static errcode_t unix_read_blk(io_channel channel, unsigned long block,
517 int count, void *buf)
518{
519 struct unix_private_data *data;
520 struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
521 errcode_t retval;
522 char *cp;
523 int i, j;
524
525 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
526 data = (struct unix_private_data *) channel->private_data;
527 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
528
529#ifdef NO_IO_CACHE
530 return raw_read_blk(channel, data, block, count, buf);
531#else
532 /*
533 * If we're doing an odd-sized read or a very large read,
534 * flush out the cache and then do a direct read.
535 */
536 if (count < 0 || count > WRITE_DIRECT_SIZE) {
537 if ((retval = flush_cached_blocks(channel, data, 0)))
538 return retval;
539 return raw_read_blk(channel, data, block, count, buf);
540 }
541
542 cp = buf;
543 while (count > 0) {
544 /* If it's in the cache, use it! */
545 if ((cache = find_cached_block(data, block, &reuse[0]))) {
546#ifdef DEBUG
547 printf("Using cached block %d\n", block);
548#endif
549 memcpy(cp, cache->buf, channel->block_size);
550 count--;
551 block++;
552 cp += channel->block_size;
553 continue;
554 }
555 /*
556 * Find the number of uncached blocks so we can do a
557 * single read request
558 */
559 for (i=1; i < count; i++)
560 if (find_cached_block(data, block+i, &reuse[i]))
561 break;
562#ifdef DEBUG
563 printf("Reading %d blocks starting at %d\n", i, block);
564#endif
565 if ((retval = raw_read_blk(channel, data, block, i, cp)))
566 return retval;
567
568 /* Save the results in the cache */
569 for (j=0; j < i; j++) {
570 count--;
571 cache = reuse[j];
572 reuse_cache(channel, data, cache, block++);
573 memcpy(cache->buf, cp, channel->block_size);
574 cp += channel->block_size;
575 }
576 }
577 return 0;
578#endif /* NO_IO_CACHE */
579}
580
581static errcode_t unix_write_blk(io_channel channel, unsigned long block,
582 int count, const void *buf)
583{
584 struct unix_private_data *data;
585 struct unix_cache *cache, *reuse;
586 errcode_t retval = 0;
587 const char *cp;
588 int writethrough;
589
590 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
591 data = (struct unix_private_data *) channel->private_data;
592 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
593
594#ifdef NO_IO_CACHE
595 return raw_write_blk(channel, data, block, count, buf);
596#else
597 /*
598 * If we're doing an odd-sized write or a very large write,
599 * flush out the cache completely and then do a direct write.
600 */
601 if (count < 0 || count > WRITE_DIRECT_SIZE) {
602 if ((retval = flush_cached_blocks(channel, data, 1)))
603 return retval;
604 return raw_write_blk(channel, data, block, count, buf);
605 }
606
607 /*
608 * For a moderate-sized multi-block write, first force a write
609 * if we're in write-through cache mode, and then fill the
610 * cache with the blocks.
611 */
612 writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
613 if (writethrough)
614 retval = raw_write_blk(channel, data, block, count, buf);
615
616 cp = buf;
617 while (count > 0) {
618 cache = find_cached_block(data, block, &reuse);
619 if (!cache) {
620 cache = reuse;
621 reuse_cache(channel, data, cache, block);
622 }
623 memcpy(cache->buf, cp, channel->block_size);
624 cache->dirty = !writethrough;
625 count--;
626 block++;
627 cp += channel->block_size;
628 }
629 return retval;
630#endif /* NO_IO_CACHE */
631}
632
633static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
634 int size, const void *buf)
635{
636 struct unix_private_data *data;
637 errcode_t retval = 0;
638 ssize_t actual;
639
640 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
641 data = (struct unix_private_data *) channel->private_data;
642 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
643
644#ifndef NO_IO_CACHE
645 /*
646 * Flush out the cache completely
647 */
648 if ((retval = flush_cached_blocks(channel, data, 1)))
649 return retval;
650#endif
651
652 if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
653 return errno;
654
655 actual = write(data->dev, buf, size);
656 if (actual != size)
657 return EXT2_ET_SHORT_WRITE;
658
659 return 0;
660}
661
662/*
663 * Flush data buffers to disk.
664 */
665static errcode_t unix_flush(io_channel channel)
666{
667 struct unix_private_data *data;
668 errcode_t retval = 0;
669
670 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
671 data = (struct unix_private_data *) channel->private_data;
672 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
673
674#ifndef NO_IO_CACHE
675 retval = flush_cached_blocks(channel, data, 0);
676#endif
677 fsync(data->dev);
678 return retval;
679}
680
681static errcode_t unix_set_option(io_channel channel, const char *option,
682 const char *arg)
683{
684 struct unix_private_data *data;
685 unsigned long tmp;
686 char *end;
687
688 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
689 data = (struct unix_private_data *) channel->private_data;
690 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
691
692 if (!strcmp(option, "offset")) {
693 if (!arg)
694 return EXT2_ET_INVALID_ARGUMENT;
695
696 tmp = strtoul(arg, &end, 0);
697 if (*end)
698 return EXT2_ET_INVALID_ARGUMENT;
699 data->offset = tmp;
700 return 0;
701 }
702 return EXT2_ET_INVALID_ARGUMENT;
703}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c b/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c
new file mode 100644
index 000000000..83ac2713e
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c
@@ -0,0 +1,100 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * unlink.c --- delete links in a ext2fs directory
4 *
5 * Copyright (C) 1993, 1994, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22struct link_struct {
23 const char *name;
24 int namelen;
25 ext2_ino_t inode;
26 int flags;
27 struct ext2_dir_entry *prev;
28 int done;
29};
30
31#ifdef __TURBOC__
32# pragma argsused
33#endif
34static int unlink_proc(struct ext2_dir_entry *dirent,
35 int offset EXT2FS_ATTR((unused)),
36 int blocksize EXT2FS_ATTR((unused)),
37 char *buf EXT2FS_ATTR((unused)),
38 void *priv_data)
39{
40 struct link_struct *ls = (struct link_struct *) priv_data;
41 struct ext2_dir_entry *prev;
42
43 prev = ls->prev;
44 ls->prev = dirent;
45
46 if (ls->name) {
47 if ((dirent->name_len & 0xFF) != ls->namelen)
48 return 0;
49 if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF))
50 return 0;
51 }
52 if (ls->inode) {
53 if (dirent->inode != ls->inode)
54 return 0;
55 } else {
56 if (!dirent->inode)
57 return 0;
58 }
59
60 if (prev)
61 prev->rec_len += dirent->rec_len;
62 else
63 dirent->inode = 0;
64 ls->done++;
65 return DIRENT_ABORT|DIRENT_CHANGED;
66}
67
68#ifdef __TURBOC__
69 #pragma argsused
70#endif
71errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir,
72 const char *name, ext2_ino_t ino,
73 int flags EXT2FS_ATTR((unused)))
74{
75 errcode_t retval;
76 struct link_struct ls;
77
78 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
79
80 if (!name && !ino)
81 return EXT2_ET_INVALID_ARGUMENT;
82
83 if (!(fs->flags & EXT2_FLAG_RW))
84 return EXT2_ET_RO_FILSYS;
85
86 ls.name = name;
87 ls.namelen = name ? strlen(name) : 0;
88 ls.inode = ino;
89 ls.flags = 0;
90 ls.done = 0;
91 ls.prev = 0;
92
93 retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
94 0, unlink_proc, &ls);
95 if (retval)
96 return retval;
97
98 return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
99}
100
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/valid_blk.c b/e2fsprogs/old_e2fsprogs/ext2fs/valid_blk.c
new file mode 100644
index 000000000..8ed77ae2a
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/valid_blk.c
@@ -0,0 +1,57 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * valid_blk.c --- does the inode have valid blocks?
4 *
5 * Copyright 1997 by Theodore Ts'o
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 *
12 */
13
14#include <stdio.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <string.h>
19#include <time.h>
20
21#include "ext2_fs.h"
22#include "ext2fs.h"
23
24/*
25 * This function returns 1 if the inode's block entries actually
26 * contain block entries.
27 */
28int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
29{
30 /*
31 * Only directories, regular files, and some symbolic links
32 * have valid block entries.
33 */
34 if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) &&
35 !LINUX_S_ISLNK(inode->i_mode))
36 return 0;
37
38 /*
39 * If the symbolic link is a "fast symlink", then the symlink
40 * target is stored in the block entries.
41 */
42 if (LINUX_S_ISLNK (inode->i_mode)) {
43 if (inode->i_file_acl == 0) {
44 /* With no EA block, we can rely on i_blocks */
45 if (inode->i_blocks == 0)
46 return 0;
47 } else {
48 /* With an EA block, life gets more tricky */
49 if (inode->i_size >= EXT2_N_BLOCKS*4)
50 return 1; /* definitely using i_block[] */
51 if (inode->i_size > 4 && inode->i_block[1] == 0)
52 return 1; /* definitely using i_block[] */
53 return 0; /* Probably a fast symlink */
54 }
55 }
56 return 1;
57}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/version.c b/e2fsprogs/old_e2fsprogs/ext2fs/version.c
new file mode 100644
index 000000000..d2981e867
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/version.c
@@ -0,0 +1,51 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * version.c --- Return the version of the ext2 library
4 *
5 * Copyright (C) 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#if HAVE_UNISTD_H
14#include <unistd.h>
15#endif
16#include <string.h>
17#include <stdio.h>
18#include <ctype.h>
19
20#include "ext2_fs.h"
21#include "ext2fs.h"
22
23static const char *lib_version = E2FSPROGS_VERSION;
24static const char *lib_date = E2FSPROGS_DATE;
25
26int ext2fs_parse_version_string(const char *ver_string)
27{
28 const char *cp;
29 int version = 0;
30
31 for (cp = ver_string; *cp; cp++) {
32 if (*cp == '.')
33 continue;
34 if (!isdigit(*cp))
35 break;
36 version = (version * 10) + (*cp - '0');
37 }
38 return version;
39}
40
41
42int ext2fs_get_library_version(const char **ver_string,
43 const char **date_string)
44{
45 if (ver_string)
46 *ver_string = lib_version;
47 if (date_string)
48 *date_string = lib_date;
49
50 return ext2fs_parse_version_string(lib_version);
51}
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/write_bb_file.c b/e2fsprogs/old_e2fsprogs/ext2fs/write_bb_file.c
new file mode 100644
index 000000000..5b19eefa0
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/write_bb_file.c
@@ -0,0 +1,35 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * write_bb_file.c --- write a list of bad blocks to a FILE *
4 *
5 * Copyright (C) 1994, 1995 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14
15#include "ext2_fs.h"
16#include "ext2fs.h"
17
18errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
19 unsigned int flags EXT2FS_ATTR((unused)),
20 FILE *f)
21{
22 badblocks_iterate bb_iter;
23 blk_t blk;
24 errcode_t retval;
25
26 retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
27 if (retval)
28 return retval;
29
30 while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
31 fprintf(f, "%d\n", blk);
32 }
33 ext2fs_badblocks_list_iterate_end(bb_iter);
34 return 0;
35}
diff --git a/e2fsprogs/old_e2fsprogs/fsck.c b/e2fsprogs/old_e2fsprogs/fsck.c
new file mode 100644
index 000000000..da66250f1
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/fsck.c
@@ -0,0 +1,1392 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * pfsck --- A generic, parallelizing front-end for the fsck program.
4 * It will automatically try to run fsck programs in parallel if the
5 * devices are on separate spindles. It is based on the same ideas as
6 * the generic front end for fsck by David Engel and Fred van Kempen,
7 * but it has been completely rewritten from scratch to support
8 * parallel execution.
9 *
10 * Written by Theodore Ts'o, <tytso@mit.edu>
11 *
12 * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994:
13 * o Changed -t fstype to behave like with mount when -A (all file
14 * systems) or -M (like mount) is specified.
15 * o fsck looks if it can find the fsck.type program to decide
16 * if it should ignore the fs type. This way more fsck programs
17 * can be added without changing this front-end.
18 * o -R flag skip root file system.
19 *
20 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
21 * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
22 *
23 * %Begin-Header%
24 * This file may be redistributed under the terms of the GNU Public
25 * License.
26 * %End-Header%
27 */
28
29#include <sys/types.h>
30#include <sys/wait.h>
31#include <sys/stat.h>
32#include <limits.h>
33#include <stdio.h>
34#include <ctype.h>
35#include <string.h>
36#include <time.h>
37#include <stdlib.h>
38#include <errno.h>
39#include <paths.h>
40#include <unistd.h>
41#include <errno.h>
42#include <signal.h>
43
44#include "fsck.h"
45#include "blkid/blkid.h"
46
47#include "e2fsbb.h"
48
49#include "busybox.h"
50
51#ifndef _PATH_MNTTAB
52#define _PATH_MNTTAB "/etc/fstab"
53#endif
54
55/*
56 * fsck.h
57 */
58
59#ifndef DEFAULT_FSTYPE
60#define DEFAULT_FSTYPE "ext2"
61#endif
62
63#define MAX_DEVICES 32
64#define MAX_ARGS 32
65
66/*
67 * Internal structure for mount tabel entries.
68 */
69
70struct fs_info {
71 char *device;
72 char *mountpt;
73 char *type;
74 char *opts;
75 int freq;
76 int passno;
77 int flags;
78 struct fs_info *next;
79};
80
81#define FLAG_DONE 1
82#define FLAG_PROGRESS 2
83
84/*
85 * Structure to allow exit codes to be stored
86 */
87struct fsck_instance {
88 int pid;
89 int flags;
90 int exit_status;
91 time_t start_time;
92 char * prog;
93 char * type;
94 char * device;
95 char * base_device;
96 struct fsck_instance *next;
97};
98
99/*
100 * base_device.c
101 *
102 * Return the "base device" given a particular device; this is used to
103 * assure that we only fsck one partition on a particular drive at any
104 * one time. Otherwise, the disk heads will be seeking all over the
105 * place. If the base device cannot be determined, return NULL.
106 *
107 * The base_device() function returns an allocated string which must
108 * be freed.
109 *
110 */
111
112
113#ifdef CONFIG_FEATURE_DEVFS
114/*
115 * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
116 * pathames.
117 */
118static const char * const devfs_hier[] = {
119 "host", "bus", "target", "lun", 0
120};
121#endif
122
123static char *base_device(const char *device)
124{
125 char *str, *cp;
126#ifdef CONFIG_FEATURE_DEVFS
127 const char * const *hier;
128 const char *disk;
129 int len;
130#endif
131
132 cp = str = xstrdup(device);
133
134 /* Skip over /dev/; if it's not present, give up. */
135 if (strncmp(cp, "/dev/", 5) != 0)
136 goto errout;
137 cp += 5;
138
139 /*
140 * For md devices, we treat them all as if they were all
141 * on one disk, since we don't know how to parallelize them.
142 */
143 if (cp[0] == 'm' && cp[1] == 'd') {
144 *(cp+2) = 0;
145 return str;
146 }
147
148 /* Handle DAC 960 devices */
149 if (strncmp(cp, "rd/", 3) == 0) {
150 cp += 3;
151 if (cp[0] != 'c' || cp[2] != 'd' ||
152 !isdigit(cp[1]) || !isdigit(cp[3]))
153 goto errout;
154 *(cp+4) = 0;
155 return str;
156 }
157
158 /* Now let's handle /dev/hd* and /dev/sd* devices.... */
159 if ((cp[0] == 'h' || cp[0] == 's') && (cp[1] == 'd')) {
160 cp += 2;
161 /* If there's a single number after /dev/hd, skip it */
162 if (isdigit(*cp))
163 cp++;
164 /* What follows must be an alpha char, or give up */
165 if (!isalpha(*cp))
166 goto errout;
167 *(cp + 1) = 0;
168 return str;
169 }
170
171#ifdef CONFIG_FEATURE_DEVFS
172 /* Now let's handle devfs (ugh) names */
173 len = 0;
174 if (strncmp(cp, "ide/", 4) == 0)
175 len = 4;
176 if (strncmp(cp, "scsi/", 5) == 0)
177 len = 5;
178 if (len) {
179 cp += len;
180 /*
181 * Now we proceed down the expected devfs hierarchy.
182 * i.e., .../host1/bus2/target3/lun4/...
183 * If we don't find the expected token, followed by
184 * some number of digits at each level, abort.
185 */
186 for (hier = devfs_hier; *hier; hier++) {
187 len = strlen(*hier);
188 if (strncmp(cp, *hier, len) != 0)
189 goto errout;
190 cp += len;
191 while (*cp != '/' && *cp != 0) {
192 if (!isdigit(*cp))
193 goto errout;
194 cp++;
195 }
196 cp++;
197 }
198 *(cp - 1) = 0;
199 return str;
200 }
201
202 /* Now handle devfs /dev/disc or /dev/disk names */
203 disk = 0;
204 if (strncmp(cp, "discs/", 6) == 0)
205 disk = "disc";
206 else if (strncmp(cp, "disks/", 6) == 0)
207 disk = "disk";
208 if (disk) {
209 cp += 6;
210 if (strncmp(cp, disk, 4) != 0)
211 goto errout;
212 cp += 4;
213 while (*cp != '/' && *cp != 0) {
214 if (!isdigit(*cp))
215 goto errout;
216 cp++;
217 }
218 *cp = 0;
219 return str;
220 }
221#endif
222
223errout:
224 free(str);
225 return NULL;
226}
227
228
229static const char * const ignored_types[] = {
230 "ignore",
231 "iso9660",
232 "nfs",
233 "proc",
234 "sw",
235 "swap",
236 "tmpfs",
237 "devpts",
238 NULL
239};
240
241static const char * const really_wanted[] = {
242 "minix",
243 "ext2",
244 "ext3",
245 "jfs",
246 "reiserfs",
247 "xiafs",
248 "xfs",
249 NULL
250};
251
252#define BASE_MD "/dev/md"
253
254/*
255 * Global variables for options
256 */
257static char *devices[MAX_DEVICES];
258static char *args[MAX_ARGS];
259static int num_devices, num_args;
260
261static int verbose;
262static int doall;
263static int noexecute;
264static int serialize;
265static int skip_root;
266static int like_mount;
267static int notitle;
268static int parallel_root;
269static int progress;
270static int progress_fd;
271static int force_all_parallel;
272static int num_running;
273static int max_running;
274static volatile int cancel_requested;
275static int kill_sent;
276static char *fstype;
277static struct fs_info *filesys_info, *filesys_last;
278static struct fsck_instance *instance_list;
279static char *fsck_path;
280static blkid_cache cache;
281
282static char *string_copy(const char *s)
283{
284 char *ret;
285
286 if (!s)
287 return 0;
288 ret = strdup(s);
289 return ret;
290}
291
292static int string_to_int(const char *s)
293{
294 long l;
295 char *p;
296
297 l = strtol(s, &p, 0);
298 if (*p || l == LONG_MIN || l == LONG_MAX || l < 0 || l > INT_MAX)
299 return -1;
300 else
301 return (int) l;
302}
303
304static char *skip_over_blank(char *cp)
305{
306 while (*cp && isspace(*cp))
307 cp++;
308 return cp;
309}
310
311static char *skip_over_word(char *cp)
312{
313 while (*cp && !isspace(*cp))
314 cp++;
315 return cp;
316}
317
318static void strip_line(char *line)
319{
320 char *p;
321
322 while (*line) {
323 p = line + strlen(line) - 1;
324 if ((*p == '\n') || (*p == '\r'))
325 *p = 0;
326 else
327 break;
328 }
329}
330
331static char *parse_word(char **buf)
332{
333 char *word, *next;
334
335 word = *buf;
336 if (*word == 0)
337 return 0;
338
339 word = skip_over_blank(word);
340 next = skip_over_word(word);
341 if (*next)
342 *next++ = 0;
343 *buf = next;
344 return word;
345}
346
347static void parse_escape(char *word)
348{
349 char *q, c;
350 const char *p;
351
352 if (!word)
353 return;
354
355 for (p = q = word; *p; q++) {
356 c = *p++;
357 if (c != '\\') {
358 *q = c;
359 } else {
360 *q = bb_process_escape_sequence(&p);
361 }
362 }
363 *q = 0;
364}
365
366static void free_instance(struct fsck_instance *i)
367{
368 if (i->prog)
369 free(i->prog);
370 if (i->device)
371 free(i->device);
372 if (i->base_device)
373 free(i->base_device);
374 free(i);
375 return;
376}
377
378static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
379 const char *type, const char *opts,
380 int freq, int passno)
381{
382 struct fs_info *fs;
383
384 if (!(fs = malloc(sizeof(struct fs_info))))
385 return NULL;
386
387 fs->device = string_copy(device);
388 fs->mountpt = string_copy(mntpnt);
389 fs->type = string_copy(type);
390 fs->opts = string_copy(opts ? opts : "");
391 fs->freq = freq;
392 fs->passno = passno;
393 fs->flags = 0;
394 fs->next = NULL;
395
396 if (!filesys_info)
397 filesys_info = fs;
398 else
399 filesys_last->next = fs;
400 filesys_last = fs;
401
402 return fs;
403}
404
405
406
407static int parse_fstab_line(char *line, struct fs_info **ret_fs)
408{
409 char *dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
410 struct fs_info *fs;
411
412 *ret_fs = 0;
413 strip_line(line);
414 if ((cp = strchr(line, '#')))
415 *cp = 0; /* Ignore everything after the comment char */
416 cp = line;
417
418 device = parse_word(&cp);
419 mntpnt = parse_word(&cp);
420 type = parse_word(&cp);
421 opts = parse_word(&cp);
422 freq = parse_word(&cp);
423 passno = parse_word(&cp);
424
425 if (!device)
426 return 0; /* Allow blank lines */
427
428 if (!mntpnt || !type)
429 return -1;
430
431 parse_escape(device);
432 parse_escape(mntpnt);
433 parse_escape(type);
434 parse_escape(opts);
435 parse_escape(freq);
436 parse_escape(passno);
437
438 dev = blkid_get_devname(cache, device, NULL);
439 if (dev)
440 device = dev;
441
442 if (strchr(type, ','))
443 type = 0;
444
445 fs = create_fs_device(device, mntpnt, type ? type : "auto", opts,
446 freq ? atoi(freq) : -1,
447 passno ? atoi(passno) : -1);
448 if (dev)
449 free(dev);
450
451 if (!fs)
452 return -1;
453 *ret_fs = fs;
454 return 0;
455}
456
457static void interpret_type(struct fs_info *fs)
458{
459 char *t;
460
461 if (strcmp(fs->type, "auto") != 0)
462 return;
463 t = blkid_get_tag_value(cache, "TYPE", fs->device);
464 if (t) {
465 free(fs->type);
466 fs->type = t;
467 }
468}
469
470/*
471 * Load the filesystem database from /etc/fstab
472 */
473static void load_fs_info(const char *filename)
474{
475 FILE *f;
476 char buf[1024];
477 int lineno = 0;
478 int old_fstab = 1;
479 struct fs_info *fs;
480
481 if ((f = fopen(filename, "r")) == NULL) {
482 bb_perror_msg("WARNING: cannot open %s", filename);
483 return;
484 }
485 while (!feof(f)) {
486 lineno++;
487 if (!fgets(buf, sizeof(buf), f))
488 break;
489 buf[sizeof(buf)-1] = 0;
490 if (parse_fstab_line(buf, &fs) < 0) {
491 bb_error_msg("WARNING: bad format "
492 "on line %d of %s\n", lineno, filename);
493 continue;
494 }
495 if (!fs)
496 continue;
497 if (fs->passno < 0)
498 fs->passno = 0;
499 else
500 old_fstab = 0;
501 }
502
503 fclose(f);
504
505 if (old_fstab) {
506 fputs("\007\007\007"
507 "WARNING: Your /etc/fstab does not contain the fsck passno\n"
508 " field. I will kludge around things for you, but you\n"
509 " should fix your /etc/fstab file as soon as you can.\n\n", stderr);
510
511 for (fs = filesys_info; fs; fs = fs->next) {
512 fs->passno = 1;
513 }
514 }
515}
516
517/* Lookup filesys in /etc/fstab and return the corresponding entry. */
518static struct fs_info *lookup(char *filesys)
519{
520 struct fs_info *fs;
521
522 /* No filesys name given. */
523 if (filesys == NULL)
524 return NULL;
525
526 for (fs = filesys_info; fs; fs = fs->next) {
527 if (!strcmp(filesys, fs->device) ||
528 (fs->mountpt && !strcmp(filesys, fs->mountpt)))
529 break;
530 }
531
532 return fs;
533}
534
535/* Find fsck program for a given fs type. */
536static char *find_fsck(char *type)
537{
538 char *s;
539 const char *tpl;
540 char *p = string_copy(fsck_path);
541 struct stat st;
542
543 /* Are we looking for a program or just a type? */
544 tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s");
545
546 for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
547 s = xasprintf(tpl, s, type);
548 if (stat(s, &st) == 0) break;
549 free(s);
550 }
551 free(p);
552 return s;
553}
554
555static int progress_active(void)
556{
557 struct fsck_instance *inst;
558
559 for (inst = instance_list; inst; inst = inst->next) {
560 if (inst->flags & FLAG_DONE)
561 continue;
562 if (inst->flags & FLAG_PROGRESS)
563 return 1;
564 }
565 return 0;
566}
567
568/*
569 * Execute a particular fsck program, and link it into the list of
570 * child processes we are waiting for.
571 */
572static int execute(const char *type, const char *device, const char *mntpt,
573 int interactive)
574{
575 char *s, *argv[80];
576 char *prog;
577 int argc, i;
578 struct fsck_instance *inst, *p;
579 pid_t pid;
580
581 inst = malloc(sizeof(struct fsck_instance));
582 if (!inst)
583 return ENOMEM;
584 memset(inst, 0, sizeof(struct fsck_instance));
585
586 prog = xasprintf("fsck.%s", type);
587 argv[0] = prog;
588 argc = 1;
589
590 for (i=0; i <num_args; i++)
591 argv[argc++] = string_copy(args[i]);
592
593 if (progress && !progress_active()) {
594 if ((strcmp(type, "ext2") == 0) ||
595 (strcmp(type, "ext3") == 0)) {
596 char tmp[80];
597 snprintf(tmp, 80, "-C%d", progress_fd);
598 argv[argc++] = string_copy(tmp);
599 inst->flags |= FLAG_PROGRESS;
600 }
601 }
602
603 argv[argc++] = string_copy(device);
604 argv[argc] = 0;
605
606 s = find_fsck(prog);
607 if (s == NULL) {
608 bb_error_msg("%s: not found", prog);
609 return ENOENT;
610 }
611
612 if (verbose || noexecute) {
613 printf("[%s (%d) -- %s] ", s, num_running,
614 mntpt ? mntpt : device);
615 for (i=0; i < argc; i++)
616 printf("%s ", argv[i]);
617 puts("");
618 }
619
620 /* Fork and execute the correct program. */
621 if (noexecute)
622 pid = -1;
623 else if ((pid = fork()) < 0) {
624 perror("fork");
625 return errno;
626 } else if (pid == 0) {
627 if (!interactive)
628 close(0);
629 (void) execv(s, argv);
630 bb_perror_msg_and_die("%s", argv[0]);
631 }
632
633 for (i = 1; i < argc; i++)
634 free(argv[i]);
635
636 free(s);
637 inst->pid = pid;
638 inst->prog = prog;
639 inst->type = string_copy(type);
640 inst->device = string_copy(device);
641 inst->base_device = base_device(device);
642 inst->start_time = time(0);
643 inst->next = NULL;
644
645 /*
646 * Find the end of the list, so we add the instance on at the end.
647 */
648 for (p = instance_list; p && p->next; p = p->next);
649
650 if (p)
651 p->next = inst;
652 else
653 instance_list = inst;
654
655 return 0;
656}
657
658/*
659 * Send a signal to all outstanding fsck child processes
660 */
661static int kill_all(int signum)
662{
663 struct fsck_instance *inst;
664 int n = 0;
665
666 for (inst = instance_list; inst; inst = inst->next) {
667 if (inst->flags & FLAG_DONE)
668 continue;
669 kill(inst->pid, signum);
670 n++;
671 }
672 return n;
673}
674
675/*
676 * Wait for one child process to exit; when it does, unlink it from
677 * the list of executing child processes, and return it.
678 */
679static struct fsck_instance *wait_one(int flags)
680{
681 int status;
682 int sig;
683 struct fsck_instance *inst, *inst2, *prev;
684 pid_t pid;
685
686 if (!instance_list)
687 return NULL;
688
689 if (noexecute) {
690 inst = instance_list;
691 prev = 0;
692#ifdef RANDOM_DEBUG
693 while (inst->next && (random() & 1)) {
694 prev = inst;
695 inst = inst->next;
696 }
697#endif
698 inst->exit_status = 0;
699 goto ret_inst;
700 }
701
702 /*
703 * gcc -Wall fails saving throw against stupidity
704 * (inst and prev are thought to be uninitialized variables)
705 */
706 inst = prev = NULL;
707
708 do {
709 pid = waitpid(-1, &status, flags);
710 if (cancel_requested && !kill_sent) {
711 kill_all(SIGTERM);
712 kill_sent++;
713 }
714 if ((pid == 0) && (flags & WNOHANG))
715 return NULL;
716 if (pid < 0) {
717 if ((errno == EINTR) || (errno == EAGAIN))
718 continue;
719 if (errno == ECHILD) {
720 bb_error_msg("wait: no more child process?!?");
721 return NULL;
722 }
723 perror("wait");
724 continue;
725 }
726 for (prev = 0, inst = instance_list;
727 inst;
728 prev = inst, inst = inst->next) {
729 if (inst->pid == pid)
730 break;
731 }
732 } while (!inst);
733
734 if (WIFEXITED(status))
735 status = WEXITSTATUS(status);
736 else if (WIFSIGNALED(status)) {
737 sig = WTERMSIG(status);
738 if (sig == SIGINT) {
739 status = EXIT_UNCORRECTED;
740 } else {
741 printf("Warning... %s for device %s exited "
742 "with signal %d.\n",
743 inst->prog, inst->device, sig);
744 status = EXIT_ERROR;
745 }
746 } else {
747 printf("%s %s: status is %x, should never happen.\n",
748 inst->prog, inst->device, status);
749 status = EXIT_ERROR;
750 }
751 inst->exit_status = status;
752 if (progress && (inst->flags & FLAG_PROGRESS) &&
753 !progress_active()) {
754 for (inst2 = instance_list; inst2; inst2 = inst2->next) {
755 if (inst2->flags & FLAG_DONE)
756 continue;
757 if (strcmp(inst2->type, "ext2") &&
758 strcmp(inst2->type, "ext3"))
759 continue;
760 /*
761 * If we've just started the fsck, wait a tiny
762 * bit before sending the kill, to give it
763 * time to set up the signal handler
764 */
765 if (inst2->start_time < time(0)+2) {
766 if (fork() == 0) {
767 sleep(1);
768 kill(inst2->pid, SIGUSR1);
769 exit(0);
770 }
771 } else
772 kill(inst2->pid, SIGUSR1);
773 inst2->flags |= FLAG_PROGRESS;
774 break;
775 }
776 }
777ret_inst:
778 if (prev)
779 prev->next = inst->next;
780 else
781 instance_list = inst->next;
782 if (verbose > 1)
783 printf("Finished with %s (exit status %d)\n",
784 inst->device, inst->exit_status);
785 num_running--;
786 return inst;
787}
788
789#define FLAG_WAIT_ALL 0
790#define FLAG_WAIT_ATLEAST_ONE 1
791/*
792 * Wait until all executing child processes have exited; return the
793 * logical OR of all of their exit code values.
794 */
795static int wait_many(int flags)
796{
797 struct fsck_instance *inst;
798 int global_status = 0;
799 int wait_flags = 0;
800
801 while ((inst = wait_one(wait_flags))) {
802 global_status |= inst->exit_status;
803 free_instance(inst);
804#ifdef RANDOM_DEBUG
805 if (noexecute && (flags & WNOHANG) && !(random() % 3))
806 break;
807#endif
808 if (flags & FLAG_WAIT_ATLEAST_ONE)
809 wait_flags = WNOHANG;
810 }
811 return global_status;
812}
813
814/*
815 * Run the fsck program on a particular device
816 *
817 * If the type is specified using -t, and it isn't prefixed with "no"
818 * (as in "noext2") and only one filesystem type is specified, then
819 * use that type regardless of what is specified in /etc/fstab.
820 *
821 * If the type isn't specified by the user, then use either the type
822 * specified in /etc/fstab, or DEFAULT_FSTYPE.
823 */
824static void fsck_device(struct fs_info *fs, int interactive)
825{
826 const char *type;
827 int retval;
828
829 interpret_type(fs);
830
831 if (strcmp(fs->type, "auto") != 0)
832 type = fs->type;
833 else if (fstype && strncmp(fstype, "no", 2) &&
834 strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) &&
835 !strchr(fstype, ','))
836 type = fstype;
837 else
838 type = DEFAULT_FSTYPE;
839
840 num_running++;
841 retval = execute(type, fs->device, fs->mountpt, interactive);
842 if (retval) {
843 bb_error_msg("error %d while executing fsck.%s for %s",
844 retval, type, fs->device);
845 num_running--;
846 }
847}
848
849
850/*
851 * Deal with the fsck -t argument.
852 */
853struct fs_type_compile {
854 char **list;
855 int *type;
856 int negate;
857} fs_type_compiled;
858
859#define FS_TYPE_NORMAL 0
860#define FS_TYPE_OPT 1
861#define FS_TYPE_NEGOPT 2
862
863static const char fs_type_syntax_error[] =
864"Either all or none of the filesystem types passed to -t must be prefixed\n"
865 "with 'no' or '!'.";
866
867static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp)
868{
869 char *cp, *list, *s;
870 int num = 2;
871 int negate, first_negate = 1;
872
873 if (fs_type) {
874 for (cp=fs_type; *cp; cp++) {
875 if (*cp == ',')
876 num++;
877 }
878 }
879
880 cmp->list = xzalloc(num * sizeof(char *));
881 cmp->type = xzalloc(num * sizeof(int));
882 cmp->negate = 0;
883
884 if (!fs_type)
885 return;
886
887 list = string_copy(fs_type);
888 num = 0;
889 s = strtok(list, ",");
890 while(s) {
891 negate = 0;
892 if (strncmp(s, "no", 2) == 0) {
893 s += 2;
894 negate = 1;
895 } else if (*s == '!') {
896 s++;
897 negate = 1;
898 }
899 if (strcmp(s, "loop") == 0)
900 /* loop is really short-hand for opts=loop */
901 goto loop_special_case;
902 else if (strncmp(s, "opts=", 5) == 0) {
903 s += 5;
904 loop_special_case:
905 cmp->type[num] = negate ? FS_TYPE_NEGOPT : FS_TYPE_OPT;
906 } else {
907 if (first_negate) {
908 cmp->negate = negate;
909 first_negate = 0;
910 }
911 if ((negate && !cmp->negate) ||
912 (!negate && cmp->negate)) {
913 bb_error_msg_and_die("%s", fs_type_syntax_error);
914 }
915 }
916 cmp->list[num++] = string_copy(s);
917 s = strtok(NULL, ",");
918 }
919 free(list);
920}
921
922/*
923 * This function returns true if a particular option appears in a
924 * comma-delimited options list
925 */
926static int opt_in_list(char *opt, char *optlist)
927{
928 char *list, *s;
929
930 if (!optlist)
931 return 0;
932 list = string_copy(optlist);
933
934 s = strtok(list, ",");
935 while(s) {
936 if (strcmp(s, opt) == 0) {
937 free(list);
938 return 1;
939 }
940 s = strtok(NULL, ",");
941 }
942 free(list);
943 return 0;
944}
945
946/* See if the filesystem matches the criteria given by the -t option */
947static int fs_match(struct fs_info *fs, struct fs_type_compile *cmp)
948{
949 int n, ret = 0, checked_type = 0;
950 char *cp;
951
952 if (cmp->list == 0 || cmp->list[0] == 0)
953 return 1;
954
955 for (n=0; (cp = cmp->list[n]); n++) {
956 switch (cmp->type[n]) {
957 case FS_TYPE_NORMAL:
958 checked_type++;
959 if (strcmp(cp, fs->type) == 0) {
960 ret = 1;
961 }
962 break;
963 case FS_TYPE_NEGOPT:
964 if (opt_in_list(cp, fs->opts))
965 return 0;
966 break;
967 case FS_TYPE_OPT:
968 if (!opt_in_list(cp, fs->opts))
969 return 0;
970 break;
971 }
972 }
973 if (checked_type == 0)
974 return 1;
975 return (cmp->negate ? !ret : ret);
976}
977
978/* Check if we should ignore this filesystem. */
979static int ignore(struct fs_info *fs)
980{
981 int wanted;
982 char *s;
983
984 /*
985 * If the pass number is 0, ignore it.
986 */
987 if (fs->passno == 0)
988 return 1;
989
990 interpret_type(fs);
991
992 /*
993 * If a specific fstype is specified, and it doesn't match,
994 * ignore it.
995 */
996 if (!fs_match(fs, &fs_type_compiled)) return 1;
997
998 /* Are we ignoring this type? */
999 if (index_in_str_array(ignored_types, fs->type) >= 0)
1000 return 1;
1001
1002 /* Do we really really want to check this fs? */
1003 wanted = index_in_str_array(really_wanted, fs->type) >= 0;
1004
1005 /* See if the <fsck.fs> program is available. */
1006 s = find_fsck(fs->type);
1007 if (s == NULL) {
1008 if (wanted)
1009 bb_error_msg("cannot check %s: fsck.%s not found",
1010 fs->device, fs->type);
1011 return 1;
1012 }
1013 free(s);
1014
1015 /* We can and want to check this file system type. */
1016 return 0;
1017}
1018
1019/*
1020 * Returns TRUE if a partition on the same disk is already being
1021 * checked.
1022 */
1023static int device_already_active(char *device)
1024{
1025 struct fsck_instance *inst;
1026 char *base;
1027
1028 if (force_all_parallel)
1029 return 0;
1030
1031#ifdef BASE_MD
1032 /* Don't check a soft raid disk with any other disk */
1033 if (instance_list &&
1034 (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) ||
1035 !strncmp(device, BASE_MD, sizeof(BASE_MD)-1)))
1036 return 1;
1037#endif
1038
1039 base = base_device(device);
1040 /*
1041 * If we don't know the base device, assume that the device is
1042 * already active if there are any fsck instances running.
1043 */
1044 if (!base)
1045 return (instance_list != 0);
1046 for (inst = instance_list; inst; inst = inst->next) {
1047 if (!inst->base_device || !strcmp(base, inst->base_device)) {
1048 free(base);
1049 return 1;
1050 }
1051 }
1052 free(base);
1053 return 0;
1054}
1055
1056/* Check all file systems, using the /etc/fstab table. */
1057static int check_all(void)
1058{
1059 struct fs_info *fs = NULL;
1060 int status = EXIT_OK;
1061 int not_done_yet = 1;
1062 int passno = 1;
1063 int pass_done;
1064
1065 if (verbose)
1066 fputs("Checking all file systems.\n", stdout);
1067
1068 /*
1069 * Do an initial scan over the filesystem; mark filesystems
1070 * which should be ignored as done, and resolve any "auto"
1071 * filesystem types (done as a side-effect of calling ignore()).
1072 */
1073 for (fs = filesys_info; fs; fs = fs->next) {
1074 if (ignore(fs))
1075 fs->flags |= FLAG_DONE;
1076 }
1077
1078 /*
1079 * Find and check the root filesystem.
1080 */
1081 if (!parallel_root) {
1082 for (fs = filesys_info; fs; fs = fs->next) {
1083 if (LONE_CHAR(fs->mountpt, '/'))
1084 break;
1085 }
1086 if (fs) {
1087 if (!skip_root && !ignore(fs)) {
1088 fsck_device(fs, 1);
1089 status |= wait_many(FLAG_WAIT_ALL);
1090 if (status > EXIT_NONDESTRUCT)
1091 return status;
1092 }
1093 fs->flags |= FLAG_DONE;
1094 }
1095 }
1096 /*
1097 * This is for the bone-headed user who enters the root
1098 * filesystem twice. Skip root will skep all root entries.
1099 */
1100 if (skip_root)
1101 for (fs = filesys_info; fs; fs = fs->next)
1102 if (LONE_CHAR(fs->mountpt, '/'))
1103 fs->flags |= FLAG_DONE;
1104
1105 while (not_done_yet) {
1106 not_done_yet = 0;
1107 pass_done = 1;
1108
1109 for (fs = filesys_info; fs; fs = fs->next) {
1110 if (cancel_requested)
1111 break;
1112 if (fs->flags & FLAG_DONE)
1113 continue;
1114 /*
1115 * If the filesystem's pass number is higher
1116 * than the current pass number, then we don't
1117 * do it yet.
1118 */
1119 if (fs->passno > passno) {
1120 not_done_yet++;
1121 continue;
1122 }
1123 /*
1124 * If a filesystem on a particular device has
1125 * already been spawned, then we need to defer
1126 * this to another pass.
1127 */
1128 if (device_already_active(fs->device)) {
1129 pass_done = 0;
1130 continue;
1131 }
1132 /*
1133 * Spawn off the fsck process
1134 */
1135 fsck_device(fs, serialize);
1136 fs->flags |= FLAG_DONE;
1137
1138 /*
1139 * Only do one filesystem at a time, or if we
1140 * have a limit on the number of fsck's extant
1141 * at one time, apply that limit.
1142 */
1143 if (serialize ||
1144 (max_running && (num_running >= max_running))) {
1145 pass_done = 0;
1146 break;
1147 }
1148 }
1149 if (cancel_requested)
1150 break;
1151 if (verbose > 1)
1152 printf("--waiting-- (pass %d)\n", passno);
1153 status |= wait_many(pass_done ? FLAG_WAIT_ALL :
1154 FLAG_WAIT_ATLEAST_ONE);
1155 if (pass_done) {
1156 if (verbose > 1)
1157 printf("----------------------------------\n");
1158 passno++;
1159 } else
1160 not_done_yet++;
1161 }
1162 if (cancel_requested && !kill_sent) {
1163 kill_all(SIGTERM);
1164 kill_sent++;
1165 }
1166 status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
1167 return status;
1168}
1169
1170static void signal_cancel(int sig FSCK_ATTR((unused)))
1171{
1172 cancel_requested++;
1173}
1174
1175static void PRS(int argc, char *argv[])
1176{
1177 int i, j;
1178 char *arg, *dev, *tmp = 0;
1179 char options[128];
1180 int opt = 0;
1181 int opts_for_fsck = 0;
1182 struct sigaction sa;
1183
1184 /*
1185 * Set up signal action
1186 */
1187 memset(&sa, 0, sizeof(struct sigaction));
1188 sa.sa_handler = signal_cancel;
1189 sigaction(SIGINT, &sa, 0);
1190 sigaction(SIGTERM, &sa, 0);
1191
1192 num_devices = 0;
1193 num_args = 0;
1194 instance_list = 0;
1195
1196 for (i=1; i < argc; i++) {
1197 arg = argv[i];
1198 if (!arg)
1199 continue;
1200 if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
1201 if (num_devices >= MAX_DEVICES) {
1202 bb_error_msg_and_die("too many devices");
1203 }
1204 dev = blkid_get_devname(cache, arg, NULL);
1205 if (!dev && strchr(arg, '=')) {
1206 /*
1207 * Check to see if we failed because
1208 * /proc/partitions isn't found.
1209 */
1210 if (access("/proc/partitions", R_OK) < 0) {
1211 bb_perror_msg_and_die("cannot open /proc/partitions "
1212 "(is /proc mounted?)");
1213 }
1214 /*
1215 * Check to see if this is because
1216 * we're not running as root
1217 */
1218 if (geteuid())
1219 bb_error_msg_and_die(
1220 "must be root to scan for matching filesystems: %s\n", arg);
1221 else
1222 bb_error_msg_and_die(
1223 "cannot find matching filesystem: %s", arg);
1224 }
1225 devices[num_devices++] = dev ? dev : string_copy(arg);
1226 continue;
1227 }
1228 if (arg[0] != '-' || opts_for_fsck) {
1229 if (num_args >= MAX_ARGS) {
1230 bb_error_msg_and_die("too many arguments");
1231 }
1232 args[num_args++] = string_copy(arg);
1233 continue;
1234 }
1235 for (j=1; arg[j]; j++) {
1236 if (opts_for_fsck) {
1237 options[++opt] = arg[j];
1238 continue;
1239 }
1240 switch (arg[j]) {
1241 case 'A':
1242 doall++;
1243 break;
1244 case 'C':
1245 progress++;
1246 if (arg[j+1]) {
1247 progress_fd = string_to_int(arg+j+1);
1248 if (progress_fd < 0)
1249 progress_fd = 0;
1250 else
1251 goto next_arg;
1252 } else if ((i+1) < argc
1253 && argv[i+1][0] != '-') {
1254 progress_fd = string_to_int(argv[i]);
1255 if (progress_fd < 0)
1256 progress_fd = 0;
1257 else {
1258 goto next_arg;
1259 i++;
1260 }
1261 }
1262 break;
1263 case 'V':
1264 verbose++;
1265 break;
1266 case 'N':
1267 noexecute++;
1268 break;
1269 case 'R':
1270 skip_root++;
1271 break;
1272 case 'T':
1273 notitle++;
1274 break;
1275 case 'M':
1276 like_mount++;
1277 break;
1278 case 'P':
1279 parallel_root++;
1280 break;
1281 case 's':
1282 serialize++;
1283 break;
1284 case 't':
1285 tmp = 0;
1286 if (fstype)
1287 bb_show_usage();
1288 if (arg[j+1])
1289 tmp = arg+j+1;
1290 else if ((i+1) < argc)
1291 tmp = argv[++i];
1292 else
1293 bb_show_usage();
1294 fstype = string_copy(tmp);
1295 compile_fs_type(fstype, &fs_type_compiled);
1296 goto next_arg;
1297 case '-':
1298 opts_for_fsck++;
1299 break;
1300 case '?':
1301 bb_show_usage();
1302 break;
1303 default:
1304 options[++opt] = arg[j];
1305 break;
1306 }
1307 }
1308 next_arg:
1309 if (opt) {
1310 options[0] = '-';
1311 options[++opt] = '\0';
1312 if (num_args >= MAX_ARGS) {
1313 bb_error_msg("too many arguments");
1314 }
1315 args[num_args++] = string_copy(options);
1316 opt = 0;
1317 }
1318 }
1319 if (getenv("FSCK_FORCE_ALL_PARALLEL"))
1320 force_all_parallel++;
1321 if ((tmp = getenv("FSCK_MAX_INST")))
1322 max_running = atoi(tmp);
1323}
1324
1325int fsck_main(int argc, char *argv[])
1326{
1327 int i, status = 0;
1328 int interactive = 0;
1329 const char *fstab;
1330 struct fs_info *fs;
1331
1332 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
1333 setvbuf(stderr, NULL, _IONBF, BUFSIZ);
1334
1335 blkid_get_cache(&cache, NULL);
1336 PRS(argc, argv);
1337
1338 if (!notitle)
1339 printf("fsck %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
1340
1341 fstab = getenv("FSTAB_FILE");
1342 if (!fstab)
1343 fstab = _PATH_MNTTAB;
1344 load_fs_info(fstab);
1345
1346 fsck_path = e2fs_set_sbin_path();
1347
1348 if ((num_devices == 1) || (serialize))
1349 interactive = 1;
1350
1351 /* If -A was specified ("check all"), do that! */
1352 if (doall)
1353 return check_all();
1354
1355 if (num_devices == 0) {
1356 serialize++;
1357 interactive++;
1358 return check_all();
1359 }
1360 for (i = 0 ; i < num_devices; i++) {
1361 if (cancel_requested) {
1362 if (!kill_sent) {
1363 kill_all(SIGTERM);
1364 kill_sent++;
1365 }
1366 break;
1367 }
1368 fs = lookup(devices[i]);
1369 if (!fs) {
1370 fs = create_fs_device(devices[i], 0, "auto",
1371 0, -1, -1);
1372 if (!fs)
1373 continue;
1374 }
1375 fsck_device(fs, interactive);
1376 if (serialize ||
1377 (max_running && (num_running >= max_running))) {
1378 struct fsck_instance *inst;
1379
1380 inst = wait_one(0);
1381 if (inst) {
1382 status |= inst->exit_status;
1383 free_instance(inst);
1384 }
1385 if (verbose > 1)
1386 printf("----------------------------------\n");
1387 }
1388 }
1389 status |= wait_many(FLAG_WAIT_ALL);
1390 blkid_put_cache(cache);
1391 return status;
1392}
diff --git a/e2fsprogs/old_e2fsprogs/fsck.h b/e2fsprogs/old_e2fsprogs/fsck.h
new file mode 100644
index 000000000..2ca2af7da
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/fsck.h
@@ -0,0 +1,16 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fsck.h
4 */
5
6#define FSCK_ATTR(x) __attribute__(x)
7
8#define EXIT_OK 0
9#define EXIT_NONDESTRUCT 1
10#define EXIT_DESTRUCT 2
11#define EXIT_UNCORRECTED 4
12#define EXIT_ERROR 8
13#define EXIT_USAGE 16
14#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
15
16extern char *e2fs_set_sbin_path(void);
diff --git a/e2fsprogs/old_e2fsprogs/lsattr.c b/e2fsprogs/old_e2fsprogs/lsattr.c
new file mode 100644
index 000000000..eb28fcbab
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/lsattr.c
@@ -0,0 +1,128 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * lsattr.c - List file attributes on an ext2 file system
4 *
5 * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * This file can be redistributed under the terms of the GNU General
10 * Public License
11 */
12
13/*
14 * History:
15 * 93/10/30 - Creation
16 * 93/11/13 - Replace stat() calls by lstat() to avoid loops
17 * 94/02/27 - Integrated in Ted's distribution
18 * 98/12/29 - Display version info only when -V specified (G M Sipe)
19 */
20
21#include <sys/types.h>
22#include <dirent.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <getopt.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/param.h>
31#include <sys/stat.h>
32
33#include "ext2fs/ext2_fs.h"
34#include "e2fsbb.h"
35#include "e2p/e2p.h"
36
37#define OPT_RECUR 1
38#define OPT_ALL 2
39#define OPT_DIRS_OPT 4
40#define OPT_PF_LONG 8
41#define OPT_GENERATION 16
42static int flags;
43
44static void list_attributes(const char *name)
45{
46 unsigned long fsflags;
47 unsigned long generation;
48
49 if (fgetflags(name, &fsflags) == -1)
50 goto read_err;
51 if (flags & OPT_GENERATION) {
52 if (fgetversion(name, &generation) == -1)
53 goto read_err;
54 printf("%5lu ", generation);
55 }
56
57 if (flags & OPT_PF_LONG) {
58 printf("%-28s ", name);
59 print_flags(stdout, fsflags, PFOPT_LONG);
60 puts("");
61 } else {
62 print_flags(stdout, fsflags, 0);
63 printf(" %s\n", name);
64 }
65
66 return;
67read_err:
68 bb_perror_msg("reading %s", name);
69}
70
71static int lsattr_dir_proc(const char *, struct dirent *, void *);
72
73static void lsattr_args(const char *name)
74{
75 struct stat st;
76
77 if (lstat(name, &st) == -1) {
78 bb_perror_msg("stating %s", name);
79 } else {
80 if (S_ISDIR(st.st_mode) && !(flags & OPT_DIRS_OPT))
81 iterate_on_dir(name, lsattr_dir_proc, NULL);
82 else
83 list_attributes(name);
84 }
85}
86
87static int lsattr_dir_proc(const char *dir_name, struct dirent *de,
88 void *private)
89{
90 struct stat st;
91 char *path;
92
93 path = concat_path_file(dir_name, de->d_name);
94
95 if (lstat(path, &st) == -1)
96 bb_perror_msg(path);
97 else {
98 if (de->d_name[0] != '.' || (flags & OPT_ALL)) {
99 list_attributes(path);
100 if (S_ISDIR(st.st_mode) && (flags & OPT_RECUR) &&
101 (de->d_name[0] != '.' && (de->d_name[1] != '\0' ||
102 (de->d_name[1] != '.' && de->d_name[2] != '\0')))) {
103 printf("\n%s:\n", path);
104 iterate_on_dir(path, lsattr_dir_proc, NULL);
105 puts("");
106 }
107 }
108 }
109
110 free(path);
111
112 return 0;
113}
114
115int lsattr_main(int argc, char **argv)
116{
117 int i;
118
119 flags = getopt32(argc, argv, "Radlv");
120
121 if (optind > argc - 1)
122 lsattr_args(".");
123 else
124 for (i = optind; i < argc; i++)
125 lsattr_args(argv[i]);
126
127 return EXIT_SUCCESS;
128}
diff --git a/e2fsprogs/old_e2fsprogs/mke2fs.c b/e2fsprogs/old_e2fsprogs/mke2fs.c
new file mode 100644
index 000000000..f25ecfb6c
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/mke2fs.c
@@ -0,0 +1,1336 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mke2fs.c - Make a ext2fs filesystem.
4 *
5 * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
6 * 2003, 2004, 2005 by Theodore Ts'o.
7 *
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 */
11
12/* Usage: mke2fs [options] device
13 *
14 * The device may be a block device or a image of one, but this isn't
15 * enforced (but it's not much fun on a character device :-).
16 */
17
18#include <stdio.h>
19#include <string.h>
20#include <fcntl.h>
21#include <ctype.h>
22#include <time.h>
23#include <getopt.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <mntent.h>
28#include <sys/ioctl.h>
29#include <sys/types.h>
30
31#include "e2fsbb.h"
32#include "ext2fs/ext2_fs.h"
33#include "uuid/uuid.h"
34#include "e2p/e2p.h"
35#include "ext2fs/ext2fs.h"
36#include "util.h"
37
38#define STRIDE_LENGTH 8
39
40#ifndef __sparc__
41#define ZAP_BOOTBLOCK
42#endif
43
44static const char * device_name;
45
46/* Command line options */
47static int cflag;
48static int quiet;
49static int super_only;
50static int force;
51static int noaction;
52static int journal_size;
53static int journal_flags;
54static const char *bad_blocks_filename;
55static __u32 fs_stride;
56
57static struct ext2_super_block param;
58static char *creator_os;
59static char *volume_label;
60static char *mount_dir;
61static char *journal_device = NULL;
62static int sync_kludge; /* Set using the MKE2FS_SYNC env. option */
63
64static int sys_page_size = 4096;
65static int linux_version_code = 0;
66
67static int int_log2(int arg)
68{
69 int l = 0;
70
71 arg >>= 1;
72 while (arg) {
73 l++;
74 arg >>= 1;
75 }
76 return l;
77}
78
79static int int_log10(unsigned int arg)
80{
81 int l;
82
83 for (l=0; arg ; l++)
84 arg = arg / 10;
85 return l;
86}
87
88/*
89 * This function sets the default parameters for a filesystem
90 *
91 * The type is specified by the user. The size is the maximum size
92 * (in megabytes) for which a set of parameters applies, with a size
93 * of zero meaning that it is the default parameter for the type.
94 * Note that order is important in the table below.
95 */
96#define DEF_MAX_BLOCKSIZE -1
97static const char default_str[] = "default";
98struct mke2fs_defaults {
99 const char *type;
100 int size;
101 int blocksize;
102 int inode_ratio;
103};
104
105static const struct mke2fs_defaults settings[] = {
106 { default_str, 0, 4096, 8192 },
107 { default_str, 512, 1024, 4096 },
108 { default_str, 3, 1024, 8192 },
109 { "journal", 0, 4096, 8192 },
110 { "news", 0, 4096, 4096 },
111 { "largefile", 0, 4096, 1024 * 1024 },
112 { "largefile4", 0, 4096, 4096 * 1024 },
113 { 0, 0, 0, 0},
114};
115
116static void set_fs_defaults(const char *fs_type,
117 struct ext2_super_block *super,
118 int blocksize, int sector_size,
119 int *inode_ratio)
120{
121 int megs;
122 int ratio = 0;
123 const struct mke2fs_defaults *p;
124 int use_bsize = 1024;
125
126 megs = super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024;
127 if (inode_ratio)
128 ratio = *inode_ratio;
129 if (!fs_type)
130 fs_type = default_str;
131 for (p = settings; p->type; p++) {
132 if ((strcmp(p->type, fs_type) != 0) &&
133 (strcmp(p->type, default_str) != 0))
134 continue;
135 if ((p->size != 0) && (megs > p->size))
136 continue;
137 if (ratio == 0)
138 *inode_ratio = p->inode_ratio < blocksize ?
139 blocksize : p->inode_ratio;
140 use_bsize = p->blocksize;
141 }
142 if (blocksize <= 0) {
143 if (use_bsize == DEF_MAX_BLOCKSIZE) {
144 use_bsize = sys_page_size;
145 if ((linux_version_code < (2*65536 + 6*256)) &&
146 (use_bsize > 4096))
147 use_bsize = 4096;
148 }
149 if (sector_size && use_bsize < sector_size)
150 use_bsize = sector_size;
151 if ((blocksize < 0) && (use_bsize < (-blocksize)))
152 use_bsize = -blocksize;
153 blocksize = use_bsize;
154 super->s_blocks_count /= blocksize / 1024;
155 }
156 super->s_log_frag_size = super->s_log_block_size =
157 int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
158}
159
160
161/*
162 * Helper function for read_bb_file and test_disk
163 */
164static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk)
165{
166 bb_error_msg("Bad block %u out of range; ignored", blk);
167 return;
168}
169
170/*
171 * Busybox stuff
172 */
173static void mke2fs_error_msg_and_die(int retval, const char *fmt, ...)__attribute__ ((format (printf, 2, 3)));
174static void mke2fs_error_msg_and_die(int retval, const char *fmt, ...)
175{
176 va_list ap;
177
178 if (retval) {
179 va_start(ap, fmt);
180 fprintf(stderr,"\nCould not ");
181 vfprintf(stderr, fmt, ap);
182 fprintf(stderr, "\n");
183 va_end(ap);
184 exit(EXIT_FAILURE);
185 }
186}
187
188static void mke2fs_verbose(const char *fmt, ...)__attribute__ ((format (printf, 1, 2)));
189static void mke2fs_verbose(const char *fmt, ...)
190{
191 va_list ap;
192
193 if (!quiet) {
194 va_start(ap, fmt);
195 vfprintf(stdout, fmt, ap);
196 fflush(stdout);
197 va_end(ap);
198 }
199}
200
201static void mke2fs_verbose_done(void)
202{
203 mke2fs_verbose("done\n");
204}
205
206static void mke2fs_warning_msg(int retval, char *fmt, ... )__attribute__ ((format (printf, 2, 3)));
207static void mke2fs_warning_msg(int retval, char *fmt, ... )
208{
209 va_list ap;
210
211 if (retval) {
212 va_start(ap, fmt);
213 fprintf(stderr,"\nWarning: ");
214 vfprintf(stderr, fmt, ap);
215 fprintf(stderr, "\n");
216 va_end(ap);
217 }
218}
219
220/*
221 * Reads the bad blocks list from a file
222 */
223static void read_bb_file(ext2_filsys fs, badblocks_list *bb_list,
224 const char *bad_blocks_file)
225{
226 FILE *f;
227 errcode_t retval;
228
229 f = xfopen(bad_blocks_file, "r");
230 retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
231 fclose (f);
232 mke2fs_error_msg_and_die(retval, "read bad blocks from list");
233}
234
235/*
236 * Runs the badblocks program to test the disk
237 */
238static void test_disk(ext2_filsys fs, badblocks_list *bb_list)
239{
240 FILE *f;
241 errcode_t retval;
242 char buf[1024];
243
244 sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize,
245 quiet ? "" : "-s ", (cflag > 1) ? "-w " : "",
246 fs->device_name, fs->super->s_blocks_count);
247 mke2fs_verbose("Running command: %s\n", buf);
248 f = popen(buf, "r");
249 if (!f) {
250 bb_perror_msg_and_die("cannot run '%s'", buf);
251 }
252 retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
253 pclose(f);
254 mke2fs_error_msg_and_die(retval, "read bad blocks from program");
255}
256
257static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list)
258{
259 dgrp_t i;
260 blk_t j;
261 unsigned must_be_good;
262 blk_t blk;
263 badblocks_iterate bb_iter;
264 errcode_t retval;
265 blk_t group_block;
266 int group;
267 int group_bad;
268
269 if (!bb_list)
270 return;
271
272 /*
273 * The primary superblock and group descriptors *must* be
274 * good; if not, abort.
275 */
276 must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks;
277 for (i = fs->super->s_first_data_block; i <= must_be_good; i++) {
278 if (ext2fs_badblocks_list_test(bb_list, i)) {
279 bb_error_msg_and_die(
280 "Block %d in primary superblock/group descriptor area bad\n"
281 "Blocks %d through %d must be good in order to build a filesystem\n"
282 "Aborting ...", i, fs->super->s_first_data_block, must_be_good);
283 }
284 }
285
286 /*
287 * See if any of the bad blocks are showing up in the backup
288 * superblocks and/or group descriptors. If so, issue a
289 * warning and adjust the block counts appropriately.
290 */
291 group_block = fs->super->s_first_data_block +
292 fs->super->s_blocks_per_group;
293
294 for (i = 1; i < fs->group_desc_count; i++) {
295 group_bad = 0;
296 for (j=0; j < fs->desc_blocks+1; j++) {
297 if (ext2fs_badblocks_list_test(bb_list,
298 group_block + j)) {
299 mke2fs_warning_msg(!group_bad,
300 "the backup superblock/group descriptors at block %d contain\n"
301 "bad blocks\n", group_block);
302 group_bad++;
303 group = ext2fs_group_of_blk(fs, group_block+j);
304 fs->group_desc[group].bg_free_blocks_count++;
305 fs->super->s_free_blocks_count++;
306 }
307 }
308 group_block += fs->super->s_blocks_per_group;
309 }
310
311 /*
312 * Mark all the bad blocks as used...
313 */
314 retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
315 mke2fs_error_msg_and_die(retval, "mark bad blocks as used");
316
317 while (ext2fs_badblocks_list_iterate(bb_iter, &blk))
318 ext2fs_mark_block_bitmap(fs->block_map, blk);
319 ext2fs_badblocks_list_iterate_end(bb_iter);
320}
321
322/*
323 * These functions implement a generalized progress meter.
324 */
325struct progress_struct {
326 char format[20];
327 char backup[80];
328 __u32 max;
329 int skip_progress;
330};
331
332static void progress_init(struct progress_struct *progress,
333 const char *label,__u32 max)
334{
335 int i;
336
337 memset(progress, 0, sizeof(struct progress_struct));
338 if (quiet)
339 return;
340
341 /*
342 * Figure out how many digits we need
343 */
344 i = int_log10(max);
345 sprintf(progress->format, "%%%dd/%%%dld", i, i);
346 memset(progress->backup, '\b', sizeof(progress->backup)-1);
347 progress->backup[sizeof(progress->backup)-1] = 0;
348 if ((2*i)+1 < (int) sizeof(progress->backup))
349 progress->backup[(2*i)+1] = 0;
350 progress->max = max;
351
352 progress->skip_progress = 0;
353 if (getenv("MKE2FS_SKIP_PROGRESS"))
354 progress->skip_progress++;
355
356 fputs(label, stdout);
357 fflush(stdout);
358}
359
360static void progress_update(struct progress_struct *progress, __u32 val)
361{
362 if ((progress->format[0] == 0) || progress->skip_progress)
363 return;
364 printf(progress->format, val, progress->max);
365 fputs(progress->backup, stdout);
366}
367
368static void progress_close(struct progress_struct *progress)
369{
370 if (progress->format[0] == 0)
371 return;
372 printf("%-28s\n", "done");
373}
374
375
376/*
377 * Helper function which zeros out _num_ blocks starting at _blk_. In
378 * case of an error, the details of the error is returned via _ret_blk_
379 * and _ret_count_ if they are non-NULL pointers. Returns 0 on
380 * success, and an error code on an error.
381 *
382 * As a special case, if the first argument is NULL, then it will
383 * attempt to free the static zeroizing buffer. (This is to keep
384 * programs that check for memory leaks happy.)
385 */
386static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num,
387 struct progress_struct *progress,
388 blk_t *ret_blk, int *ret_count)
389{
390 int j, count, next_update, next_update_incr;
391 static char *buf;
392 errcode_t retval;
393
394 /* If fs is null, clean up the static buffer and return */
395 if (!fs) {
396 if (buf) {
397 free(buf);
398 buf = 0;
399 }
400 return 0;
401 }
402 /* Allocate the zeroizing buffer if necessary */
403 if (!buf) {
404 buf = xzalloc(fs->blocksize * STRIDE_LENGTH);
405 }
406 /* OK, do the write loop */
407 next_update = 0;
408 next_update_incr = num / 100;
409 if (next_update_incr < 1)
410 next_update_incr = 1;
411 for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
412 count = num - j;
413 if (count > STRIDE_LENGTH)
414 count = STRIDE_LENGTH;
415 retval = io_channel_write_blk(fs->io, blk, count, buf);
416 if (retval) {
417 if (ret_count)
418 *ret_count = count;
419 if (ret_blk)
420 *ret_blk = blk;
421 return retval;
422 }
423 if (progress && j > next_update) {
424 next_update += num / 100;
425 progress_update(progress, blk);
426 }
427 }
428 return 0;
429}
430
431static void write_inode_tables(ext2_filsys fs)
432{
433 errcode_t retval;
434 blk_t blk;
435 dgrp_t i;
436 int num;
437 struct progress_struct progress;
438
439 if (quiet)
440 memset(&progress, 0, sizeof(progress));
441 else
442 progress_init(&progress, "Writing inode tables: ",
443 fs->group_desc_count);
444
445 for (i = 0; i < fs->group_desc_count; i++) {
446 progress_update(&progress, i);
447
448 blk = fs->group_desc[i].bg_inode_table;
449 num = fs->inode_blocks_per_group;
450
451 retval = zero_blocks(fs, blk, num, 0, &blk, &num);
452 mke2fs_error_msg_and_die(retval,
453 "write %d blocks in inode table starting at %d.",
454 num, blk);
455 if (sync_kludge) {
456 if (sync_kludge == 1)
457 sync();
458 else if ((i % sync_kludge) == 0)
459 sync();
460 }
461 }
462 zero_blocks(0, 0, 0, 0, 0, 0);
463 progress_close(&progress);
464}
465
466static void create_root_dir(ext2_filsys fs)
467{
468 errcode_t retval;
469 struct ext2_inode inode;
470
471 retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
472 mke2fs_error_msg_and_die(retval, "create root dir");
473 if (geteuid()) {
474 retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode);
475 mke2fs_error_msg_and_die(retval, "read root inode");
476 inode.i_uid = getuid();
477 if (inode.i_uid)
478 inode.i_gid = getgid();
479 retval = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
480 mke2fs_error_msg_and_die(retval, "set root inode ownership");
481 }
482}
483
484static void create_lost_and_found(ext2_filsys fs)
485{
486 errcode_t retval;
487 ext2_ino_t ino;
488 const char *name = "lost+found";
489 int i = 1;
490 char *msg = "create";
491 int lpf_size = 0;
492
493 fs->umask = 077;
494 retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name);
495 if (retval) {
496 goto CREATE_LOST_AND_FOUND_ERROR;
497 }
498
499 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino);
500 if (retval) {
501 msg = "lookup";
502 goto CREATE_LOST_AND_FOUND_ERROR;
503 }
504
505 for (; i < EXT2_NDIR_BLOCKS; i++) {
506 if ((lpf_size += fs->blocksize) >= 16*1024)
507 break;
508 retval = ext2fs_expand_dir(fs, ino);
509 msg = "expand";
510CREATE_LOST_AND_FOUND_ERROR:
511 mke2fs_error_msg_and_die(retval, "%s %s", msg, name);
512 }
513}
514
515static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list)
516{
517 errcode_t retval;
518
519 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
520 fs->group_desc[0].bg_free_inodes_count--;
521 fs->super->s_free_inodes_count--;
522 retval = ext2fs_update_bb_inode(fs, bb_list);
523 mke2fs_error_msg_and_die(retval, "set bad block inode");
524}
525
526static void reserve_inodes(ext2_filsys fs)
527{
528 ext2_ino_t i;
529 int group;
530
531 for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) {
532 ext2fs_mark_inode_bitmap(fs->inode_map, i);
533 group = ext2fs_group_of_ino(fs, i);
534 fs->group_desc[group].bg_free_inodes_count--;
535 fs->super->s_free_inodes_count--;
536 }
537 ext2fs_mark_ib_dirty(fs);
538}
539
540#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
541#define BSD_MAGICDISK (0x57455682UL) /* The disk magic number reversed */
542#define BSD_LABEL_OFFSET 64
543
544static void zap_sector(ext2_filsys fs, int sect, int nsect)
545{
546 char *buf;
547 char *fmt = "could not %s %d";
548 int retval;
549 unsigned int *magic;
550
551 buf = xmalloc(512*nsect);
552
553 if (sect == 0) {
554 /* Check for a BSD disklabel, and don't erase it if so */
555 retval = io_channel_read_blk(fs->io, 0, -512, buf);
556 if (retval)
557 mke2fs_warning_msg(retval, fmt, "read block", 0);
558 else {
559 magic = (unsigned int *) (buf + BSD_LABEL_OFFSET);
560 if ((*magic == BSD_DISKMAGIC) ||
561 (*magic == BSD_MAGICDISK))
562 return;
563 }
564 }
565
566 memset(buf, 0, 512*nsect);
567 io_channel_set_blksize(fs->io, 512);
568 retval = io_channel_write_blk(fs->io, sect, -512*nsect, buf);
569 io_channel_set_blksize(fs->io, fs->blocksize);
570 free(buf);
571 mke2fs_warning_msg(retval, fmt, "erase sector", sect);
572}
573
574static void create_journal_dev(ext2_filsys fs)
575{
576 struct progress_struct progress;
577 errcode_t retval;
578 char *buf;
579 char *fmt = "%s journal superblock";
580 blk_t blk;
581 int count;
582
583 retval = ext2fs_create_journal_superblock(fs,
584 fs->super->s_blocks_count, 0, &buf);
585 mke2fs_error_msg_and_die(retval, fmt, "init");
586 if (quiet)
587 memset(&progress, 0, sizeof(progress));
588 else
589 progress_init(&progress, "Zeroing journal device: ",
590 fs->super->s_blocks_count);
591
592 retval = zero_blocks(fs, 0, fs->super->s_blocks_count,
593 &progress, &blk, &count);
594 mke2fs_error_msg_and_die(retval, "zero journal device (block %u, count %d)",
595 blk, count);
596 zero_blocks(0, 0, 0, 0, 0, 0);
597
598 retval = io_channel_write_blk(fs->io,
599 fs->super->s_first_data_block+1,
600 1, buf);
601 mke2fs_error_msg_and_die(retval, fmt, "write");
602 progress_close(&progress);
603}
604
605static void show_stats(ext2_filsys fs)
606{
607 struct ext2_super_block *s = fs->super;
608 char *os;
609 blk_t group_block;
610 dgrp_t i;
611 int need, col_left;
612
613 mke2fs_warning_msg((param.s_blocks_count != s->s_blocks_count),
614 "%d blocks unused\n", param.s_blocks_count - s->s_blocks_count);
615 os = e2p_os2string(fs->super->s_creator_os);
616 printf( "Filesystem label=%.*s\n"
617 "OS type: %s\n"
618 "Block size=%u (log=%u)\n"
619 "Fragment size=%u (log=%u)\n"
620 "%u inodes, %u blocks\n"
621 "%u blocks (%2.2f%%) reserved for the super user\n"
622 "First data block=%u\n",
623 (int) sizeof(s->s_volume_name),
624 s->s_volume_name,
625 os,
626 fs->blocksize, s->s_log_block_size,
627 fs->fragsize, s->s_log_frag_size,
628 s->s_inodes_count, s->s_blocks_count,
629 s->s_r_blocks_count, 100.0 * s->s_r_blocks_count / s->s_blocks_count,
630 s->s_first_data_block);
631 free(os);
632 if (s->s_reserved_gdt_blocks) {
633 printf("Maximum filesystem blocks=%lu\n",
634 (s->s_reserved_gdt_blocks + fs->desc_blocks) *
635 (fs->blocksize / sizeof(struct ext2_group_desc)) *
636 s->s_blocks_per_group);
637 }
638 printf( "%u block group%s\n"
639 "%u blocks per group, %u fragments per group\n"
640 "%u inodes per group\n",
641 fs->group_desc_count, (fs->group_desc_count > 1) ? "s" : "",
642 s->s_blocks_per_group, s->s_frags_per_group,
643 s->s_inodes_per_group);
644 if (fs->group_desc_count == 1) {
645 puts("");
646 return;
647 }
648
649 printf("Superblock backups stored on blocks: ");
650 group_block = s->s_first_data_block;
651 col_left = 0;
652 for (i = 1; i < fs->group_desc_count; i++) {
653 group_block += s->s_blocks_per_group;
654 if (!ext2fs_bg_has_super(fs, i))
655 continue;
656 if (i != 1)
657 printf(", ");
658 need = int_log10(group_block) + 2;
659 if (need > col_left) {
660 printf("\n\t");
661 col_left = 72;
662 }
663 col_left -= need;
664 printf("%u", group_block);
665 }
666 puts("\n");
667}
668
669/*
670 * Set the S_CREATOR_OS field. Return true if OS is known,
671 * otherwise, 0.
672 */
673static int set_os(struct ext2_super_block *sb, char *os)
674{
675 if (isdigit (*os)) {
676 sb->s_creator_os = atoi(os);
677 return 1;
678 }
679
680 if((sb->s_creator_os = e2p_string2os(os)) >= 0) {
681 return 1;
682 } else if (!strcasecmp("GNU", os)) {
683 sb->s_creator_os = EXT2_OS_HURD;
684 return 1;
685 }
686 return 0;
687}
688
689static void parse_extended_opts(struct ext2_super_block *sb_param,
690 const char *opts)
691{
692 char *buf, *token, *next, *p, *arg;
693 int r_usage = 0;
694
695 buf = xstrdup(opts);
696 for (token = buf; token && *token; token = next) {
697 p = strchr(token, ',');
698 next = 0;
699 if (p) {
700 *p = 0;
701 next = p+1;
702 }
703 arg = strchr(token, '=');
704 if (arg) {
705 *arg = 0;
706 arg++;
707 }
708 if (strcmp(token, "stride") == 0) {
709 if (!arg) {
710 r_usage++;
711 continue;
712 }
713 fs_stride = strtoul(arg, &p, 0);
714 if (*p || (fs_stride == 0)) {
715 bb_error_msg("Invalid stride parameter: %s", arg);
716 r_usage++;
717 continue;
718 }
719 } else if (!strcmp(token, "resize")) {
720 unsigned long resize, bpg, rsv_groups;
721 unsigned long group_desc_count, desc_blocks;
722 unsigned int gdpb, blocksize;
723 int rsv_gdb;
724
725 if (!arg) {
726 r_usage++;
727 continue;
728 }
729
730 resize = parse_num_blocks(arg,
731 sb_param->s_log_block_size);
732
733 if (resize == 0) {
734 bb_error_msg("Invalid resize parameter: %s", arg);
735 r_usage++;
736 continue;
737 }
738 if (resize <= sb_param->s_blocks_count) {
739 bb_error_msg("The resize maximum must be greater "
740 "than the filesystem size");
741 r_usage++;
742 continue;
743 }
744
745 blocksize = EXT2_BLOCK_SIZE(sb_param);
746 bpg = sb_param->s_blocks_per_group;
747 if (!bpg)
748 bpg = blocksize * 8;
749 gdpb = blocksize / sizeof(struct ext2_group_desc);
750 group_desc_count = (sb_param->s_blocks_count +
751 bpg - 1) / bpg;
752 desc_blocks = (group_desc_count +
753 gdpb - 1) / gdpb;
754 rsv_groups = (resize + bpg - 1) / bpg;
755 rsv_gdb = (rsv_groups + gdpb - 1) / gdpb -
756 desc_blocks;
757 if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb_param))
758 rsv_gdb = EXT2_ADDR_PER_BLOCK(sb_param);
759
760 if (rsv_gdb > 0) {
761 sb_param->s_feature_compat |=
762 EXT2_FEATURE_COMPAT_RESIZE_INODE;
763
764 sb_param->s_reserved_gdt_blocks = rsv_gdb;
765 }
766 } else
767 r_usage++;
768 }
769 if (r_usage) {
770 bb_error_msg_and_die(
771 "\nBad options specified.\n\n"
772 "Extended options are separated by commas, "
773 "and may take an argument which\n"
774 "\tis set off by an equals ('=') sign.\n\n"
775 "Valid extended options are:\n"
776 "\tstride=<stride length in blocks>\n"
777 "\tresize=<resize maximum size in blocks>\n");
778 }
779}
780
781static __u32 ok_features[3] = {
782 EXT3_FEATURE_COMPAT_HAS_JOURNAL |
783 EXT2_FEATURE_COMPAT_RESIZE_INODE |
784 EXT2_FEATURE_COMPAT_DIR_INDEX, /* Compat */
785 EXT2_FEATURE_INCOMPAT_FILETYPE| /* Incompat */
786 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
787 EXT2_FEATURE_INCOMPAT_META_BG,
788 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */
789};
790
791static int PRS(int argc, char *argv[])
792{
793 int c;
794 int size;
795 char * tmp;
796 int blocksize = 0;
797 int inode_ratio = 0;
798 int inode_size = 0;
799 int reserved_ratio = 5;
800 int sector_size = 0;
801 int show_version_only = 0;
802 ext2_ino_t num_inodes = 0;
803 errcode_t retval;
804 char * extended_opts = 0;
805 const char * fs_type = 0;
806 blk_t dev_size;
807 long sysval;
808
809 /* Update our PATH to include /sbin */
810 e2fs_set_sbin_path();
811
812 tmp = getenv("MKE2FS_SYNC");
813 if (tmp)
814 sync_kludge = atoi(tmp);
815
816 /* Determine the system page size if possible */
817#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
818#define _SC_PAGESIZE _SC_PAGE_SIZE
819#endif
820#ifdef _SC_PAGESIZE
821 sysval = sysconf(_SC_PAGESIZE);
822 if (sysval > 0)
823 sys_page_size = sysval;
824#endif /* _SC_PAGESIZE */
825
826 setbuf(stdout, NULL);
827 setbuf(stderr, NULL);
828 memset(&param, 0, sizeof(struct ext2_super_block));
829 param.s_rev_level = 1; /* Create revision 1 filesystems now */
830 param.s_feature_incompat |= EXT2_FEATURE_INCOMPAT_FILETYPE;
831 param.s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
832
833#ifdef __linux__
834 linux_version_code = get_linux_version_code();
835 if (linux_version_code && linux_version_code < KERNEL_VERSION(2,2,0)) {
836 param.s_rev_level = 0;
837 param.s_feature_incompat = 0;
838 param.s_feature_compat = 0;
839 param.s_feature_ro_compat = 0;
840 }
841#endif
842
843 /* If called as mkfs.ext3, create a journal inode */
844 if (last_char_is(applet_name, '3'))
845 journal_size = -1;
846
847 while ((c = getopt (argc, argv,
848 "b:cE:f:g:i:jl:m:no:qr:R:s:tvI:J:ST:FL:M:N:O:V")) != EOF) {
849 switch (c) {
850 case 'b':
851 blocksize = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE);
852 mke2fs_warning_msg((blocksize > 4096),
853 "blocksize %d not usable on most systems",
854 blocksize);
855 param.s_log_block_size =
856 int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
857 break;
858 case 'c': /* Check for bad blocks */
859 case 't': /* deprecated */
860 cflag++;
861 break;
862 case 'f':
863 size = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE);
864 param.s_log_frag_size =
865 int_log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
866 mke2fs_warning_msg(1, "fragments not supported. Ignoring -f option");
867 break;
868 case 'g':
869 param.s_blocks_per_group = xatou32(optarg);
870 if ((param.s_blocks_per_group % 8) != 0) {
871 bb_error_msg_and_die("blocks per group must be multiple of 8");
872 }
873 break;
874 case 'i':
875 /* Huh? is "* 1024" correct? */
876 inode_ratio = xatou_range(optarg, EXT2_MIN_BLOCK_SIZE, EXT2_MAX_BLOCK_SIZE * 1024);
877 break;
878 case 'J':
879 parse_journal_opts(&journal_device, &journal_flags, &journal_size, optarg);
880 break;
881 case 'j':
882 param.s_feature_compat |=
883 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
884 if (!journal_size)
885 journal_size = -1;
886 break;
887 case 'l':
888 bad_blocks_filename = optarg;
889 break;
890 case 'm':
891 reserved_ratio = xatou_range(optarg, 0, 50);
892 break;
893 case 'n':
894 noaction++;
895 break;
896 case 'o':
897 creator_os = optarg;
898 break;
899 case 'r':
900 param.s_rev_level = xatoi_u(optarg);
901 if (param.s_rev_level == EXT2_GOOD_OLD_REV) {
902 param.s_feature_incompat = 0;
903 param.s_feature_compat = 0;
904 param.s_feature_ro_compat = 0;
905 }
906 break;
907 case 's': /* deprecated */
908 if (xatou(optarg))
909 param.s_feature_ro_compat |=
910 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
911 else
912 param.s_feature_ro_compat &=
913 ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
914 break;
915#ifdef EXT2_DYNAMIC_REV
916 case 'I':
917 inode_size = xatoi_u(optarg);
918 break;
919#endif
920 case 'N':
921 num_inodes = xatoi_u(optarg);
922 break;
923 case 'v':
924 quiet = 0;
925 break;
926 case 'q':
927 quiet = 1;
928 break;
929 case 'F':
930 force = 1;
931 break;
932 case 'L':
933 volume_label = optarg;
934 break;
935 case 'M':
936 mount_dir = optarg;
937 break;
938 case 'O':
939 if (!strcmp(optarg, "none")) {
940 param.s_feature_compat = 0;
941 param.s_feature_incompat = 0;
942 param.s_feature_ro_compat = 0;
943 break;
944 }
945 if (e2p_edit_feature(optarg,
946 &param.s_feature_compat,
947 ok_features)) {
948 bb_error_msg_and_die("Invalid filesystem option set: %s", optarg);
949 }
950 break;
951 case 'E':
952 case 'R':
953 extended_opts = optarg;
954 break;
955 case 'S':
956 super_only = 1;
957 break;
958 case 'T':
959 fs_type = optarg;
960 break;
961 case 'V':
962 /* Print version number and exit */
963 show_version_only = 1;
964 quiet = 0;
965 break;
966 default:
967 bb_show_usage();
968 }
969 }
970 if ((optind == argc) /*&& !show_version_only*/)
971 bb_show_usage();
972 device_name = argv[optind++];
973
974 mke2fs_verbose("mke2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
975
976 if (show_version_only) {
977 return 0;
978 }
979
980 /*
981 * If there's no blocksize specified and there is a journal
982 * device, use it to figure out the blocksize
983 */
984 if (blocksize <= 0 && journal_device) {
985 ext2_filsys jfs;
986 io_manager io_ptr;
987
988#ifdef CONFIG_TESTIO_DEBUG
989 io_ptr = test_io_manager;
990 test_io_backing_manager = unix_io_manager;
991#else
992 io_ptr = unix_io_manager;
993#endif
994 retval = ext2fs_open(journal_device,
995 EXT2_FLAG_JOURNAL_DEV_OK, 0,
996 0, io_ptr, &jfs);
997 mke2fs_error_msg_and_die(retval, "open journal device %s", journal_device);
998 if ((blocksize < 0) && (jfs->blocksize < (unsigned) (-blocksize))) {
999 bb_error_msg_and_die(
1000 "Journal dev blocksize (%d) smaller than "
1001 "minimum blocksize %d\n", jfs->blocksize,
1002 -blocksize);
1003 }
1004 blocksize = jfs->blocksize;
1005 param.s_log_block_size =
1006 int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
1007 ext2fs_close(jfs);
1008 }
1009
1010 if (blocksize > sys_page_size) {
1011 mke2fs_warning_msg(1, "%d-byte blocks too big for system (max %d)",
1012 blocksize, sys_page_size);
1013 if (!force) {
1014 proceed_question();
1015 }
1016 bb_error_msg("Forced to continue");
1017 }
1018 mke2fs_warning_msg(((blocksize > 4096) &&
1019 (param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)),
1020 "some 2.4 kernels do not support "
1021 "blocksizes greater than 4096 using ext3.\n"
1022 "Use -b 4096 if this is an issue for you\n");
1023
1024 if (optind < argc) {
1025 param.s_blocks_count = parse_num_blocks(argv[optind++],
1026 param.s_log_block_size);
1027 mke2fs_error_msg_and_die(!param.s_blocks_count, "invalid blocks count - %s", argv[optind - 1]);
1028 }
1029 if (optind < argc)
1030 bb_show_usage();
1031
1032 if (param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
1033 if (!fs_type)
1034 fs_type = "journal";
1035 reserved_ratio = 0;
1036 param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV;
1037 param.s_feature_compat = 0;
1038 param.s_feature_ro_compat = 0;
1039 }
1040 if (param.s_rev_level == EXT2_GOOD_OLD_REV &&
1041 (param.s_feature_compat || param.s_feature_ro_compat ||
1042 param.s_feature_incompat))
1043 param.s_rev_level = 1; /* Create a revision 1 filesystem */
1044
1045 check_plausibility(device_name , force);
1046 check_mount(device_name, force, "filesystem");
1047
1048 param.s_log_frag_size = param.s_log_block_size;
1049
1050 if (noaction && param.s_blocks_count) {
1051 dev_size = param.s_blocks_count;
1052 retval = 0;
1053 } else {
1054 retry:
1055 retval = ext2fs_get_device_size(device_name,
1056 EXT2_BLOCK_SIZE(&param),
1057 &dev_size);
1058 if ((retval == EFBIG) &&
1059 (blocksize == 0) &&
1060 (param.s_log_block_size == 0)) {
1061 param.s_log_block_size = 2;
1062 blocksize = 4096;
1063 goto retry;
1064 }
1065 }
1066
1067 mke2fs_error_msg_and_die((retval && (retval != EXT2_ET_UNIMPLEMENTED)),"determine filesystem size");
1068
1069 if (!param.s_blocks_count) {
1070 if (retval == EXT2_ET_UNIMPLEMENTED) {
1071 mke2fs_error_msg_and_die(1,
1072 "determine device size; you "
1073 "must specify\nthe size of the "
1074 "filesystem");
1075 } else {
1076 if (dev_size == 0) {
1077 bb_error_msg_and_die(
1078 "Device size reported to be zero. "
1079 "Invalid partition specified, or\n\t"
1080 "partition table wasn't reread "
1081 "after running fdisk, due to\n\t"
1082 "a modified partition being busy "
1083 "and in use. You may need to reboot\n\t"
1084 "to re-read your partition table.\n"
1085 );
1086 }
1087 param.s_blocks_count = dev_size;
1088 if (sys_page_size > EXT2_BLOCK_SIZE(&param))
1089 param.s_blocks_count &= ~((sys_page_size /
1090 EXT2_BLOCK_SIZE(&param))-1);
1091 }
1092
1093 } else if (!force && (param.s_blocks_count > dev_size)) {
1094 bb_error_msg("Filesystem larger than apparent device size");
1095 proceed_question();
1096 }
1097
1098 /*
1099 * If the user asked for HAS_JOURNAL, then make sure a journal
1100 * gets created.
1101 */
1102 if ((param.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
1103 !journal_size)
1104 journal_size = -1;
1105
1106 /* Set first meta blockgroup via an environment variable */
1107 /* (this is mostly for debugging purposes) */
1108 if ((param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) &&
1109 ((tmp = getenv("MKE2FS_FIRST_META_BG"))))
1110 param.s_first_meta_bg = atoi(tmp);
1111
1112 /* Get the hardware sector size, if available */
1113 retval = ext2fs_get_device_sectsize(device_name, &sector_size);
1114 mke2fs_error_msg_and_die(retval, "determine hardware sector size");
1115
1116 if ((tmp = getenv("MKE2FS_DEVICE_SECTSIZE")) != NULL)
1117 sector_size = atoi(tmp);
1118
1119 set_fs_defaults(fs_type, &param, blocksize, sector_size, &inode_ratio);
1120 blocksize = EXT2_BLOCK_SIZE(&param);
1121
1122 if (extended_opts)
1123 parse_extended_opts(&param, extended_opts);
1124
1125 /* Since sparse_super is the default, we would only have a problem
1126 * here if it was explicitly disabled.
1127 */
1128 if ((param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
1129 !(param.s_feature_ro_compat&EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
1130 bb_error_msg_and_die("reserved online resize blocks not supported "
1131 "on non-sparse filesystem");
1132 }
1133
1134 if (param.s_blocks_per_group) {
1135 if (param.s_blocks_per_group < 256 ||
1136 param.s_blocks_per_group > 8 * (unsigned) blocksize) {
1137 bb_error_msg_and_die("blocks per group count out of range");
1138 }
1139 }
1140
1141 if (!force && param.s_blocks_count >= (1 << 31)) {
1142 bb_error_msg_and_die("Filesystem too large. No more than 2**31-1 blocks\n"
1143 "\t (8TB using a blocksize of 4k) are currently supported.");
1144 }
1145
1146 if (inode_size) {
1147 if (inode_size < EXT2_GOOD_OLD_INODE_SIZE ||
1148 inode_size > EXT2_BLOCK_SIZE(&param) ||
1149 inode_size & (inode_size - 1)) {
1150 bb_error_msg_and_die("invalid inode size %d (min %d/max %d)",
1151 inode_size, EXT2_GOOD_OLD_INODE_SIZE,
1152 blocksize);
1153 }
1154 mke2fs_warning_msg((inode_size != EXT2_GOOD_OLD_INODE_SIZE),
1155 "%d-byte inodes not usable on most systems",
1156 inode_size);
1157 param.s_inode_size = inode_size;
1158 }
1159
1160 /*
1161 * Calculate number of inodes based on the inode ratio
1162 */
1163 param.s_inodes_count = num_inodes ? num_inodes :
1164 ((__u64) param.s_blocks_count * blocksize)
1165 / inode_ratio;
1166
1167 /*
1168 * Calculate number of blocks to reserve
1169 */
1170 param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100;
1171 return 1;
1172}
1173
1174static void mke2fs_clean_up(void)
1175{
1176 if (ENABLE_FEATURE_CLEAN_UP && journal_device) free(journal_device);
1177}
1178
1179int mke2fs_main (int argc, char *argv[])
1180{
1181 errcode_t retval;
1182 ext2_filsys fs;
1183 badblocks_list bb_list = 0;
1184 unsigned int i;
1185 int val;
1186 io_manager io_ptr;
1187
1188 if (ENABLE_FEATURE_CLEAN_UP)
1189 atexit(mke2fs_clean_up);
1190 if(!PRS(argc, argv))
1191 return 0;
1192
1193#ifdef CONFIG_TESTIO_DEBUG
1194 io_ptr = test_io_manager;
1195 test_io_backing_manager = unix_io_manager;
1196#else
1197 io_ptr = unix_io_manager;
1198#endif
1199
1200 /*
1201 * Initialize the superblock....
1202 */
1203 retval = ext2fs_initialize(device_name, 0, &param,
1204 io_ptr, &fs);
1205 mke2fs_error_msg_and_die(retval, "set up superblock");
1206
1207 /*
1208 * Wipe out the old on-disk superblock
1209 */
1210 if (!noaction)
1211 zap_sector(fs, 2, 6);
1212
1213 /*
1214 * Generate a UUID for it...
1215 */
1216 uuid_generate(fs->super->s_uuid);
1217
1218 /*
1219 * Initialize the directory index variables
1220 */
1221 fs->super->s_def_hash_version = EXT2_HASH_TEA;
1222 uuid_generate((unsigned char *) fs->super->s_hash_seed);
1223
1224 /*
1225 * Add "jitter" to the superblock's check interval so that we
1226 * don't check all the filesystems at the same time. We use a
1227 * kludgy hack of using the UUID to derive a random jitter value.
1228 */
1229 for (i = 0, val = 0 ; i < sizeof(fs->super->s_uuid); i++)
1230 val += fs->super->s_uuid[i];
1231 fs->super->s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
1232
1233 /*
1234 * Override the creator OS, if applicable
1235 */
1236 if (creator_os && !set_os(fs->super, creator_os)) {
1237 bb_error_msg_and_die("unknown os - %s", creator_os);
1238 }
1239
1240 /*
1241 * For the Hurd, we will turn off filetype since it doesn't
1242 * support it.
1243 */
1244 if (fs->super->s_creator_os == EXT2_OS_HURD)
1245 fs->super->s_feature_incompat &=
1246 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
1247
1248 /*
1249 * Set the volume label...
1250 */
1251 if (volume_label) {
1252 snprintf(fs->super->s_volume_name, sizeof(fs->super->s_volume_name), "%s", volume_label);
1253 }
1254
1255 /*
1256 * Set the last mount directory
1257 */
1258 if (mount_dir) {
1259 snprintf(fs->super->s_last_mounted, sizeof(fs->super->s_last_mounted), "%s", mount_dir);
1260 }
1261
1262 if (!quiet || noaction)
1263 show_stats(fs);
1264
1265 if (noaction)
1266 return 0;
1267
1268 if (fs->super->s_feature_incompat &
1269 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
1270 create_journal_dev(fs);
1271 return (ext2fs_close(fs) ? 1 : 0);
1272 }
1273
1274 if (bad_blocks_filename)
1275 read_bb_file(fs, &bb_list, bad_blocks_filename);
1276 if (cflag)
1277 test_disk(fs, &bb_list);
1278
1279 handle_bad_blocks(fs, bb_list);
1280 fs->stride = fs_stride;
1281 retval = ext2fs_allocate_tables(fs);
1282 mke2fs_error_msg_and_die(retval, "allocate filesystem tables");
1283 if (super_only) {
1284 fs->super->s_state |= EXT2_ERROR_FS;
1285 fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY);
1286 } else {
1287 /* rsv must be a power of two (64kB is MD RAID sb alignment) */
1288 unsigned int rsv = 65536 / fs->blocksize;
1289 unsigned long blocks = fs->super->s_blocks_count;
1290 unsigned long start;
1291 blk_t ret_blk;
1292
1293#ifdef ZAP_BOOTBLOCK
1294 zap_sector(fs, 0, 2);
1295#endif
1296
1297 /*
1298 * Wipe out any old MD RAID (or other) metadata at the end
1299 * of the device. This will also verify that the device is
1300 * as large as we think. Be careful with very small devices.
1301 */
1302 start = (blocks & ~(rsv - 1));
1303 if (start > rsv)
1304 start -= rsv;
1305 if (start > 0)
1306 retval = zero_blocks(fs, start, blocks - start,
1307 NULL, &ret_blk, NULL);
1308
1309 mke2fs_warning_msg(retval, "cannot zero block %u at end of filesystem", ret_blk);
1310 write_inode_tables(fs);
1311 create_root_dir(fs);
1312 create_lost_and_found(fs);
1313 reserve_inodes(fs);
1314 create_bad_block_inode(fs, bb_list);
1315 if (fs->super->s_feature_compat &
1316 EXT2_FEATURE_COMPAT_RESIZE_INODE) {
1317 retval = ext2fs_create_resize_inode(fs);
1318 mke2fs_error_msg_and_die(retval, "reserve blocks for online resize");
1319 }
1320 }
1321
1322 if (journal_device) {
1323 make_journal_device(journal_device, fs, quiet, force);
1324 } else if (journal_size) {
1325 make_journal_blocks(fs, journal_size, journal_flags, quiet);
1326 }
1327
1328 mke2fs_verbose("Writing superblocks and filesystem accounting information: ");
1329 retval = ext2fs_flush(fs);
1330 mke2fs_warning_msg(retval, "had trouble writing out superblocks");
1331 mke2fs_verbose_done();
1332 if (!quiet && !getenv("MKE2FS_SKIP_CHECK_MSG"))
1333 print_check_message(fs);
1334 val = ext2fs_close(fs);
1335 return (retval || val) ? 1 : 0;
1336}
diff --git a/e2fsprogs/old_e2fsprogs/tune2fs.c b/e2fsprogs/old_e2fsprogs/tune2fs.c
new file mode 100644
index 000000000..a2ca1ba09
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/tune2fs.c
@@ -0,0 +1,729 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * tune2fs.c - Change the file system parameters on an ext2 file system
4 *
5 * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
6 * Laboratoire MASI, Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
10 *
11 * %Begin-Header%
12 * This file may be redistributed under the terms of the GNU Public
13 * License.
14 * %End-Header%
15 */
16
17/*
18 * History:
19 * 93/06/01 - Creation
20 * 93/10/31 - Added the -c option to change the maximal mount counts
21 * 93/12/14 - Added -l flag to list contents of superblock
22 * M.J.E. Mol (marcel@duteca.et.tudelft.nl)
23 * F.W. ten Wolde (franky@duteca.et.tudelft.nl)
24 * 93/12/29 - Added the -e option to change errors behavior
25 * 94/02/27 - Ported to use the ext2fs library
26 * 94/03/06 - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de)
27 */
28
29#include <sys/types.h>
30#include <fcntl.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <time.h>
35#include <unistd.h>
36#include <getopt.h>
37
38#include "e2fsbb.h"
39#include "ext2fs/ext2_fs.h"
40#include "ext2fs/ext2fs.h"
41#include "uuid/uuid.h"
42#include "e2p/e2p.h"
43#include "ext2fs/kernel-jbd.h"
44#include "util.h"
45#include "blkid/blkid.h"
46
47#include "busybox.h"
48
49static char * device_name = NULL;
50static char * new_label, *new_last_mounted, *new_UUID;
51static char * io_options;
52static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
53static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
54static time_t last_check_time;
55static int print_label;
56static int max_mount_count, mount_count, mount_flags;
57static unsigned long interval, reserved_blocks;
58static unsigned reserved_ratio;
59static unsigned long resgid, resuid;
60static unsigned short errors;
61static int open_flag;
62static char *features_cmd;
63static char *mntopts_cmd;
64
65static int journal_size, journal_flags;
66static char *journal_device = NULL;
67
68static const char *please_fsck = "Please run e2fsck on the filesystem\n";
69
70static __u32 ok_features[3] = {
71 EXT3_FEATURE_COMPAT_HAS_JOURNAL | EXT2_FEATURE_COMPAT_DIR_INDEX,
72 EXT2_FEATURE_INCOMPAT_FILETYPE,
73 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
74};
75
76/*
77 * Remove an external journal from the filesystem
78 */
79static void remove_journal_device(ext2_filsys fs)
80{
81 char *journal_path;
82 ext2_filsys jfs;
83 char buf[1024];
84 journal_superblock_t *jsb;
85 int i, nr_users;
86 errcode_t retval;
87 int commit_remove_journal = 0;
88 io_manager io_ptr;
89
90 if (f_flag)
91 commit_remove_journal = 1; /* force removal even if error */
92
93 uuid_unparse(fs->super->s_journal_uuid, buf);
94 journal_path = blkid_get_devname(NULL, "UUID", buf);
95
96 if (!journal_path) {
97 journal_path =
98 ext2fs_find_block_device(fs->super->s_journal_dev);
99 if (!journal_path)
100 return;
101 }
102
103 io_ptr = unix_io_manager;
104 retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
105 EXT2_FLAG_JOURNAL_DEV_OK, 0,
106 fs->blocksize, io_ptr, &jfs);
107 if (retval) {
108 bb_error_msg("Failed to open external journal");
109 goto no_valid_journal;
110 }
111 if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
112 bb_error_msg("%s is not a journal device", journal_path);
113 goto no_valid_journal;
114 }
115
116 /* Get the journal superblock */
117 if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) {
118 bb_error_msg("Failed to read journal superblock");
119 goto no_valid_journal;
120 }
121
122 jsb = (journal_superblock_t *) buf;
123 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
124 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
125 bb_error_msg("Journal superblock not found!");
126 goto no_valid_journal;
127 }
128
129 /* Find the filesystem UUID */
130 nr_users = ntohl(jsb->s_nr_users);
131 for (i=0; i < nr_users; i++) {
132 if (memcmp(fs->super->s_uuid,
133 &jsb->s_users[i*16], 16) == 0)
134 break;
135 }
136 if (i >= nr_users) {
137 bb_error_msg("Filesystem's UUID not found on journal device");
138 commit_remove_journal = 1;
139 goto no_valid_journal;
140 }
141 nr_users--;
142 for (i=0; i < nr_users; i++)
143 memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16);
144 jsb->s_nr_users = htonl(nr_users);
145
146 /* Write back the journal superblock */
147 if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) {
148 bb_error_msg("Failed to write journal superblock");
149 goto no_valid_journal;
150 }
151
152 commit_remove_journal = 1;
153
154no_valid_journal:
155 if (commit_remove_journal == 0)
156 bb_error_msg_and_die("Journal NOT removed");
157 fs->super->s_journal_dev = 0;
158 uuid_clear(fs->super->s_journal_uuid);
159 ext2fs_mark_super_dirty(fs);
160 puts("Journal removed");
161 free(journal_path);
162}
163
164/* Helper function for remove_journal_inode */
165static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
166 int blockcnt EXT2FS_ATTR((unused)),
167 void *private EXT2FS_ATTR((unused)))
168{
169 blk_t block;
170 int group;
171
172 block = *blocknr;
173 ext2fs_unmark_block_bitmap(fs->block_map,block);
174 group = ext2fs_group_of_blk(fs, block);
175 fs->group_desc[group].bg_free_blocks_count++;
176 fs->super->s_free_blocks_count++;
177 return 0;
178}
179
180/*
181 * Remove the journal inode from the filesystem
182 */
183static void remove_journal_inode(ext2_filsys fs)
184{
185 struct ext2_inode inode;
186 errcode_t retval;
187 ino_t ino = fs->super->s_journal_inum;
188 char *msg = "to read";
189 char *s = "journal inode";
190
191 retval = ext2fs_read_inode(fs, ino, &inode);
192 if (retval)
193 goto REMOVE_JOURNAL_INODE_ERROR;
194 if (ino == EXT2_JOURNAL_INO) {
195 retval = ext2fs_read_bitmaps(fs);
196 if (retval) {
197 msg = "to read bitmaps";
198 s = "";
199 goto REMOVE_JOURNAL_INODE_ERROR;
200 }
201 retval = ext2fs_block_iterate(fs, ino, 0, NULL,
202 release_blocks_proc, NULL);
203 if (retval) {
204 msg = "clearing";
205 goto REMOVE_JOURNAL_INODE_ERROR;
206 }
207 memset(&inode, 0, sizeof(inode));
208 ext2fs_mark_bb_dirty(fs);
209 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
210 } else
211 inode.i_flags &= ~EXT2_IMMUTABLE_FL;
212 retval = ext2fs_write_inode(fs, ino, &inode);
213 if (retval) {
214 msg = "writing";
215REMOVE_JOURNAL_INODE_ERROR:
216 bb_error_msg_and_die("Failed %s %s", msg, s);
217 }
218 fs->super->s_journal_inum = 0;
219 ext2fs_mark_super_dirty(fs);
220}
221
222/*
223 * Update the default mount options
224 */
225static void update_mntopts(ext2_filsys fs, char *mntopts)
226{
227 struct ext2_super_block *sb= fs->super;
228
229 if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0))
230 bb_error_msg_and_die("Invalid mount option set: %s", mntopts);
231 ext2fs_mark_super_dirty(fs);
232}
233
234/*
235 * Update the feature set as provided by the user.
236 */
237static void update_feature_set(ext2_filsys fs, char *features)
238{
239 int sparse, old_sparse, filetype, old_filetype;
240 int journal, old_journal, dxdir, old_dxdir;
241 struct ext2_super_block *sb= fs->super;
242 __u32 old_compat, old_incompat, old_ro_compat;
243
244 old_compat = sb->s_feature_compat;
245 old_ro_compat = sb->s_feature_ro_compat;
246 old_incompat = sb->s_feature_incompat;
247
248 old_sparse = sb->s_feature_ro_compat &
249 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
250 old_filetype = sb->s_feature_incompat &
251 EXT2_FEATURE_INCOMPAT_FILETYPE;
252 old_journal = sb->s_feature_compat &
253 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
254 old_dxdir = sb->s_feature_compat &
255 EXT2_FEATURE_COMPAT_DIR_INDEX;
256 if (e2p_edit_feature(features, &sb->s_feature_compat, ok_features))
257 bb_error_msg_and_die("Invalid filesystem option set: %s", features);
258 sparse = sb->s_feature_ro_compat &
259 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
260 filetype = sb->s_feature_incompat &
261 EXT2_FEATURE_INCOMPAT_FILETYPE;
262 journal = sb->s_feature_compat &
263 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
264 dxdir = sb->s_feature_compat &
265 EXT2_FEATURE_COMPAT_DIR_INDEX;
266 if (old_journal && !journal) {
267 if ((mount_flags & EXT2_MF_MOUNTED) &&
268 !(mount_flags & EXT2_MF_READONLY)) {
269 bb_error_msg_and_die(
270 "The has_journal flag may only be "
271 "cleared when the filesystem is\n"
272 "unmounted or mounted "
273 "read-only");
274 }
275 if (sb->s_feature_incompat &
276 EXT3_FEATURE_INCOMPAT_RECOVER) {
277 bb_error_msg_and_die(
278 "The needs_recovery flag is set. "
279 "%s before clearing the has_journal flag.",
280 please_fsck);
281 }
282 if (sb->s_journal_inum) {
283 remove_journal_inode(fs);
284 }
285 if (sb->s_journal_dev) {
286 remove_journal_device(fs);
287 }
288 }
289 if (journal && !old_journal) {
290 /*
291 * If adding a journal flag, let the create journal
292 * code below handle creating setting the flag and
293 * creating the journal. We supply a default size if
294 * necessary.
295 */
296 if (!journal_size)
297 journal_size = -1;
298 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
299 }
300 if (dxdir && !old_dxdir) {
301 if (!sb->s_def_hash_version)
302 sb->s_def_hash_version = EXT2_HASH_TEA;
303 if (uuid_is_null((unsigned char *) sb->s_hash_seed))
304 uuid_generate((unsigned char *) sb->s_hash_seed);
305 }
306
307 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
308 (sb->s_feature_compat || sb->s_feature_ro_compat ||
309 sb->s_feature_incompat))
310 ext2fs_update_dynamic_rev(fs);
311 if ((sparse != old_sparse) ||
312 (filetype != old_filetype)) {
313 sb->s_state &= ~EXT2_VALID_FS;
314 printf("\n%s\n", please_fsck);
315 }
316 if ((old_compat != sb->s_feature_compat) ||
317 (old_ro_compat != sb->s_feature_ro_compat) ||
318 (old_incompat != sb->s_feature_incompat))
319 ext2fs_mark_super_dirty(fs);
320}
321
322/*
323 * Add a journal to the filesystem.
324 */
325static void add_journal(ext2_filsys fs)
326{
327 if (fs->super->s_feature_compat &
328 EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
329 bb_error_msg_and_die("The filesystem already has a journal");
330 }
331 if (journal_device) {
332 make_journal_device(journal_device, fs, 0, 0);
333 } else if (journal_size) {
334 make_journal_blocks(fs, journal_size, journal_flags, 0);
335 /*
336 * If the filesystem wasn't mounted, we need to force
337 * the block group descriptors out.
338 */
339 if ((mount_flags & EXT2_MF_MOUNTED) == 0)
340 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
341 }
342 print_check_message(fs);
343 return;
344}
345
346/*
347 * Busybox stuff
348 */
349static char * x_blkid_get_devname(const char *token)
350{
351 char * dev_name;
352
353 if (!(dev_name = blkid_get_devname(NULL, token, NULL)))
354 bb_error_msg_and_die("Unable to resolve '%s'", token);
355 return dev_name;
356}
357
358#ifdef CONFIG_E2LABEL
359static void parse_e2label_options(int argc, char ** argv)
360{
361 if ((argc < 2) || (argc > 3))
362 bb_show_usage();
363 io_options = strchr(argv[1], '?');
364 if (io_options)
365 *io_options++ = 0;
366 device_name = x_blkid_get_devname(argv[1]);
367 if (argc == 3) {
368 open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK;
369 L_flag = 1;
370 new_label = argv[2];
371 } else
372 print_label++;
373}
374#else
375#define parse_e2label_options(x,y)
376#endif
377
378static time_t parse_time(char *str)
379{
380 struct tm ts;
381
382 if (strcmp(str, "now") == 0) {
383 return time(0);
384 }
385 memset(&ts, 0, sizeof(ts));
386#ifdef HAVE_STRPTIME
387 strptime(str, "%Y%m%d%H%M%S", &ts);
388#else
389 sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
390 &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
391 ts.tm_year -= 1900;
392 ts.tm_mon -= 1;
393 if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 ||
394 ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
395 ts.tm_min > 59 || ts.tm_sec > 61)
396 ts.tm_mday = 0;
397#endif
398 if (ts.tm_mday == 0) {
399 bb_error_msg_and_die("Cannot parse date/time specifier: %s", str);
400 }
401 return mktime(&ts);
402}
403
404static void parse_tune2fs_options(int argc, char **argv)
405{
406 int c;
407 char * tmp;
408
409 printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
410 while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:J:L:M:O:T:U:")) != EOF)
411 switch (c)
412 {
413 case 'c':
414 max_mount_count = xatou_range(optarg, 0, 16000);
415 if (max_mount_count == 0)
416 max_mount_count = -1;
417 c_flag = 1;
418 open_flag = EXT2_FLAG_RW;
419 break;
420 case 'C':
421 mount_count = xatou_range(optarg, 0, 16000);
422 C_flag = 1;
423 open_flag = EXT2_FLAG_RW;
424 break;
425 case 'e':
426 if (strcmp (optarg, "continue") == 0)
427 errors = EXT2_ERRORS_CONTINUE;
428 else if (strcmp (optarg, "remount-ro") == 0)
429 errors = EXT2_ERRORS_RO;
430 else if (strcmp (optarg, "panic") == 0)
431 errors = EXT2_ERRORS_PANIC;
432 else {
433 bb_error_msg_and_die("bad error behavior - %s", optarg);
434 }
435 e_flag = 1;
436 open_flag = EXT2_FLAG_RW;
437 break;
438 case 'f': /* Force */
439 f_flag = 1;
440 break;
441 case 'g':
442 resgid = bb_strtoul(optarg, NULL, 10);
443 if (errno)
444 resgid = bb_xgetgrnam(optarg);
445 g_flag = 1;
446 open_flag = EXT2_FLAG_RW;
447 break;
448 case 'i':
449 interval = strtoul(optarg, &tmp, 0);
450 switch (*tmp) {
451 case 's':
452 tmp++;
453 break;
454 case '\0':
455 case 'd':
456 case 'D': /* days */
457 interval *= 86400;
458 if (*tmp != '\0')
459 tmp++;
460 break;
461 case 'm':
462 case 'M': /* months! */
463 interval *= 86400 * 30;
464 tmp++;
465 break;
466 case 'w':
467 case 'W': /* weeks */
468 interval *= 86400 * 7;
469 tmp++;
470 break;
471 }
472 if (*tmp || interval > (365 * 86400)) {
473 bb_error_msg_and_die("bad interval - %s", optarg);
474 }
475 i_flag = 1;
476 open_flag = EXT2_FLAG_RW;
477 break;
478 case 'j':
479 if (!journal_size)
480 journal_size = -1;
481 open_flag = EXT2_FLAG_RW;
482 break;
483 case 'J':
484 parse_journal_opts(&journal_device, &journal_flags, &journal_size, optarg);
485 open_flag = EXT2_FLAG_RW;
486 break;
487 case 'l':
488 l_flag = 1;
489 break;
490 case 'L':
491 new_label = optarg;
492 L_flag = 1;
493 open_flag = EXT2_FLAG_RW |
494 EXT2_FLAG_JOURNAL_DEV_OK;
495 break;
496 case 'm':
497 reserved_ratio = xatou_range(optarg, 0, 50);
498 m_flag = 1;
499 open_flag = EXT2_FLAG_RW;
500 break;
501 case 'M':
502 new_last_mounted = optarg;
503 M_flag = 1;
504 open_flag = EXT2_FLAG_RW;
505 break;
506 case 'o':
507 if (mntopts_cmd) {
508 bb_error_msg_and_die("-o may only be specified once");
509 }
510 mntopts_cmd = optarg;
511 open_flag = EXT2_FLAG_RW;
512 break;
513
514 case 'O':
515 if (features_cmd) {
516 bb_error_msg_and_die("-O may only be specified once");
517 }
518 features_cmd = optarg;
519 open_flag = EXT2_FLAG_RW;
520 break;
521 case 'r':
522 reserved_blocks = xatoul(optarg);
523 r_flag = 1;
524 open_flag = EXT2_FLAG_RW;
525 break;
526 case 's':
527 s_flag = atoi(optarg);
528 open_flag = EXT2_FLAG_RW;
529 break;
530 case 'T':
531 T_flag = 1;
532 last_check_time = parse_time(optarg);
533 open_flag = EXT2_FLAG_RW;
534 break;
535 case 'u':
536 resuid = bb_strtoul(optarg, NULL, 10);
537 if (errno)
538 resuid = bb_xgetpwnam(optarg);
539 u_flag = 1;
540 open_flag = EXT2_FLAG_RW;
541 break;
542 case 'U':
543 new_UUID = optarg;
544 U_flag = 1;
545 open_flag = EXT2_FLAG_RW |
546 EXT2_FLAG_JOURNAL_DEV_OK;
547 break;
548 default:
549 bb_show_usage();
550 }
551 if (optind < argc - 1 || optind == argc)
552 bb_show_usage();
553 if (!open_flag && !l_flag)
554 bb_show_usage();
555 io_options = strchr(argv[optind], '?');
556 if (io_options)
557 *io_options++ = 0;
558 device_name = x_blkid_get_devname(argv[optind]);
559}
560
561#ifdef CONFIG_FINDFS
562static ATTRIBUTE_NORETURN void do_findfs(int argc, char **argv)
563{
564 if ((argc != 2) ||
565 (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5)))
566 bb_show_usage();
567 device_name = x_blkid_get_devname(argv[1]);
568 puts(device_name);
569 exit(0);
570}
571#else
572#define do_findfs(x, y)
573#endif
574
575static void tune2fs_clean_up(void)
576{
577 if (ENABLE_FEATURE_CLEAN_UP && device_name) free(device_name);
578 if (ENABLE_FEATURE_CLEAN_UP && journal_device) free(journal_device);
579}
580
581int tune2fs_main(int argc, char **argv)
582{
583 errcode_t retval;
584 ext2_filsys fs;
585 struct ext2_super_block *sb;
586 io_manager io_ptr;
587
588 if (ENABLE_FEATURE_CLEAN_UP)
589 atexit(tune2fs_clean_up);
590
591 if (ENABLE_FINDFS && (applet_name[0] == 'f')) /* findfs */
592 do_findfs(argc, argv); /* no return */
593 else if (ENABLE_E2LABEL && (applet_name[0] == 'e')) /* e2label */
594 parse_e2label_options(argc, argv);
595 else
596 parse_tune2fs_options(argc, argv); /* tune2fs */
597
598 io_ptr = unix_io_manager;
599 retval = ext2fs_open2(device_name, io_options, open_flag,
600 0, 0, io_ptr, &fs);
601 if (retval)
602 bb_error_msg_and_die("No valid superblock on %s", device_name);
603 sb = fs->super;
604 if (print_label) {
605 /* For e2label emulation */
606 printf("%.*s\n", (int) sizeof(sb->s_volume_name),
607 sb->s_volume_name);
608 return 0;
609 }
610 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
611 if (retval)
612 bb_error_msg_and_die("cannot determine if %s is mounted", device_name);
613 /* Normally we only need to write out the superblock */
614 fs->flags |= EXT2_FLAG_SUPER_ONLY;
615
616 if (c_flag) {
617 sb->s_max_mnt_count = max_mount_count;
618 ext2fs_mark_super_dirty(fs);
619 printf("Setting maximal mount count to %d\n", max_mount_count);
620 }
621 if (C_flag) {
622 sb->s_mnt_count = mount_count;
623 ext2fs_mark_super_dirty(fs);
624 printf("Setting current mount count to %d\n", mount_count);
625 }
626 if (e_flag) {
627 sb->s_errors = errors;
628 ext2fs_mark_super_dirty(fs);
629 printf("Setting error behavior to %d\n", errors);
630 }
631 if (g_flag) {
632 sb->s_def_resgid = resgid;
633 ext2fs_mark_super_dirty(fs);
634 printf("Setting reserved blocks gid to %lu\n", resgid);
635 }
636 if (i_flag) {
637 sb->s_checkinterval = interval;
638 ext2fs_mark_super_dirty(fs);
639 printf("Setting interval between check %lu seconds\n", interval);
640 }
641 if (m_flag) {
642 sb->s_r_blocks_count = (sb->s_blocks_count / 100)
643 * reserved_ratio;
644 ext2fs_mark_super_dirty(fs);
645 printf("Setting reserved blocks percentage to %u (%u blocks)\n",
646 reserved_ratio, sb->s_r_blocks_count);
647 }
648 if (r_flag) {
649 if (reserved_blocks >= sb->s_blocks_count/2)
650 bb_error_msg_and_die("reserved blocks count is too big (%lu)", reserved_blocks);
651 sb->s_r_blocks_count = reserved_blocks;
652 ext2fs_mark_super_dirty(fs);
653 printf("Setting reserved blocks count to %lu\n", reserved_blocks);
654 }
655 if (s_flag == 1) {
656 if (sb->s_feature_ro_compat &
657 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
658 bb_error_msg("\nThe filesystem already has sparse superblocks");
659 else {
660 sb->s_feature_ro_compat |=
661 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
662 sb->s_state &= ~EXT2_VALID_FS;
663 ext2fs_mark_super_dirty(fs);
664 printf("\nSparse superblock flag set. %s", please_fsck);
665 }
666 }
667 if (s_flag == 0) {
668 if (!(sb->s_feature_ro_compat &
669 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
670 bb_error_msg("\nThe filesystem already has sparse superblocks disabled");
671 else {
672 sb->s_feature_ro_compat &=
673 ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
674 sb->s_state &= ~EXT2_VALID_FS;
675 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
676 ext2fs_mark_super_dirty(fs);
677 printf("\nSparse superblock flag cleared. %s", please_fsck);
678 }
679 }
680 if (T_flag) {
681 sb->s_lastcheck = last_check_time;
682 ext2fs_mark_super_dirty(fs);
683 printf("Setting time filesystem last checked to %s\n",
684 ctime(&last_check_time));
685 }
686 if (u_flag) {
687 sb->s_def_resuid = resuid;
688 ext2fs_mark_super_dirty(fs);
689 printf("Setting reserved blocks uid to %lu\n", resuid);
690 }
691 if (L_flag) {
692 if (strlen(new_label) > sizeof(sb->s_volume_name))
693 bb_error_msg("Warning: label too long, truncating");
694 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
695 safe_strncpy(sb->s_volume_name, new_label,
696 sizeof(sb->s_volume_name));
697 ext2fs_mark_super_dirty(fs);
698 }
699 if (M_flag) {
700 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
701 safe_strncpy(sb->s_last_mounted, new_last_mounted,
702 sizeof(sb->s_last_mounted));
703 ext2fs_mark_super_dirty(fs);
704 }
705 if (mntopts_cmd)
706 update_mntopts(fs, mntopts_cmd);
707 if (features_cmd)
708 update_feature_set(fs, features_cmd);
709 if (journal_size || journal_device)
710 add_journal(fs);
711
712 if (U_flag) {
713 if ((strcasecmp(new_UUID, "null") == 0) ||
714 (strcasecmp(new_UUID, "clear") == 0)) {
715 uuid_clear(sb->s_uuid);
716 } else if (strcasecmp(new_UUID, "time") == 0) {
717 uuid_generate_time(sb->s_uuid);
718 } else if (strcasecmp(new_UUID, "random") == 0) {
719 uuid_generate(sb->s_uuid);
720 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
721 bb_error_msg_and_die("Invalid UUID format");
722 }
723 ext2fs_mark_super_dirty(fs);
724 }
725
726 if (l_flag)
727 list_super (sb);
728 return (ext2fs_close (fs) ? 1 : 0);
729}
diff --git a/e2fsprogs/old_e2fsprogs/util.c b/e2fsprogs/old_e2fsprogs/util.c
new file mode 100644
index 000000000..b30c294b8
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/util.c
@@ -0,0 +1,267 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * util.c --- helper functions used by tune2fs and mke2fs
4 *
5 * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13#include <stdio.h>
14#include <string.h>
15#include <errno.h>
16#include <linux/major.h>
17#include <sys/stat.h>
18
19#include "e2fsbb.h"
20#include "e2p/e2p.h"
21#include "ext2fs/ext2_fs.h"
22#include "ext2fs/ext2fs.h"
23#include "blkid/blkid.h"
24#include "util.h"
25
26void proceed_question(void)
27{
28 fputs("Proceed anyway? (y,n) ", stdout);
29 if (bb_ask_confirmation() == 0)
30 exit(1);
31}
32
33void check_plausibility(const char *device, int force)
34{
35 int val;
36 struct stat s;
37 val = stat(device, &s);
38 if (force)
39 return;
40 if(val == -1)
41 bb_perror_msg_and_die("cannot stat %s", device);
42 if (!S_ISBLK(s.st_mode)) {
43 printf("%s is not a block special device.\n", device);
44 proceed_question();
45 return;
46 }
47
48#ifdef HAVE_LINUX_MAJOR_H
49#ifndef MAJOR
50#define MAJOR(dev) ((dev)>>8)
51#define MINOR(dev) ((dev) & 0xff)
52#endif
53#ifndef SCSI_BLK_MAJOR
54#ifdef SCSI_DISK0_MAJOR
55#ifdef SCSI_DISK8_MAJOR
56#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
57 ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \
58 ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR))
59#else
60#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
61 ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
62#endif /* defined(SCSI_DISK8_MAJOR) */
63#define SCSI_BLK_MAJOR(M) (SCSI_DISK_MAJOR((M)) || (M) == SCSI_CDROM_MAJOR)
64#else
65#define SCSI_BLK_MAJOR(M) ((M) == SCSI_DISK_MAJOR || (M) == SCSI_CDROM_MAJOR)
66#endif /* defined(SCSI_DISK0_MAJOR) */
67#endif /* defined(SCSI_BLK_MAJOR) */
68 if (((MAJOR(s.st_rdev) == HD_MAJOR &&
69 MINOR(s.st_rdev)%64 == 0) ||
70 (SCSI_BLK_MAJOR(MAJOR(s.st_rdev)) &&
71 MINOR(s.st_rdev)%16 == 0))) {
72 printf("%s is entire device, not just one partition!\n", device);
73 proceed_question();
74 }
75#endif
76}
77
78void check_mount(const char *device, int force, const char *type)
79{
80 errcode_t retval;
81 int mount_flags;
82
83 retval = ext2fs_check_if_mounted(device, &mount_flags);
84 if (retval) {
85 bb_error_msg("cannot determine if %s is mounted", device);
86 return;
87 }
88 if (mount_flags & EXT2_MF_MOUNTED) {
89 bb_error_msg("%s is mounted !", device);
90force_check:
91 if (force)
92 bb_error_msg("badblocks forced anyways");
93 else
94 bb_error_msg_and_die("it's not safe to run badblocks!");
95 }
96
97 if (mount_flags & EXT2_MF_BUSY) {
98 bb_error_msg("%s is apparently in use by the system", device);
99 goto force_check;
100 }
101
102}
103
104void parse_journal_opts(char **journal_device, int *journal_flags,
105 int *journal_size, const char *opts)
106{
107 char *buf, *token, *next, *p, *arg;
108 int journal_usage = 0;
109 buf = xstrdup(opts);
110 for (token = buf; token && *token; token = next) {
111 p = strchr(token, ',');
112 next = 0;
113 if (p) {
114 *p = 0;
115 next = p+1;
116 }
117 arg = strchr(token, '=');
118 if (arg) {
119 *arg = 0;
120 arg++;
121 }
122 if (strcmp(token, "device") == 0) {
123 *journal_device = blkid_get_devname(NULL, arg, NULL);
124 if (!journal_device) {
125 journal_usage++;
126 continue;
127 }
128 } else if (strcmp(token, "size") == 0) {
129 if (!arg) {
130 journal_usage++;
131 continue;
132 }
133 (*journal_size) = strtoul(arg, &p, 0);
134 if (*p)
135 journal_usage++;
136 } else if (strcmp(token, "v1_superblock") == 0) {
137 (*journal_flags) |= EXT2_MKJOURNAL_V1_SUPER;
138 continue;
139 } else
140 journal_usage++;
141 }
142 if (journal_usage)
143 bb_error_msg_and_die(
144 "\nBad journal options specified.\n\n"
145 "Journal options are separated by commas, "
146 "and may take an argument which\n"
147 "\tis set off by an equals ('=') sign.\n\n"
148 "Valid journal options are:\n"
149 "\tsize=<journal size in megabytes>\n"
150 "\tdevice=<journal device>\n\n"
151 "The journal size must be between "
152 "1024 and 102400 filesystem blocks.\n\n");
153}
154
155/*
156 * Determine the number of journal blocks to use, either via
157 * user-specified # of megabytes, or via some intelligently selected
158 * defaults.
159 *
160 * Find a reasonable journal file size (in blocks) given the number of blocks
161 * in the filesystem. For very small filesystems, it is not reasonable to
162 * have a journal that fills more than half of the filesystem.
163 */
164int figure_journal_size(int size, ext2_filsys fs)
165{
166 blk_t j_blocks;
167
168 if (fs->super->s_blocks_count < 2048) {
169 bb_error_msg("Filesystem too small for a journal");
170 return 0;
171 }
172
173 if (size >= 0) {
174 j_blocks = size * 1024 / (fs->blocksize / 1024);
175 if (j_blocks < 1024 || j_blocks > 102400)
176 bb_error_msg_and_die("\nThe requested journal "
177 "size is %d blocks;\n it must be "
178 "between 1024 and 102400 blocks; Aborting",
179 j_blocks);
180 if (j_blocks > fs->super->s_free_blocks_count)
181 bb_error_msg_and_die("Journal size too big for filesystem");
182 return j_blocks;
183 }
184
185 if (fs->super->s_blocks_count < 32768)
186 j_blocks = 1024;
187 else if (fs->super->s_blocks_count < 256*1024)
188 j_blocks = 4096;
189 else if (fs->super->s_blocks_count < 512*1024)
190 j_blocks = 8192;
191 else if (fs->super->s_blocks_count < 1024*1024)
192 j_blocks = 16384;
193 else
194 j_blocks = 32768;
195
196 return j_blocks;
197}
198
199void print_check_message(ext2_filsys fs)
200{
201 printf("This filesystem will be automatically "
202 "checked every %d mounts or\n"
203 "%g days, whichever comes first. "
204 "Use tune2fs -c or -i to override.\n",
205 fs->super->s_max_mnt_count,
206 (double)fs->super->s_checkinterval / (3600 * 24));
207}
208
209void make_journal_device(char *journal_device, ext2_filsys fs, int quiet, int force)
210{
211 errcode_t retval;
212 ext2_filsys jfs;
213 io_manager io_ptr;
214
215 check_plausibility(journal_device, force);
216 check_mount(journal_device, force, "journal");
217 io_ptr = unix_io_manager;
218 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
219 EXT2_FLAG_JOURNAL_DEV_OK, 0,
220 fs->blocksize, io_ptr, &jfs);
221 if (retval)
222 bb_error_msg_and_die("cannot journal device %s", journal_device);
223 if(!quiet)
224 printf("Adding journal to device %s: ", journal_device);
225 fflush(stdout);
226 retval = ext2fs_add_journal_device(fs, jfs);
227 if(retval)
228 bb_error_msg_and_die("\nFailed to add journal to device %s", journal_device);
229 if(!quiet)
230 puts("done");
231 ext2fs_close(jfs);
232}
233
234void make_journal_blocks(ext2_filsys fs, int journal_size, int journal_flags, int quiet)
235{
236 unsigned long journal_blocks;
237 errcode_t retval;
238
239 journal_blocks = figure_journal_size(journal_size, fs);
240 if (!journal_blocks) {
241 fs->super->s_feature_compat &=
242 ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
243 return;
244 }
245 if(!quiet)
246 printf("Creating journal (%ld blocks): ", journal_blocks);
247 fflush(stdout);
248 retval = ext2fs_add_journal_inode(fs, journal_blocks,
249 journal_flags);
250 if(retval)
251 bb_error_msg_and_die("cannot create journal");
252 if(!quiet)
253 puts("done");
254}
255
256char *e2fs_set_sbin_path(void)
257{
258 char *oldpath = getenv("PATH");
259 /* Update our PATH to include /sbin */
260#define PATH_SET "/sbin"
261 if (oldpath)
262 oldpath = xasprintf("%s:%s", PATH_SET, oldpath);
263 else
264 oldpath = PATH_SET;
265 putenv (oldpath);
266 return oldpath;
267}
diff --git a/e2fsprogs/old_e2fsprogs/util.h b/e2fsprogs/old_e2fsprogs/util.h
new file mode 100644
index 000000000..80d241718
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/util.h
@@ -0,0 +1,22 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * util.h --- header file defining prototypes for helper functions
4 * used by tune2fs and mke2fs
5 *
6 * Copyright 2000 by Theodore Ts'o.
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14extern void proceed_question(void);
15extern void check_plausibility(const char *device, int force);
16extern void parse_journal_opts(char **, int *, int *, const char *opts);
17extern void check_mount(const char *device, int force, const char *type);
18extern int figure_journal_size(int size, ext2_filsys fs);
19extern void print_check_message(ext2_filsys fs);
20extern void make_journal_device(char *journal_device, ext2_filsys fs, int quiet, int force);
21extern void make_journal_blocks(ext2_filsys fs, int journal_size, int journal_flags, int quiet);
22extern char *e2fs_set_sbin_path(void);
diff --git a/e2fsprogs/old_e2fsprogs/uuid/Kbuild b/e2fsprogs/old_e2fsprogs/uuid/Kbuild
new file mode 100644
index 000000000..dde981840
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/Kbuild
@@ -0,0 +1,14 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7NEEDED-$(CONFIG_E2FSCK) = y
8NEEDED-$(CONFIG_FSCK) = y
9NEEDED-$(CONFIG_MKE2FS) = y
10NEEDED-$(CONFIG_TUNE2FS) = y
11
12lib-y:=
13lib-$(NEEDED-y) += compare.o gen_uuid.o pack.o parse.o unpack.o unparse.o \
14 uuid_time.o
diff --git a/e2fsprogs/old_e2fsprogs/uuid/compare.c b/e2fsprogs/old_e2fsprogs/uuid/compare.c
new file mode 100644
index 000000000..348ea7c1f
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/compare.c
@@ -0,0 +1,55 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * compare.c --- compare whether or not two UUID's are the same
4 *
5 * Returns 0 if the two UUID's are different, and 1 if they are the same.
6 *
7 * Copyright (C) 1996, 1997 Theodore Ts'o.
8 *
9 * %Begin-Header%
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, and the entire permission notice in its entirety,
15 * including the disclaimer of warranties.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
26 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
34 * DAMAGE.
35 * %End-Header%
36 */
37
38#include "uuidP.h"
39#include <string.h>
40
41#define UUCMP(u1,u2) if (u1 != u2) return (u1 < u2) ? -1 : 1;
42
43int uuid_compare(const uuid_t uu1, const uuid_t uu2)
44{
45 struct uuid uuid1, uuid2;
46
47 uuid_unpack(uu1, &uuid1);
48 uuid_unpack(uu2, &uuid2);
49
50 UUCMP(uuid1.time_low, uuid2.time_low);
51 UUCMP(uuid1.time_mid, uuid2.time_mid);
52 UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
53 UUCMP(uuid1.clock_seq, uuid2.clock_seq);
54 return memcmp(uuid1.node, uuid2.node, 6);
55}
diff --git a/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c b/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c
new file mode 100644
index 000000000..9d700a015
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/gen_uuid.c
@@ -0,0 +1,305 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * gen_uuid.c --- generate a DCE-compatible uuid
4 *
5 * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, and the entire permission notice in its entirety,
13 * including the disclaimer of warranties.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
24 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
32 * DAMAGE.
33 * %End-Header%
34 */
35
36#include <unistd.h>
37#include <stdlib.h>
38#include <string.h>
39#include <fcntl.h>
40#include <errno.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <sys/file.h>
44#include <sys/time.h>
45#ifdef HAVE_SYS_IOCTL_H
46#include <sys/ioctl.h>
47#endif
48#include <sys/socket.h>
49#ifdef HAVE_SYS_SOCKIO_H
50#include <sys/sockio.h>
51#endif
52#ifdef HAVE_NET_IF_H
53#include <net/if.h>
54#endif
55#ifdef HAVE_NETINET_IN_H
56#include <netinet/in.h>
57#endif
58#ifdef HAVE_NET_IF_DL_H
59#include <net/if_dl.h>
60#endif
61
62#include "uuidP.h"
63
64#ifdef HAVE_SRANDOM
65#define srand(x) srandom(x)
66#define rand() random()
67#endif
68
69static int get_random_fd(void)
70{
71 struct timeval tv;
72 static int fd = -2;
73 int i;
74
75 if (fd == -2) {
76 gettimeofday(&tv, 0);
77 fd = open("/dev/urandom", O_RDONLY);
78 if (fd == -1)
79 fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
80 srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
81 }
82 /* Crank the random number generator a few times */
83 gettimeofday(&tv, 0);
84 for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
85 rand();
86 return fd;
87}
88
89
90/*
91 * Generate a series of random bytes. Use /dev/urandom if possible,
92 * and if not, use srandom/random.
93 */
94static void get_random_bytes(void *buf, int nbytes)
95{
96 int i, n = nbytes, fd = get_random_fd();
97 int lose_counter = 0;
98 unsigned char *cp = (unsigned char *) buf;
99
100 if (fd >= 0) {
101 while (n > 0) {
102 i = read(fd, cp, n);
103 if (i <= 0) {
104 if (lose_counter++ > 16)
105 break;
106 continue;
107 }
108 n -= i;
109 cp += i;
110 lose_counter = 0;
111 }
112 }
113
114 /*
115 * We do this all the time, but this is the only source of
116 * randomness if /dev/random/urandom is out to lunch.
117 */
118 for (cp = buf, i = 0; i < nbytes; i++)
119 *cp++ ^= (rand() >> 7) & 0xFF;
120 return;
121}
122
123/*
124 * Get the ethernet hardware address, if we can find it...
125 */
126static int get_node_id(unsigned char *node_id)
127{
128#ifdef HAVE_NET_IF_H
129 int sd;
130 struct ifreq ifr, *ifrp;
131 struct ifconf ifc;
132 char buf[1024];
133 int n, i;
134 unsigned char *a;
135#ifdef HAVE_NET_IF_DL_H
136 struct sockaddr_dl *sdlp;
137#endif
138
139/*
140 * BSD 4.4 defines the size of an ifreq to be
141 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
142 * However, under earlier systems, sa_len isn't present, so the size is
143 * just sizeof(struct ifreq)
144 */
145#ifdef HAVE_SA_LEN
146#ifndef max
147#define max(a,b) ((a) > (b) ? (a) : (b))
148#endif
149#define ifreq_size(i) max(sizeof(struct ifreq),\
150 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
151#else
152#define ifreq_size(i) sizeof(struct ifreq)
153#endif /* HAVE_SA_LEN*/
154
155 sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
156 if (sd < 0) {
157 return -1;
158 }
159 memset(buf, 0, sizeof(buf));
160 ifc.ifc_len = sizeof(buf);
161 ifc.ifc_buf = buf;
162 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
163 close(sd);
164 return -1;
165 }
166 n = ifc.ifc_len;
167 for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
168 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
169 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
170#ifdef SIOCGIFHWADDR
171 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
172 continue;
173 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
174#else
175#ifdef SIOCGENADDR
176 if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
177 continue;
178 a = (unsigned char *) ifr.ifr_enaddr;
179#else
180#ifdef HAVE_NET_IF_DL_H
181 sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
182 if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
183 continue;
184 a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
185#else
186 /*
187 * XXX we don't have a way of getting the hardware
188 * address
189 */
190 close(sd);
191 return 0;
192#endif /* HAVE_NET_IF_DL_H */
193#endif /* SIOCGENADDR */
194#endif /* SIOCGIFHWADDR */
195 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
196 continue;
197 if (node_id) {
198 memcpy(node_id, a, 6);
199 close(sd);
200 return 1;
201 }
202 }
203 close(sd);
204#endif
205 return 0;
206}
207
208/* Assume that the gettimeofday() has microsecond granularity */
209#define MAX_ADJUSTMENT 10
210
211static int get_clock(uint32_t *clock_high, uint32_t *clock_low, uint16_t *ret_clock_seq)
212{
213 static int adjustment = 0;
214 static struct timeval last = {0, 0};
215 static uint16_t clock_seq;
216 struct timeval tv;
217 unsigned long long clock_reg;
218
219try_again:
220 gettimeofday(&tv, 0);
221 if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
222 get_random_bytes(&clock_seq, sizeof(clock_seq));
223 clock_seq &= 0x3FFF;
224 last = tv;
225 last.tv_sec--;
226 }
227 if ((tv.tv_sec < last.tv_sec) ||
228 ((tv.tv_sec == last.tv_sec) &&
229 (tv.tv_usec < last.tv_usec))) {
230 clock_seq = (clock_seq+1) & 0x3FFF;
231 adjustment = 0;
232 last = tv;
233 } else if ((tv.tv_sec == last.tv_sec) &&
234 (tv.tv_usec == last.tv_usec)) {
235 if (adjustment >= MAX_ADJUSTMENT)
236 goto try_again;
237 adjustment++;
238 } else {
239 adjustment = 0;
240 last = tv;
241 }
242
243 clock_reg = tv.tv_usec*10 + adjustment;
244 clock_reg += ((unsigned long long) tv.tv_sec)*10000000;
245 clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
246
247 *clock_high = clock_reg >> 32;
248 *clock_low = clock_reg;
249 *ret_clock_seq = clock_seq;
250 return 0;
251}
252
253void uuid_generate_time(uuid_t out)
254{
255 static unsigned char node_id[6];
256 static int has_init = 0;
257 struct uuid uu;
258 uint32_t clock_mid;
259
260 if (!has_init) {
261 if (get_node_id(node_id) <= 0) {
262 get_random_bytes(node_id, 6);
263 /*
264 * Set multicast bit, to prevent conflicts
265 * with IEEE 802 addresses obtained from
266 * network cards
267 */
268 node_id[0] |= 0x01;
269 }
270 has_init = 1;
271 }
272 get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
273 uu.clock_seq |= 0x8000;
274 uu.time_mid = (uint16_t) clock_mid;
275 uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
276 memcpy(uu.node, node_id, 6);
277 uuid_pack(&uu, out);
278}
279
280void uuid_generate_random(uuid_t out)
281{
282 uuid_t buf;
283 struct uuid uu;
284
285 get_random_bytes(buf, sizeof(buf));
286 uuid_unpack(buf, &uu);
287
288 uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
289 uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
290 uuid_pack(&uu, out);
291}
292
293/*
294 * This is the generic front-end to uuid_generate_random and
295 * uuid_generate_time. It uses uuid_generate_random only if
296 * /dev/urandom is available, since otherwise we won't have
297 * high-quality randomness.
298 */
299void uuid_generate(uuid_t out)
300{
301 if (get_random_fd() >= 0)
302 uuid_generate_random(out);
303 else
304 uuid_generate_time(out);
305}
diff --git a/e2fsprogs/old_e2fsprogs/uuid/pack.c b/e2fsprogs/old_e2fsprogs/uuid/pack.c
new file mode 100644
index 000000000..217cfce5d
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/pack.c
@@ -0,0 +1,69 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Internal routine for packing UUID's
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, and the entire permission notice in its entirety,
13 * including the disclaimer of warranties.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
24 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
32 * DAMAGE.
33 * %End-Header%
34 */
35
36#include <string.h>
37#include "uuidP.h"
38
39void uuid_pack(const struct uuid *uu, uuid_t ptr)
40{
41 uint32_t tmp;
42 unsigned char *out = ptr;
43
44 tmp = uu->time_low;
45 out[3] = (unsigned char) tmp;
46 tmp >>= 8;
47 out[2] = (unsigned char) tmp;
48 tmp >>= 8;
49 out[1] = (unsigned char) tmp;
50 tmp >>= 8;
51 out[0] = (unsigned char) tmp;
52
53 tmp = uu->time_mid;
54 out[5] = (unsigned char) tmp;
55 tmp >>= 8;
56 out[4] = (unsigned char) tmp;
57
58 tmp = uu->time_hi_and_version;
59 out[7] = (unsigned char) tmp;
60 tmp >>= 8;
61 out[6] = (unsigned char) tmp;
62
63 tmp = uu->clock_seq;
64 out[9] = (unsigned char) tmp;
65 tmp >>= 8;
66 out[8] = (unsigned char) tmp;
67
68 memcpy(out+10, uu->node, 6);
69}
diff --git a/e2fsprogs/old_e2fsprogs/uuid/parse.c b/e2fsprogs/old_e2fsprogs/uuid/parse.c
new file mode 100644
index 000000000..9a3f9cb92
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/parse.c
@@ -0,0 +1,80 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * parse.c --- UUID parsing
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, and the entire permission notice in its entirety,
13 * including the disclaimer of warranties.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
24 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
32 * DAMAGE.
33 * %End-Header%
34 */
35
36#include <stdlib.h>
37#include <stdio.h>
38#include <ctype.h>
39#include <string.h>
40
41#include "uuidP.h"
42
43int uuid_parse(const char *in, uuid_t uu)
44{
45 struct uuid uuid;
46 int i;
47 const char *cp;
48 char buf[3];
49
50 if (strlen(in) != 36)
51 return -1;
52 for (i=0, cp = in; i <= 36; i++,cp++) {
53 if ((i == 8) || (i == 13) || (i == 18) ||
54 (i == 23)) {
55 if (*cp == '-')
56 continue;
57 else
58 return -1;
59 }
60 if (i== 36)
61 if (*cp == 0)
62 continue;
63 if (!isxdigit(*cp))
64 return -1;
65 }
66 uuid.time_low = strtoul(in, NULL, 16);
67 uuid.time_mid = strtoul(in+9, NULL, 16);
68 uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
69 uuid.clock_seq = strtoul(in+19, NULL, 16);
70 cp = in+24;
71 buf[2] = 0;
72 for (i=0; i < 6; i++) {
73 buf[0] = *cp++;
74 buf[1] = *cp++;
75 uuid.node[i] = strtoul(buf, NULL, 16);
76 }
77
78 uuid_pack(&uuid, uu);
79 return 0;
80}
diff --git a/e2fsprogs/old_e2fsprogs/uuid/unpack.c b/e2fsprogs/old_e2fsprogs/uuid/unpack.c
new file mode 100644
index 000000000..95d3aab4a
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/unpack.c
@@ -0,0 +1,63 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Internal routine for unpacking UUID
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, and the entire permission notice in its entirety,
13 * including the disclaimer of warranties.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
24 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
32 * DAMAGE.
33 * %End-Header%
34 */
35
36#include <string.h>
37#include "uuidP.h"
38
39void uuid_unpack(const uuid_t in, struct uuid *uu)
40{
41 const uint8_t *ptr = in;
42 uint32_t tmp;
43
44 tmp = *ptr++;
45 tmp = (tmp << 8) | *ptr++;
46 tmp = (tmp << 8) | *ptr++;
47 tmp = (tmp << 8) | *ptr++;
48 uu->time_low = tmp;
49
50 tmp = *ptr++;
51 tmp = (tmp << 8) | *ptr++;
52 uu->time_mid = tmp;
53
54 tmp = *ptr++;
55 tmp = (tmp << 8) | *ptr++;
56 uu->time_hi_and_version = tmp;
57
58 tmp = *ptr++;
59 tmp = (tmp << 8) | *ptr++;
60 uu->clock_seq = tmp;
61
62 memcpy(uu->node, ptr, 6);
63}
diff --git a/e2fsprogs/old_e2fsprogs/uuid/unparse.c b/e2fsprogs/old_e2fsprogs/uuid/unparse.c
new file mode 100644
index 000000000..d2948fe6d
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/unparse.c
@@ -0,0 +1,77 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * unparse.c -- convert a UUID to string
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, and the entire permission notice in its entirety,
13 * including the disclaimer of warranties.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
24 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
32 * DAMAGE.
33 * %End-Header%
34 */
35
36#include <stdio.h>
37
38#include "uuidP.h"
39
40static const char *fmt_lower =
41 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
42
43static const char *fmt_upper =
44 "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X";
45
46#ifdef UUID_UNPARSE_DEFAULT_UPPER
47#define FMT_DEFAULT fmt_upper
48#else
49#define FMT_DEFAULT fmt_lower
50#endif
51
52static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt)
53{
54 struct uuid uuid;
55
56 uuid_unpack(uu, &uuid);
57 sprintf(out, fmt,
58 uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
59 uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
60 uuid.node[0], uuid.node[1], uuid.node[2],
61 uuid.node[3], uuid.node[4], uuid.node[5]);
62}
63
64void uuid_unparse_lower(const uuid_t uu, char *out)
65{
66 uuid_unparse_x(uu, out, fmt_lower);
67}
68
69void uuid_unparse_upper(const uuid_t uu, char *out)
70{
71 uuid_unparse_x(uu, out, fmt_upper);
72}
73
74void uuid_unparse(const uuid_t uu, char *out)
75{
76 uuid_unparse_x(uu, out, FMT_DEFAULT);
77}
diff --git a/e2fsprogs/old_e2fsprogs/uuid/uuid.h b/e2fsprogs/old_e2fsprogs/uuid/uuid.h
new file mode 100644
index 000000000..bd53b15d0
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/uuid.h
@@ -0,0 +1,104 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Public include file for the UUID library
4 *
5 * Copyright (C) 1996, 1997, 1998 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, and the entire permission notice in its entirety,
13 * including the disclaimer of warranties.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
24 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
32 * DAMAGE.
33 * %End-Header%
34 */
35
36#ifndef _UUID_UUID_H
37#define _UUID_UUID_H
38
39#include <sys/types.h>
40#include <time.h>
41
42typedef unsigned char uuid_t[16];
43
44/* UUID Variant definitions */
45#define UUID_VARIANT_NCS 0
46#define UUID_VARIANT_DCE 1
47#define UUID_VARIANT_MICROSOFT 2
48#define UUID_VARIANT_OTHER 3
49
50/* UUID Type definitions */
51#define UUID_TYPE_DCE_TIME 1
52#define UUID_TYPE_DCE_RANDOM 4
53
54/* Allow UUID constants to be defined */
55#ifdef __GNUC__
56#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
57 static const uuid_t name ATTRIBUTE_UNUSED = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
58#else
59#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
60 static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
61#endif
62
63#ifdef __cplusplus
64extern "C" {
65#endif
66
67/* clear.c */
68/*void uuid_clear(uuid_t uu);*/
69#define uuid_clear(uu) memset(uu, 0, sizeof(uu))
70
71/* compare.c */
72int uuid_compare(const uuid_t uu1, const uuid_t uu2);
73
74/* copy.c */
75/*void uuid_copy(uuid_t dst, const uuid_t src);*/
76#define uuid_copy(dst,src) memcpy(dst, src, sizeof(dst))
77
78/* gen_uuid.c */
79void uuid_generate(uuid_t out);
80void uuid_generate_random(uuid_t out);
81void uuid_generate_time(uuid_t out);
82
83/* isnull.c */
84/*int uuid_is_null(const uuid_t uu);*/
85#define uuid_is_null(uu) (!memcmp(uu, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(uu)))
86
87/* parse.c */
88int uuid_parse(const char *in, uuid_t uu);
89
90/* unparse.c */
91void uuid_unparse(const uuid_t uu, char *out);
92void uuid_unparse_lower(const uuid_t uu, char *out);
93void uuid_unparse_upper(const uuid_t uu, char *out);
94
95/* uuid_time.c */
96time_t uuid_time(const uuid_t uu, struct timeval *ret_tv);
97int uuid_type(const uuid_t uu);
98int uuid_variant(const uuid_t uu);
99
100#ifdef __cplusplus
101}
102#endif
103
104#endif /* _UUID_UUID_H */
diff --git a/e2fsprogs/old_e2fsprogs/uuid/uuidP.h b/e2fsprogs/old_e2fsprogs/uuid/uuidP.h
new file mode 100644
index 000000000..87041ef0a
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/uuidP.h
@@ -0,0 +1,60 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * uuid.h -- private header file for uuids
4 *
5 * Copyright (C) 1996, 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, and the entire permission notice in its entirety,
13 * including the disclaimer of warranties.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
24 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
32 * DAMAGE.
33 * %End-Header%
34 */
35
36#include <inttypes.h>
37#include <sys/types.h>
38
39#include "uuid.h"
40
41/*
42 * Offset between 15-Oct-1582 and 1-Jan-70
43 */
44#define TIME_OFFSET_HIGH 0x01B21DD2
45#define TIME_OFFSET_LOW 0x13814000
46
47struct uuid {
48 uint32_t time_low;
49 uint16_t time_mid;
50 uint16_t time_hi_and_version;
51 uint16_t clock_seq;
52 uint8_t node[6];
53};
54
55
56/*
57 * prototypes
58 */
59void uuid_pack(const struct uuid *uu, uuid_t ptr);
60void uuid_unpack(const uuid_t in, struct uuid *uu);
diff --git a/e2fsprogs/old_e2fsprogs/uuid/uuid_time.c b/e2fsprogs/old_e2fsprogs/uuid/uuid_time.c
new file mode 100644
index 000000000..b54d67322
--- /dev/null
+++ b/e2fsprogs/old_e2fsprogs/uuid/uuid_time.c
@@ -0,0 +1,161 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * uuid_time.c --- Interpret the time field from a uuid. This program
4 * violates the UUID abstraction barrier by reaching into the guts
5 * of a UUID and interpreting it.
6 *
7 * Copyright (C) 1998, 1999 Theodore Ts'o.
8 *
9 * %Begin-Header%
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, and the entire permission notice in its entirety,
15 * including the disclaimer of warranties.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
26 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
34 * DAMAGE.
35 * %End-Header%
36 */
37
38#include <stdio.h>
39#include <unistd.h>
40#include <stdlib.h>
41#include <sys/types.h>
42#include <time.h>
43
44#include "uuidP.h"
45
46time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
47{
48 struct uuid uuid;
49 uint32_t high;
50 struct timeval tv;
51 unsigned long long clock_reg;
52
53 uuid_unpack(uu, &uuid);
54
55 high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
56 clock_reg = uuid.time_low | ((unsigned long long) high << 32);
57
58 clock_reg -= (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
59 tv.tv_sec = clock_reg / 10000000;
60 tv.tv_usec = (clock_reg % 10000000) / 10;
61
62 if (ret_tv)
63 *ret_tv = tv;
64
65 return tv.tv_sec;
66}
67
68int uuid_type(const uuid_t uu)
69{
70 struct uuid uuid;
71
72 uuid_unpack(uu, &uuid);
73 return ((uuid.time_hi_and_version >> 12) & 0xF);
74}
75
76int uuid_variant(const uuid_t uu)
77{
78 struct uuid uuid;
79 int var;
80
81 uuid_unpack(uu, &uuid);
82 var = uuid.clock_seq;
83
84 if ((var & 0x8000) == 0)
85 return UUID_VARIANT_NCS;
86 if ((var & 0x4000) == 0)
87 return UUID_VARIANT_DCE;
88 if ((var & 0x2000) == 0)
89 return UUID_VARIANT_MICROSOFT;
90 return UUID_VARIANT_OTHER;
91}
92
93#ifdef DEBUG
94static const char *variant_string(int variant)
95{
96 switch (variant) {
97 case UUID_VARIANT_NCS:
98 return "NCS";
99 case UUID_VARIANT_DCE:
100 return "DCE";
101 case UUID_VARIANT_MICROSOFT:
102 return "Microsoft";
103 default:
104 return "Other";
105 }
106}
107
108
109int
110main(int argc, char **argv)
111{
112 uuid_t buf;
113 time_t time_reg;
114 struct timeval tv;
115 int type, variant;
116
117 if (argc != 2) {
118 fprintf(stderr, "Usage: %s uuid\n", argv[0]);
119 exit(1);
120 }
121 if (uuid_parse(argv[1], buf)) {
122 fprintf(stderr, "Invalid UUID: %s\n", argv[1]);
123 exit(1);
124 }
125 variant = uuid_variant(buf);
126 type = uuid_type(buf);
127 time_reg = uuid_time(buf, &tv);
128
129 printf("UUID variant is %d (%s)\n", variant, variant_string(variant));
130 if (variant != UUID_VARIANT_DCE) {
131 printf("Warning: This program only knows how to interpret "
132 "DCE UUIDs.\n\tThe rest of the output is likely "
133 "to be incorrect!!\n");
134 }
135 printf("UUID type is %d", type);
136 switch (type) {
137 case 1:
138 printf(" (time based)\n");
139 break;
140 case 2:
141 printf(" (DCE)\n");
142 break;
143 case 3:
144 printf(" (name-based)\n");
145 break;
146 case 4:
147 printf(" (random)\n");
148 break;
149 default:
150 puts("");
151 }
152 if (type != 1) {
153 printf("Warning: not a time-based UUID, so UUID time "
154 "decoding will likely not work!\n");
155 }
156 printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec,
157 ctime(&time_reg));
158
159 return 0;
160}
161#endif