aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2005-05-09 22:10:42 +0000
committerMike Frysinger <vapier@gentoo.org>2005-05-09 22:10:42 +0000
commit1fd98e039d146dcff02a5350f509cabca65fd29c (patch)
tree1564707d41a6271bb44cf3fa5b88b9cc70fedd35
parentb32011943a0764872ca1ea17f13b53176ace8e69 (diff)
downloadbusybox-w32-1fd98e039d146dcff02a5350f509cabca65fd29c.tar.gz
busybox-w32-1fd98e039d146dcff02a5350f509cabca65fd29c.tar.bz2
busybox-w32-1fd98e039d146dcff02a5350f509cabca65fd29c.zip
import ext2fs lib to prep for new e2fsprogs
-rw-r--r--e2fsprogs/ext2fs/alloc.c173
-rw-r--r--e2fsprogs/ext2fs/alloc_sb.c57
-rw-r--r--e2fsprogs/ext2fs/alloc_stats.c52
-rw-r--r--e2fsprogs/ext2fs/alloc_tables.c117
-rw-r--r--e2fsprogs/ext2fs/badblocks.c327
-rw-r--r--e2fsprogs/ext2fs/bb_compat.c63
-rw-r--r--e2fsprogs/ext2fs/bb_inode.c267
-rw-r--r--e2fsprogs/ext2fs/bitmaps.c212
-rw-r--r--e2fsprogs/ext2fs/bitops.c91
-rw-r--r--e2fsprogs/ext2fs/bitops.h617
-rw-r--r--e2fsprogs/ext2fs/block.c437
-rw-r--r--e2fsprogs/ext2fs/bmap.c270
-rw-r--r--e2fsprogs/ext2fs/bmove.c160
-rw-r--r--e2fsprogs/ext2fs/brel.h86
-rw-r--r--e2fsprogs/ext2fs/brel_ma.c197
-rw-r--r--e2fsprogs/ext2fs/check_desc.c68
-rw-r--r--e2fsprogs/ext2fs/closefs.c381
-rw-r--r--e2fsprogs/ext2fs/cmp_bitmaps.c72
-rw-r--r--e2fsprogs/ext2fs/dblist.c260
-rw-r--r--e2fsprogs/ext2fs/dblist_dir.c75
-rw-r--r--e2fsprogs/ext2fs/dir_iterate.c219
-rw-r--r--e2fsprogs/ext2fs/dirblock.c130
-rw-r--r--e2fsprogs/ext2fs/dirhash.c233
-rw-r--r--e2fsprogs/ext2fs/dosio.c456
-rw-r--r--e2fsprogs/ext2fs/dosio.h153
-rw-r--r--e2fsprogs/ext2fs/dupfs.c96
-rw-r--r--e2fsprogs/ext2fs/e2image.h51
-rw-r--r--e2fsprogs/ext2fs/expanddir.c126
-rw-r--r--e2fsprogs/ext2fs/ext2_err.h117
-rw-r--r--e2fsprogs/ext2fs/ext2_ext_attr.h69
-rw-r--r--e2fsprogs/ext2fs/ext2_fs.h644
-rw-r--r--e2fsprogs/ext2fs/ext2_io.h108
-rw-r--r--e2fsprogs/ext2fs/ext2_types.h1
-rw-r--r--e2fsprogs/ext2fs/ext2fs.h1137
-rw-r--r--e2fsprogs/ext2fs/ext2fsP.h88
-rw-r--r--e2fsprogs/ext2fs/ext_attr.c105
-rw-r--r--e2fsprogs/ext2fs/fileio.c378
-rw-r--r--e2fsprogs/ext2fs/finddev.c208
-rw-r--r--e2fsprogs/ext2fs/flushb.c82
-rw-r--r--e2fsprogs/ext2fs/freefs.c147
-rw-r--r--e2fsprogs/ext2fs/gen_bitmap.c48
-rw-r--r--e2fsprogs/ext2fs/get_pathname.c157
-rw-r--r--e2fsprogs/ext2fs/getsectsize.c57
-rw-r--r--e2fsprogs/ext2fs/getsize.c290
-rw-r--r--e2fsprogs/ext2fs/icount.c483
-rw-r--r--e2fsprogs/ext2fs/imager.c387
-rw-r--r--e2fsprogs/ext2fs/ind_block.c66
-rw-r--r--e2fsprogs/ext2fs/initialize.c387
-rw-r--r--e2fsprogs/ext2fs/inline.c32
-rw-r--r--e2fsprogs/ext2fs/inode.c794
-rw-r--r--e2fsprogs/ext2fs/inode_io.c270
-rw-r--r--e2fsprogs/ext2fs/io_manager.c69
-rw-r--r--e2fsprogs/ext2fs/irel.h114
-rw-r--r--e2fsprogs/ext2fs/irel_ma.c372
-rw-r--r--e2fsprogs/ext2fs/ismounted.c358
-rw-r--r--e2fsprogs/ext2fs/jfs_compat.h67
-rw-r--r--e2fsprogs/ext2fs/jfs_dat.h64
-rw-r--r--e2fsprogs/ext2fs/jfs_user.h8
-rw-r--r--e2fsprogs/ext2fs/kernel-jbd.h910
-rw-r--r--e2fsprogs/ext2fs/kernel-list.h112
-rw-r--r--e2fsprogs/ext2fs/link.c134
-rw-r--r--e2fsprogs/ext2fs/llseek.c135
-rw-r--r--e2fsprogs/ext2fs/lookup.c69
-rw-r--r--e2fsprogs/ext2fs/mkdir.c142
-rw-r--r--e2fsprogs/ext2fs/mkjournal.c425
-rw-r--r--e2fsprogs/ext2fs/namei.c205
-rw-r--r--e2fsprogs/ext2fs/native.c27
-rw-r--r--e2fsprogs/ext2fs/newdir.c72
-rw-r--r--e2fsprogs/ext2fs/openfs.c326
-rw-r--r--e2fsprogs/ext2fs/read_bb.c97
-rw-r--r--e2fsprogs/ext2fs/read_bb_file.c97
-rw-r--r--e2fsprogs/ext2fs/res_gdt.c220
-rw-r--r--e2fsprogs/ext2fs/rs_bitmap.c106
-rw-r--r--e2fsprogs/ext2fs/rw_bitmaps.c300
-rw-r--r--e2fsprogs/ext2fs/sparse.c78
-rw-r--r--e2fsprogs/ext2fs/swapfs.c237
-rw-r--r--e2fsprogs/ext2fs/test_io.c382
-rw-r--r--e2fsprogs/ext2fs/unix_io.c707
-rw-r--r--e2fsprogs/ext2fs/unlink.c99
-rw-r--r--e2fsprogs/ext2fs/valid_blk.c56
-rw-r--r--e2fsprogs/ext2fs/version.c52
-rw-r--r--e2fsprogs/ext2fs/write_bb_file.c34
82 files changed, 17575 insertions, 0 deletions
diff --git a/e2fsprogs/ext2fs/alloc.c b/e2fsprogs/ext2fs/alloc.c
new file mode 100644
index 000000000..7385123b8
--- /dev/null
+++ b/e2fsprogs/ext2fs/alloc.c
@@ -0,0 +1,173 @@
1/*
2 * alloc.c --- allocate new inodes, blocks for ext2fs
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
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#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28
29/*
30 * Right now, just search forward from the parent directory's block
31 * group to find the next free inode.
32 *
33 * Should have a special policy for directories.
34 */
35errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
36 int mode EXT2FS_ATTR((unused)),
37 ext2fs_inode_bitmap map, ext2_ino_t *ret)
38{
39 ext2_ino_t dir_group = 0;
40 ext2_ino_t i;
41 ext2_ino_t start_inode;
42
43 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
44
45 if (!map)
46 map = fs->inode_map;
47 if (!map)
48 return EXT2_ET_NO_INODE_BITMAP;
49
50 if (dir > 0)
51 dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
52
53 start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
54 if (start_inode < EXT2_FIRST_INODE(fs->super))
55 start_inode = EXT2_FIRST_INODE(fs->super);
56 i = start_inode;
57
58 do {
59 if (!ext2fs_fast_test_inode_bitmap(map, i))
60 break;
61 i++;
62 if (i > fs->super->s_inodes_count)
63 i = EXT2_FIRST_INODE(fs->super);
64 } while (i != start_inode);
65
66 if (ext2fs_test_inode_bitmap(map, i))
67 return EXT2_ET_INODE_ALLOC_FAIL;
68 *ret = i;
69 return 0;
70}
71
72/*
73 * Stupid algorithm --- we now just search forward starting from the
74 * goal. Should put in a smarter one someday....
75 */
76errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
77 ext2fs_block_bitmap map, blk_t *ret)
78{
79 blk_t i;
80
81 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
82
83 if (!map)
84 map = fs->block_map;
85 if (!map)
86 return EXT2_ET_NO_BLOCK_BITMAP;
87 if (!goal || (goal >= fs->super->s_blocks_count))
88 goal = fs->super->s_first_data_block;
89 i = goal;
90 do {
91 if (!ext2fs_fast_test_block_bitmap(map, i)) {
92 *ret = i;
93 return 0;
94 }
95 i++;
96 if (i >= fs->super->s_blocks_count)
97 i = fs->super->s_first_data_block;
98 } while (i != goal);
99 return EXT2_ET_BLOCK_ALLOC_FAIL;
100}
101
102/*
103 * This function zeros out the allocated block, and updates all of the
104 * appropriate filesystem records.
105 */
106errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
107 char *block_buf, blk_t *ret)
108{
109 errcode_t retval;
110 blk_t block;
111 char *buf = 0;
112
113 if (!block_buf) {
114 retval = ext2fs_get_mem(fs->blocksize, &buf);
115 if (retval)
116 return retval;
117 block_buf = buf;
118 }
119 memset(block_buf, 0, fs->blocksize);
120
121 if (!fs->block_map) {
122 retval = ext2fs_read_block_bitmap(fs);
123 if (retval)
124 goto fail;
125 }
126
127 retval = ext2fs_new_block(fs, goal, 0, &block);
128 if (retval)
129 goto fail;
130
131 retval = io_channel_write_blk(fs->io, block, 1, block_buf);
132 if (retval)
133 goto fail;
134
135 ext2fs_block_alloc_stats(fs, block, +1);
136 *ret = block;
137 return 0;
138
139fail:
140 if (buf)
141 ext2fs_free_mem(&buf);
142 return retval;
143}
144
145errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
146 int num, ext2fs_block_bitmap map, blk_t *ret)
147{
148 blk_t b = start;
149
150 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
151
152 if (!map)
153 map = fs->block_map;
154 if (!map)
155 return EXT2_ET_NO_BLOCK_BITMAP;
156 if (!b)
157 b = fs->super->s_first_data_block;
158 if (!finish)
159 finish = start;
160 if (!num)
161 num = 1;
162 do {
163 if (b+num-1 > fs->super->s_blocks_count)
164 b = fs->super->s_first_data_block;
165 if (ext2fs_fast_test_block_bitmap_range(map, b, num)) {
166 *ret = b;
167 return 0;
168 }
169 b++;
170 } while (b != finish);
171 return EXT2_ET_BLOCK_ALLOC_FAIL;
172}
173
diff --git a/e2fsprogs/ext2fs/alloc_sb.c b/e2fsprogs/ext2fs/alloc_sb.c
new file mode 100644
index 000000000..ef40b938f
--- /dev/null
+++ b/e2fsprogs/ext2fs/alloc_sb.c
@@ -0,0 +1,57 @@
1/*
2 * alloc_sb.c --- Allocate the superblock and block group descriptors for a
3 * newly initialized filesystem. Used by mke2fs when initializing a filesystem
4 *
5 * Copyright (C) 1994, 1995, 1996, 2003 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
30int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
31 dgrp_t group,
32 ext2fs_block_bitmap bmap)
33{
34 blk_t super_blk, old_desc_blk, new_desc_blk;
35 int j, old_desc_blocks, num_blocks;
36
37 num_blocks = ext2fs_super_and_bgd_loc(fs, group, &super_blk,
38 &old_desc_blk, &new_desc_blk, 0);
39
40 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
41 old_desc_blocks = fs->super->s_first_meta_bg;
42 else
43 old_desc_blocks =
44 fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
45
46 if (super_blk || (group == 0))
47 ext2fs_mark_block_bitmap(bmap, super_blk);
48
49 if (old_desc_blk) {
50 for (j=0; j < old_desc_blocks; j++)
51 ext2fs_mark_block_bitmap(bmap, old_desc_blk + j);
52 }
53 if (new_desc_blk)
54 ext2fs_mark_block_bitmap(bmap, new_desc_blk);
55
56 return num_blocks;
57}
diff --git a/e2fsprogs/ext2fs/alloc_stats.c b/e2fsprogs/ext2fs/alloc_stats.c
new file mode 100644
index 000000000..4088f7b87
--- /dev/null
+++ b/e2fsprogs/ext2fs/alloc_stats.c
@@ -0,0 +1,52 @@
1/*
2 * alloc_stats.c --- Update allocation statistics for ext2fs
3 *
4 * Copyright (C) 2001 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 */
12
13#include <stdio.h>
14
15#include "ext2_fs.h"
16#include "ext2fs.h"
17
18void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
19 int inuse, int isdir)
20{
21 int group = ext2fs_group_of_ino(fs, ino);
22
23 if (inuse > 0)
24 ext2fs_mark_inode_bitmap(fs->inode_map, ino);
25 else
26 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
27 fs->group_desc[group].bg_free_inodes_count -= inuse;
28 if (isdir)
29 fs->group_desc[group].bg_used_dirs_count += inuse;
30 fs->super->s_free_inodes_count -= inuse;
31 ext2fs_mark_super_dirty(fs);
32 ext2fs_mark_ib_dirty(fs);
33}
34
35void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse)
36{
37 ext2fs_inode_alloc_stats2(fs, ino, inuse, 0);
38}
39
40void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
41{
42 int group = ext2fs_group_of_blk(fs, blk);
43
44 if (inuse > 0)
45 ext2fs_mark_block_bitmap(fs->block_map, blk);
46 else
47 ext2fs_unmark_block_bitmap(fs->block_map, blk);
48 fs->group_desc[group].bg_free_blocks_count -= inuse;
49 fs->super->s_free_blocks_count -= inuse;
50 ext2fs_mark_super_dirty(fs);
51 ext2fs_mark_bb_dirty(fs);
52}
diff --git a/e2fsprogs/ext2fs/alloc_tables.c b/e2fsprogs/ext2fs/alloc_tables.c
new file mode 100644
index 000000000..0326321be
--- /dev/null
+++ b/e2fsprogs/ext2fs/alloc_tables.c
@@ -0,0 +1,117 @@
1/*
2 * alloc_tables.c --- Allocate tables for a newly initialized
3 * filesystem. Used by mke2fs when initializing a filesystem
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
30errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
31 ext2fs_block_bitmap bmap)
32{
33 errcode_t retval;
34 blk_t group_blk, start_blk, last_blk, new_blk, blk;
35 int j;
36
37 group_blk = fs->super->s_first_data_block +
38 (group * fs->super->s_blocks_per_group);
39
40 last_blk = group_blk + fs->super->s_blocks_per_group;
41 if (last_blk >= fs->super->s_blocks_count)
42 last_blk = fs->super->s_blocks_count - 1;
43
44 if (!bmap)
45 bmap = fs->block_map;
46
47 /*
48 * Allocate the block and inode bitmaps, if necessary
49 */
50 if (fs->stride) {
51 start_blk = group_blk + fs->inode_blocks_per_group;
52 start_blk += ((fs->stride * group) %
53 (last_blk - start_blk));
54 if (start_blk > last_blk)
55 start_blk = group_blk;
56 } else
57 start_blk = group_blk;
58
59 if (!fs->group_desc[group].bg_block_bitmap) {
60 retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
61 1, bmap, &new_blk);
62 if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
63 retval = ext2fs_get_free_blocks(fs, group_blk,
64 last_blk, 1, bmap, &new_blk);
65 if (retval)
66 return retval;
67 ext2fs_mark_block_bitmap(bmap, new_blk);
68 fs->group_desc[group].bg_block_bitmap = new_blk;
69 }
70
71 if (!fs->group_desc[group].bg_inode_bitmap) {
72 retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
73 1, bmap, &new_blk);
74 if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
75 retval = ext2fs_get_free_blocks(fs, group_blk,
76 last_blk, 1, bmap, &new_blk);
77 if (retval)
78 return retval;
79 ext2fs_mark_block_bitmap(bmap, new_blk);
80 fs->group_desc[group].bg_inode_bitmap = new_blk;
81 }
82
83 /*
84 * Allocate the inode table
85 */
86 if (!fs->group_desc[group].bg_inode_table) {
87 retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
88 fs->inode_blocks_per_group,
89 bmap, &new_blk);
90 if (retval)
91 return retval;
92 for (j=0, blk = new_blk;
93 j < fs->inode_blocks_per_group;
94 j++, blk++)
95 ext2fs_mark_block_bitmap(bmap, blk);
96 fs->group_desc[group].bg_inode_table = new_blk;
97 }
98
99
100 return 0;
101}
102
103
104
105errcode_t ext2fs_allocate_tables(ext2_filsys fs)
106{
107 errcode_t retval;
108 dgrp_t i;
109
110 for (i = 0; i < fs->group_desc_count; i++) {
111 retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
112 if (retval)
113 return retval;
114 }
115 return 0;
116}
117
diff --git a/e2fsprogs/ext2fs/badblocks.c b/e2fsprogs/ext2fs/badblocks.c
new file mode 100644
index 000000000..4b76ef032
--- /dev/null
+++ b/e2fsprogs/ext2fs/badblocks.c
@@ -0,0 +1,327 @@
1/*
2 * badblocks.c --- routines to manipulate the bad block structure
3 *
4 * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fsP.h"
28
29/*
30 * Helper function for making a badblocks list
31 */
32static errcode_t make_u32_list(int size, int num, __u32 *list,
33 ext2_u32_list *ret)
34{
35 ext2_u32_list bb;
36 errcode_t retval;
37
38 retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb);
39 if (retval)
40 return retval;
41 memset(bb, 0, sizeof(struct ext2_struct_u32_list));
42 bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
43 bb->size = size ? size : 10;
44 bb->num = num;
45 retval = ext2fs_get_mem(bb->size * sizeof(blk_t), &bb->list);
46 if (!bb->list) {
47 ext2fs_free_mem(&bb);
48 return retval;
49 }
50 if (list)
51 memcpy(bb->list, list, bb->size * sizeof(blk_t));
52 else
53 memset(bb->list, 0, bb->size * sizeof(blk_t));
54 *ret = bb;
55 return 0;
56}
57
58
59/*
60 * This procedure creates an empty u32 list.
61 */
62errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
63{
64 return make_u32_list(size, 0, 0, ret);
65}
66
67/*
68 * This procedure creates an empty badblocks list.
69 */
70errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
71{
72 return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
73}
74
75
76/*
77 * This procedure copies a badblocks list
78 */
79errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
80{
81 errcode_t retval;
82
83 retval = make_u32_list(src->size, src->num, src->list, dest);
84 if (retval)
85 return retval;
86 (*dest)->badblocks_flags = src->badblocks_flags;
87 return 0;
88}
89
90errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
91 ext2_badblocks_list *dest)
92{
93 return ext2fs_u32_copy((ext2_u32_list) src,
94 (ext2_u32_list *) dest);
95}
96
97/*
98 * This procedure frees a badblocks list.
99 *
100 * (note: moved to closefs.c)
101 */
102
103
104/*
105 * This procedure adds a block to a badblocks list.
106 */
107errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
108{
109 errcode_t retval;
110 int i, j;
111 unsigned long old_size;
112
113 EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
114
115 if (bb->num >= bb->size) {
116 old_size = bb->size * sizeof(__u32);
117 bb->size += 100;
118 retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
119 &bb->list);
120 if (retval) {
121 bb->size -= 100;
122 return retval;
123 }
124 }
125
126 /*
127 * Add special case code for appending to the end of the list
128 */
129 i = bb->num-1;
130 if ((bb->num != 0) && (bb->list[i] == blk))
131 return 0;
132 if ((bb->num == 0) || (bb->list[i] < blk)) {
133 bb->list[bb->num++] = blk;
134 return 0;
135 }
136
137 j = bb->num;
138 for (i=0; i < bb->num; i++) {
139 if (bb->list[i] == blk)
140 return 0;
141 if (bb->list[i] > blk) {
142 j = i;
143 break;
144 }
145 }
146 for (i=bb->num; i > j; i--)
147 bb->list[i] = bb->list[i-1];
148 bb->list[j] = blk;
149 bb->num++;
150 return 0;
151}
152
153errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
154{
155 return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
156}
157
158/*
159 * This procedure finds a particular block is on a badblocks
160 * list.
161 */
162int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
163{
164 int low, high, mid;
165
166 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
167 return -1;
168
169 if (bb->num == 0)
170 return -1;
171
172 low = 0;
173 high = bb->num-1;
174 if (blk == bb->list[low])
175 return low;
176 if (blk == bb->list[high])
177 return high;
178
179 while (low < high) {
180 mid = (low+high)/2;
181 if (mid == low || mid == high)
182 break;
183 if (blk == bb->list[mid])
184 return mid;
185 if (blk < bb->list[mid])
186 high = mid;
187 else
188 low = mid;
189 }
190 return -1;
191}
192
193/*
194 * This procedure tests to see if a particular block is on a badblocks
195 * list.
196 */
197int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
198{
199 if (ext2fs_u32_list_find(bb, blk) < 0)
200 return 0;
201 else
202 return 1;
203}
204
205int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
206{
207 return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
208}
209
210
211/*
212 * Remove a block from the badblock list
213 */
214int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
215{
216 int remloc, i;
217
218 if (bb->num == 0)
219 return -1;
220
221 remloc = ext2fs_u32_list_find(bb, blk);
222 if (remloc < 0)
223 return -1;
224
225 for (i = remloc ; i < bb->num-1; i++)
226 bb->list[i] = bb->list[i+1];
227 bb->num--;
228 return 0;
229}
230
231void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
232{
233 ext2fs_u32_list_del(bb, blk);
234}
235
236errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
237 ext2_u32_iterate *ret)
238{
239 ext2_u32_iterate iter;
240 errcode_t retval;
241
242 EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
243
244 retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter);
245 if (retval)
246 return retval;
247
248 iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
249 iter->bb = bb;
250 iter->ptr = 0;
251 *ret = iter;
252 return 0;
253}
254
255errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
256 ext2_badblocks_iterate *ret)
257{
258 return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
259 (ext2_u32_iterate *) ret);
260}
261
262
263int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
264{
265 ext2_u32_list bb;
266
267 if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
268 return 0;
269
270 bb = iter->bb;
271
272 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
273 return 0;
274
275 if (iter->ptr < bb->num) {
276 *blk = bb->list[iter->ptr++];
277 return 1;
278 }
279 *blk = 0;
280 return 0;
281}
282
283int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
284{
285 return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
286 (__u32 *) blk);
287}
288
289
290void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
291{
292 if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
293 return;
294
295 iter->bb = 0;
296 ext2fs_free_mem(&iter);
297}
298
299void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
300{
301 ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
302}
303
304
305int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
306{
307 EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
308 EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
309
310 if (bb1->num != bb2->num)
311 return 0;
312
313 if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
314 return 0;
315 return 1;
316}
317
318int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
319{
320 return ext2fs_u32_list_equal((ext2_u32_list) bb1,
321 (ext2_u32_list) bb2);
322}
323
324int ext2fs_u32_list_count(ext2_u32_list bb)
325{
326 return bb->num;
327}
diff --git a/e2fsprogs/ext2fs/bb_compat.c b/e2fsprogs/ext2fs/bb_compat.c
new file mode 100644
index 000000000..40f734368
--- /dev/null
+++ b/e2fsprogs/ext2fs/bb_compat.c
@@ -0,0 +1,63 @@
1/*
2 * bb_compat.c --- compatibility badblocks routines
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fsP.h"
28
29errcode_t badblocks_list_create(badblocks_list *ret, int size)
30{
31 return ext2fs_badblocks_list_create(ret, size);
32}
33
34void badblocks_list_free(badblocks_list bb)
35{
36 ext2fs_badblocks_list_free(bb);
37}
38
39errcode_t badblocks_list_add(badblocks_list bb, blk_t blk)
40{
41 return ext2fs_badblocks_list_add(bb, blk);
42}
43
44int badblocks_list_test(badblocks_list bb, blk_t blk)
45{
46 return ext2fs_badblocks_list_test(bb, blk);
47}
48
49errcode_t badblocks_list_iterate_begin(badblocks_list bb,
50 badblocks_iterate *ret)
51{
52 return ext2fs_badblocks_list_iterate_begin(bb, ret);
53}
54
55int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk)
56{
57 return ext2fs_badblocks_list_iterate(iter, blk);
58}
59
60void badblocks_list_iterate_end(badblocks_iterate iter)
61{
62 ext2fs_badblocks_list_iterate_end(iter);
63}
diff --git a/e2fsprogs/ext2fs/bb_inode.c b/e2fsprogs/ext2fs/bb_inode.c
new file mode 100644
index 000000000..dd8e7c319
--- /dev/null
+++ b/e2fsprogs/ext2fs/bb_inode.c
@@ -0,0 +1,267 @@
1/*
2 * bb_inode.c --- routines to update the bad block inode.
3 *
4 * WARNING: This routine modifies a lot of state in the filesystem; if
5 * this routine returns an error, the bad block inode may be in an
6 * inconsistent state.
7 *
8 * Copyright (C) 1994, 1995 Theodore Ts'o.
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#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#include "ext2fs.h"
32
33struct set_badblock_record {
34 ext2_badblocks_iterate bb_iter;
35 int bad_block_count;
36 blk_t *ind_blocks;
37 int max_ind_blocks;
38 int ind_blocks_size;
39 int ind_blocks_ptr;
40 char *block_buf;
41 errcode_t err;
42};
43
44static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
45 e2_blkcnt_t blockcnt,
46 blk_t ref_block, int ref_offset,
47 void *priv_data);
48static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
49 e2_blkcnt_t blockcnt,
50 blk_t ref_block, int ref_offset,
51 void *priv_data);
52
53/*
54 * Given a bad blocks bitmap, update the bad blocks inode to reflect
55 * the map.
56 */
57errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
58{
59 errcode_t retval;
60 struct set_badblock_record rec;
61 struct ext2_inode inode;
62
63 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
64
65 if (!fs->block_map)
66 return EXT2_ET_NO_BLOCK_BITMAP;
67
68 rec.bad_block_count = 0;
69 rec.ind_blocks_size = rec.ind_blocks_ptr = 0;
70 rec.max_ind_blocks = 10;
71 retval = ext2fs_get_mem(rec.max_ind_blocks * sizeof(blk_t),
72 &rec.ind_blocks);
73 if (retval)
74 return retval;
75 memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
76 retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf);
77 if (retval)
78 goto cleanup;
79 memset(rec.block_buf, 0, fs->blocksize);
80 rec.err = 0;
81
82 /*
83 * First clear the old bad blocks (while saving the indirect blocks)
84 */
85 retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
86 BLOCK_FLAG_DEPTH_TRAVERSE, 0,
87 clear_bad_block_proc, &rec);
88 if (retval)
89 goto cleanup;
90 if (rec.err) {
91 retval = rec.err;
92 goto cleanup;
93 }
94
95 /*
96 * Now set the bad blocks!
97 *
98 * First, mark the bad blocks as used. This prevents a bad
99 * block from being used as an indirecto block for the bad
100 * block inode (!).
101 */
102 if (bb_list) {
103 retval = ext2fs_badblocks_list_iterate_begin(bb_list,
104 &rec.bb_iter);
105 if (retval)
106 goto cleanup;
107 retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
108 BLOCK_FLAG_APPEND, 0,
109 set_bad_block_proc, &rec);
110 ext2fs_badblocks_list_iterate_end(rec.bb_iter);
111 if (retval)
112 goto cleanup;
113 if (rec.err) {
114 retval = rec.err;
115 goto cleanup;
116 }
117 }
118
119 /*
120 * Update the bad block inode's mod time and block count
121 * field.
122 */
123 retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
124 if (retval)
125 goto cleanup;
126
127 inode.i_atime = inode.i_mtime = time(0);
128 if (!inode.i_ctime)
129 inode.i_ctime = time(0);
130 inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512);
131 inode.i_size = rec.bad_block_count * fs->blocksize;
132
133 retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
134 if (retval)
135 goto cleanup;
136
137cleanup:
138 ext2fs_free_mem(&rec.ind_blocks);
139 ext2fs_free_mem(&rec.block_buf);
140 return retval;
141}
142
143/*
144 * Helper function for update_bb_inode()
145 *
146 * Clear the bad blocks in the bad block inode, while saving the
147 * indirect blocks.
148 */
149#ifdef __TURBOC__
150 #pragma argsused
151#endif
152static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
153 e2_blkcnt_t blockcnt,
154 blk_t ref_block EXT2FS_ATTR((unused)),
155 int ref_offset EXT2FS_ATTR((unused)),
156 void *priv_data)
157{
158 struct set_badblock_record *rec = (struct set_badblock_record *)
159 priv_data;
160 errcode_t retval;
161 unsigned long old_size;
162
163 if (!*block_nr)
164 return 0;
165
166 /*
167 * If the block number is outrageous, clear it and ignore it.
168 */
169 if (*block_nr >= fs->super->s_blocks_count ||
170 *block_nr < fs->super->s_first_data_block) {
171 *block_nr = 0;
172 return BLOCK_CHANGED;
173 }
174
175 if (blockcnt < 0) {
176 if (rec->ind_blocks_size >= rec->max_ind_blocks) {
177 old_size = rec->max_ind_blocks * sizeof(blk_t);
178 rec->max_ind_blocks += 10;
179 retval = ext2fs_resize_mem(old_size,
180 rec->max_ind_blocks * sizeof(blk_t),
181 &rec->ind_blocks);
182 if (retval) {
183 rec->max_ind_blocks -= 10;
184 rec->err = retval;
185 return BLOCK_ABORT;
186 }
187 }
188 rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
189 }
190
191 /*
192 * Mark the block as unused, and update accounting information
193 */
194 ext2fs_block_alloc_stats(fs, *block_nr, -1);
195
196 *block_nr = 0;
197 return BLOCK_CHANGED;
198}
199
200
201/*
202 * Helper function for update_bb_inode()
203 *
204 * Set the block list in the bad block inode, using the supplied bitmap.
205 */
206#ifdef __TURBOC__
207 #pragma argsused
208#endif
209static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
210 e2_blkcnt_t blockcnt,
211 blk_t ref_block EXT2FS_ATTR((unused)),
212 int ref_offset EXT2FS_ATTR((unused)),
213 void *priv_data)
214{
215 struct set_badblock_record *rec = (struct set_badblock_record *)
216 priv_data;
217 errcode_t retval;
218 blk_t blk;
219
220 if (blockcnt >= 0) {
221 /*
222 * Get the next bad block.
223 */
224 if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk))
225 return BLOCK_ABORT;
226 rec->bad_block_count++;
227 } else {
228 /*
229 * An indirect block; fetch a block from the
230 * previously used indirect block list. The block
231 * most be not marked as used; if so, get another one.
232 * If we run out of reserved indirect blocks, allocate
233 * a new one.
234 */
235 retry:
236 if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
237 blk = rec->ind_blocks[rec->ind_blocks_ptr++];
238 if (ext2fs_test_block_bitmap(fs->block_map, blk))
239 goto retry;
240 } else {
241 retval = ext2fs_new_block(fs, 0, 0, &blk);
242 if (retval) {
243 rec->err = retval;
244 return BLOCK_ABORT;
245 }
246 }
247 retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf);
248 if (retval) {
249 rec->err = retval;
250 return BLOCK_ABORT;
251 }
252 }
253
254 /*
255 * Update block counts
256 */
257 ext2fs_block_alloc_stats(fs, blk, +1);
258
259 *block_nr = blk;
260 return BLOCK_CHANGED;
261}
262
263
264
265
266
267
diff --git a/e2fsprogs/ext2fs/bitmaps.c b/e2fsprogs/ext2fs/bitmaps.c
new file mode 100644
index 000000000..7edd28d7b
--- /dev/null
+++ b/e2fsprogs/ext2fs/bitmaps.c
@@ -0,0 +1,212 @@
1/*
2 * bitmaps.c --- routines to read, write, and manipulate the inode and
3 * block bitmaps.
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
30static errcode_t make_bitmap(__u32 start, __u32 end, __u32 real_end,
31 const char *descr, char *init_map,
32 ext2fs_generic_bitmap *ret)
33{
34 ext2fs_generic_bitmap bitmap;
35 errcode_t retval;
36 size_t size;
37
38 retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
39 &bitmap);
40 if (retval)
41 return retval;
42
43 bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
44 bitmap->fs = NULL;
45 bitmap->start = start;
46 bitmap->end = end;
47 bitmap->real_end = real_end;
48 bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
49 if (descr) {
50 retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
51 if (retval) {
52 ext2fs_free_mem(&bitmap);
53 return retval;
54 }
55 strcpy(bitmap->description, descr);
56 } else
57 bitmap->description = 0;
58
59 size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
60 retval = ext2fs_get_mem(size, &bitmap->bitmap);
61 if (retval) {
62 ext2fs_free_mem(&bitmap->description);
63 ext2fs_free_mem(&bitmap);
64 return retval;
65 }
66
67 if (init_map)
68 memcpy(bitmap->bitmap, init_map, size);
69 else
70 memset(bitmap->bitmap, 0, size);
71 *ret = bitmap;
72 return 0;
73}
74
75errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
76 __u32 end,
77 __u32 real_end,
78 const char *descr,
79 ext2fs_generic_bitmap *ret)
80{
81 return make_bitmap(start, end, real_end, descr, 0, ret);
82}
83
84errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
85 ext2fs_generic_bitmap *dest)
86{
87 errcode_t retval;
88 ext2fs_generic_bitmap new_map;
89
90 retval = make_bitmap(src->start, src->end, src->real_end,
91 src->description, src->bitmap, &new_map);
92 if (retval)
93 return retval;
94 new_map->magic = src->magic;
95 new_map->fs = src->fs;
96 new_map->base_error_code = src->base_error_code;
97 *dest = new_map;
98 return 0;
99}
100
101void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
102{
103 __u32 i, j;
104
105 for (i=map->end+1, j = i - map->start; i <= map->real_end; i++, j++)
106 ext2fs_set_bit(j, map->bitmap);
107
108 return;
109}
110
111errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
112 const char *descr,
113 ext2fs_inode_bitmap *ret)
114{
115 ext2fs_inode_bitmap bitmap;
116 errcode_t retval;
117 __u32 start, end, real_end;
118
119 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
120
121 fs->write_bitmaps = ext2fs_write_bitmaps;
122
123 start = 1;
124 end = fs->super->s_inodes_count;
125 real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count);
126
127 retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
128 descr, &bitmap);
129 if (retval)
130 return retval;
131
132 bitmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
133 bitmap->fs = fs;
134 bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
135
136 *ret = bitmap;
137 return 0;
138}
139
140errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
141 const char *descr,
142 ext2fs_block_bitmap *ret)
143{
144 ext2fs_block_bitmap bitmap;
145 errcode_t retval;
146 __u32 start, end, real_end;
147
148 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
149
150 fs->write_bitmaps = ext2fs_write_bitmaps;
151
152 start = fs->super->s_first_data_block;
153 end = fs->super->s_blocks_count-1;
154 real_end = (EXT2_BLOCKS_PER_GROUP(fs->super)
155 * fs->group_desc_count)-1 + start;
156
157 retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
158 descr, &bitmap);
159 if (retval)
160 return retval;
161
162 bitmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
163 bitmap->fs = fs;
164 bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
165
166 *ret = bitmap;
167 return 0;
168}
169
170errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
171 ext2_ino_t end, ext2_ino_t *oend)
172{
173 EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
174
175 if (end > bitmap->real_end)
176 return EXT2_ET_FUDGE_INODE_BITMAP_END;
177 if (oend)
178 *oend = bitmap->end;
179 bitmap->end = end;
180 return 0;
181}
182
183errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
184 blk_t end, blk_t *oend)
185{
186 EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
187
188 if (end > bitmap->real_end)
189 return EXT2_ET_FUDGE_BLOCK_BITMAP_END;
190 if (oend)
191 *oend = bitmap->end;
192 bitmap->end = end;
193 return 0;
194}
195
196void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap)
197{
198 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
199 return;
200
201 memset(bitmap->bitmap, 0,
202 (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
203}
204
205void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap)
206{
207 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
208 return;
209
210 memset(bitmap->bitmap, 0,
211 (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
212}
diff --git a/e2fsprogs/ext2fs/bitops.c b/e2fsprogs/ext2fs/bitops.c
new file mode 100644
index 000000000..207c44d92
--- /dev/null
+++ b/e2fsprogs/ext2fs/bitops.c
@@ -0,0 +1,91 @@
1/*
2 * bitops.c --- Bitmap frobbing code. See bitops.h for the inlined
3 * routines.
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_SYS_TYPES_H
15#include <sys/types.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21#ifndef _EXT2_HAVE_ASM_BITOPS_
22
23/*
24 * For the benefit of those who are trying to port Linux to another
25 * architecture, here are some C-language equivalents. You should
26 * recode these in the native assmebly language, if at all possible.
27 *
28 * C language equivalents written by Theodore Ts'o, 9/26/92.
29 * Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian
30 * systems, as well as non-32 bit systems.
31 */
32
33int ext2fs_set_bit(int nr,void * addr)
34{
35 int mask, retval;
36 unsigned char *ADDR = (unsigned char *) addr;
37
38 ADDR += nr >> 3;
39 mask = 1 << (nr & 0x07);
40 retval = mask & *ADDR;
41 *ADDR |= mask;
42 return retval;
43}
44
45int ext2fs_clear_bit(int nr, void * addr)
46{
47 int mask, retval;
48 unsigned char *ADDR = (unsigned char *) addr;
49
50 ADDR += nr >> 3;
51 mask = 1 << (nr & 0x07);
52 retval = mask & *ADDR;
53 *ADDR &= ~mask;
54 return retval;
55}
56
57int ext2fs_test_bit(int nr, const void * addr)
58{
59 int mask;
60 const unsigned char *ADDR = (const unsigned char *) addr;
61
62 ADDR += nr >> 3;
63 mask = 1 << (nr & 0x07);
64 return (mask & *ADDR);
65}
66
67#endif /* !_EXT2_HAVE_ASM_BITOPS_ */
68
69void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
70 const char *description)
71{
72#ifndef OMIT_COM_ERR
73 if (description)
74 com_err(0, errcode, "#%lu for %s", arg, description);
75 else
76 com_err(0, errcode, "#%lu", arg);
77#endif
78}
79
80void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
81 int code, unsigned long arg)
82{
83#ifndef OMIT_COM_ERR
84 if (bitmap->description)
85 com_err(0, bitmap->base_error_code+code,
86 "#%lu for %s", arg, bitmap->description);
87 else
88 com_err(0, bitmap->base_error_code + code, "#%lu", arg);
89#endif
90}
91
diff --git a/e2fsprogs/ext2fs/bitops.h b/e2fsprogs/ext2fs/bitops.h
new file mode 100644
index 000000000..b2238099c
--- /dev/null
+++ b/e2fsprogs/ext2fs/bitops.h
@@ -0,0 +1,617 @@
1/*
2 * bitops.h --- Bitmap frobbing code. The byte swapping routines are
3 * also included here.
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 * i386 bitops operations taken from <asm/bitops.h>, Copyright 1992,
13 * Linus Torvalds.
14 */
15
16
17extern int ext2fs_set_bit(int nr,void * addr);
18extern int ext2fs_clear_bit(int nr, void * addr);
19extern int ext2fs_test_bit(int nr, const void * addr);
20extern __u16 ext2fs_swab16(__u16 val);
21extern __u32 ext2fs_swab32(__u32 val);
22
23#ifdef WORDS_BIGENDIAN
24#define ext2fs_cpu_to_le32(x) ext2fs_swab32((x))
25#define ext2fs_le32_to_cpu(x) ext2fs_swab32((x))
26#define ext2fs_cpu_to_le16(x) ext2fs_swab16((x))
27#define ext2fs_le16_to_cpu(x) ext2fs_swab16((x))
28#define ext2fs_cpu_to_be32(x) ((__u32)(x))
29#define ext2fs_be32_to_cpu(x) ((__u32)(x))
30#define ext2fs_cpu_to_be16(x) ((__u16)(x))
31#define ext2fs_be16_to_cpu(x) ((__u16)(x))
32#else
33#define ext2fs_cpu_to_le32(x) ((__u32)(x))
34#define ext2fs_le32_to_cpu(x) ((__u32)(x))
35#define ext2fs_cpu_to_le16(x) ((__u16)(x))
36#define ext2fs_le16_to_cpu(x) ((__u16)(x))
37#define ext2fs_cpu_to_be32(x) ext2fs_swab32((x))
38#define ext2fs_be32_to_cpu(x) ext2fs_swab32((x))
39#define ext2fs_cpu_to_be16(x) ext2fs_swab16((x))
40#define ext2fs_be16_to_cpu(x) ext2fs_swab16((x))
41#endif
42
43/*
44 * EXT2FS bitmap manipulation routines.
45 */
46
47/* Support for sending warning messages from the inline subroutines */
48extern const char *ext2fs_block_string;
49extern const char *ext2fs_inode_string;
50extern const char *ext2fs_mark_string;
51extern const char *ext2fs_unmark_string;
52extern const char *ext2fs_test_string;
53extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
54 const char *description);
55extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
56 int code, unsigned long arg);
57
58extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
59extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
60 blk_t block);
61extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
62
63extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
64extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
65 ext2_ino_t inode);
66extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
67
68extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
69 blk_t block);
70extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
71 blk_t block);
72extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
73 blk_t block);
74
75extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
76 ext2_ino_t inode);
77extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
78 ext2_ino_t inode);
79extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
80 ext2_ino_t inode);
81extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap);
82extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap);
83extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap);
84extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap);
85
86extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
87 blk_t block, int num);
88extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
89 blk_t block, int num);
90extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
91 blk_t block, int num);
92extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
93 blk_t block, int num);
94extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
95 blk_t block, int num);
96extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
97 blk_t block, int num);
98extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map);
99
100/* These two routines moved to gen_bitmap.c */
101extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
102 __u32 bitno);
103extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
104 blk_t bitno);
105/*
106 * The inline routines themselves...
107 *
108 * If NO_INLINE_FUNCS is defined, then we won't try to do inline
109 * functions at all; they will be included as normal functions in
110 * inline.c
111 */
112#ifdef NO_INLINE_FUNCS
113#if (defined(__GNUC__) && (defined(__i386__) || defined(__i486__) || \
114 defined(__i586__) || defined(__mc68000__) || \
115 defined(__sparc__)))
116 /* This prevents bitops.c from trying to include the C */
117 /* function version of these functions */
118#define _EXT2_HAVE_ASM_BITOPS_
119#endif
120#endif /* NO_INLINE_FUNCS */
121
122#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
123#ifdef INCLUDE_INLINE_FUNCS
124#define _INLINE_ extern
125#else
126#ifdef __GNUC__
127#define _INLINE_ extern __inline__
128#else /* For Watcom C */
129#define _INLINE_ extern inline
130#endif
131#endif
132
133#if ((defined __GNUC__) && !defined(_EXT2_USE_C_VERSIONS_) && \
134 (defined(__i386__) || defined(__i486__) || defined(__i586__)))
135
136#define _EXT2_HAVE_ASM_BITOPS_
137#define _EXT2_HAVE_ASM_SWAB_
138#define _EXT2_HAVE_ASM_FINDBIT_
139
140/*
141 * These are done by inline assembly for speed reasons.....
142 *
143 * All bitoperations return 0 if the bit was cleared before the
144 * operation and != 0 if it was not. Bit 0 is the LSB of addr; bit 32
145 * is the LSB of (addr+1).
146 */
147
148/*
149 * Some hacks to defeat gcc over-optimizations..
150 */
151struct __dummy_h { unsigned long a[100]; };
152#define EXT2FS_ADDR (*(struct __dummy_h *) addr)
153#define EXT2FS_CONST_ADDR (*(const struct __dummy_h *) addr)
154
155_INLINE_ int ext2fs_set_bit(int nr, void * addr)
156{
157 int oldbit;
158
159 __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
160 :"=r" (oldbit),"=m" (EXT2FS_ADDR)
161 :"r" (nr));
162 return oldbit;
163}
164
165_INLINE_ int ext2fs_clear_bit(int nr, void * addr)
166{
167 int oldbit;
168
169 __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
170 :"=r" (oldbit),"=m" (EXT2FS_ADDR)
171 :"r" (nr));
172 return oldbit;
173}
174
175_INLINE_ int ext2fs_test_bit(int nr, const void * addr)
176{
177 int oldbit;
178
179 __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
180 :"=r" (oldbit)
181 :"m" (EXT2FS_CONST_ADDR),"r" (nr));
182 return oldbit;
183}
184
185#if 0
186_INLINE_ int ext2fs_find_first_bit_set(void * addr, unsigned size)
187{
188 int d0, d1, d2;
189 int res;
190
191 if (!size)
192 return 0;
193 /* This looks at memory. Mark it volatile to tell gcc not to move it around */
194 __asm__ __volatile__(
195 "cld\n\t"
196 "xorl %%eax,%%eax\n\t"
197 "xorl %%edx,%%edx\n\t"
198 "repe; scasl\n\t"
199 "je 1f\n\t"
200 "movl -4(%%edi),%%eax\n\t"
201 "subl $4,%%edi\n\t"
202 "bsfl %%eax,%%edx\n"
203 "1:\tsubl %%esi,%%edi\n\t"
204 "shll $3,%%edi\n\t"
205 "addl %%edi,%%edx"
206 :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
207 :"1" ((size + 31) >> 5), "2" (addr), "S" (addr));
208 return res;
209}
210
211_INLINE_ int ext2fs_find_next_bit_set (void * addr, int size, int offset)
212{
213 unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
214 int set = 0, bit = offset & 31, res;
215
216 if (bit) {
217 /*
218 * Look for zero in first byte
219 */
220 __asm__("bsfl %1,%0\n\t"
221 "jne 1f\n\t"
222 "movl $32, %0\n"
223 "1:"
224 : "=r" (set)
225 : "r" (*p >> bit));
226 if (set < (32 - bit))
227 return set + offset;
228 set = 32 - bit;
229 p++;
230 }
231 /*
232 * No bit found yet, search remaining full bytes for a bit
233 */
234 res = ext2fs_find_first_bit_set(p, size - 32 * (p - (unsigned long *) addr));
235 return (offset + set + res);
236}
237#endif
238
239#ifdef EXT2FS_ENABLE_SWAPFS
240_INLINE_ __u32 ext2fs_swab32(__u32 val)
241{
242#ifdef EXT2FS_REQUIRE_486
243 __asm__("bswap %0" : "=r" (val) : "0" (val));
244#else
245 __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */
246 "rorl $16,%0\n\t" /* swap words */
247 "xchgb %b0,%h0" /* swap higher bytes */
248 :"=q" (val)
249 : "0" (val));
250#endif
251 return val;
252}
253
254_INLINE_ __u16 ext2fs_swab16(__u16 val)
255{
256 __asm__("xchgb %b0,%h0" /* swap bytes */ \
257 : "=q" (val) \
258 : "0" (val)); \
259 return val;
260}
261#endif
262
263#undef EXT2FS_ADDR
264
265#endif /* i386 */
266
267#ifdef __mc68000__
268
269#define _EXT2_HAVE_ASM_BITOPS_
270
271_INLINE_ int ext2fs_set_bit(int nr,void * addr)
272{
273 char retval;
274
275 __asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
276 : "=d" (retval) : "d" (nr^7), "a" (addr));
277
278 return retval;
279}
280
281_INLINE_ int ext2fs_clear_bit(int nr, void * addr)
282{
283 char retval;
284
285 __asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0"
286 : "=d" (retval) : "d" (nr^7), "a" (addr));
287
288 return retval;
289}
290
291_INLINE_ int ext2fs_test_bit(int nr, const void * addr)
292{
293 char retval;
294
295 __asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
296 : "=d" (retval) : "d" (nr^7), "a" (addr));
297
298 return retval;
299}
300
301#endif /* __mc68000__ */
302
303
304#if !defined(_EXT2_HAVE_ASM_SWAB_) && defined(EXT2FS_ENABLE_SWAPFS)
305
306_INLINE_ __u16 ext2fs_swab16(__u16 val)
307{
308 return (val >> 8) | (val << 8);
309}
310
311_INLINE_ __u32 ext2fs_swab32(__u32 val)
312{
313 return ((val>>24) | ((val>>8)&0xFF00) |
314 ((val<<8)&0xFF0000) | (val<<24));
315}
316
317#endif /* !_EXT2_HAVE_ASM_SWAB */
318
319#if !defined(_EXT2_HAVE_ASM_FINDBIT_)
320_INLINE_ int ext2fs_find_first_bit_set(void * addr, unsigned size)
321{
322 char *cp = (unsigned char *) addr;
323 int res = 0, d0;
324
325 if (!size)
326 return 0;
327
328 while ((size > res) && (*cp == 0)) {
329 cp++;
330 res += 8;
331 }
332 d0 = ffs(*cp);
333 if (d0 == 0)
334 return size;
335
336 return res + d0 - 1;
337}
338
339_INLINE_ int ext2fs_find_next_bit_set (void * addr, int size, int offset)
340{
341 unsigned char * p;
342 int set = 0, bit = offset & 7, res = 0, d0;
343
344 res = offset >> 3;
345 p = ((unsigned char *) addr) + res;
346
347 if (bit) {
348 set = ffs(*p & ~((1 << bit) - 1));
349 if (set)
350 return (offset & ~7) + set - 1;
351 p++;
352 res += 8;
353 }
354 while ((size > res) && (*p == 0)) {
355 p++;
356 res += 8;
357 }
358 d0 = ffs(*p);
359 if (d0 == 0)
360 return size;
361
362 return (res + d0 - 1);
363}
364#endif
365
366_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
367 blk_t bitno);
368
369_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
370 blk_t bitno)
371{
372 if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
373 ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
374 return 0;
375 }
376 return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
377}
378
379_INLINE_ int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
380 blk_t block)
381{
382 return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap)
383 bitmap,
384 block);
385}
386
387_INLINE_ int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
388 blk_t block)
389{
390 return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
391 block);
392}
393
394_INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
395 blk_t block)
396{
397 return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
398 block);
399}
400
401_INLINE_ int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
402 ext2_ino_t inode)
403{
404 return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
405 inode);
406}
407
408_INLINE_ int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
409 ext2_ino_t inode)
410{
411 return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
412 inode);
413}
414
415_INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
416 ext2_ino_t inode)
417{
418 return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
419 inode);
420}
421
422_INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
423 blk_t block)
424{
425#ifdef EXT2FS_DEBUG_FAST_OPS
426 if ((block < bitmap->start) || (block > bitmap->end)) {
427 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
428 bitmap->description);
429 return;
430 }
431#endif
432 ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
433}
434
435_INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
436 blk_t block)
437{
438#ifdef EXT2FS_DEBUG_FAST_OPS
439 if ((block < bitmap->start) || (block > bitmap->end)) {
440 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK,
441 block, bitmap->description);
442 return;
443 }
444#endif
445 ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
446}
447
448_INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
449 blk_t block)
450{
451#ifdef EXT2FS_DEBUG_FAST_OPS
452 if ((block < bitmap->start) || (block > bitmap->end)) {
453 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
454 block, bitmap->description);
455 return 0;
456 }
457#endif
458 return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
459}
460
461_INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
462 ext2_ino_t inode)
463{
464#ifdef EXT2FS_DEBUG_FAST_OPS
465 if ((inode < bitmap->start) || (inode > bitmap->end)) {
466 ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_MARK,
467 inode, bitmap->description);
468 return;
469 }
470#endif
471 ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
472}
473
474_INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
475 ext2_ino_t inode)
476{
477#ifdef EXT2FS_DEBUG_FAST_OPS
478 if ((inode < bitmap->start) || (inode > bitmap->end)) {
479 ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_UNMARK,
480 inode, bitmap->description);
481 return;
482 }
483#endif
484 ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
485}
486
487_INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
488 ext2_ino_t inode)
489{
490#ifdef EXT2FS_DEBUG_FAST_OPS
491 if ((inode < bitmap->start) || (inode > bitmap->end)) {
492 ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
493 inode, bitmap->description);
494 return 0;
495 }
496#endif
497 return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
498}
499
500_INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
501{
502 return bitmap->start;
503}
504
505_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
506{
507 return bitmap->start;
508}
509
510_INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
511{
512 return bitmap->end;
513}
514
515_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
516{
517 return bitmap->end;
518}
519
520_INLINE_ int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
521 blk_t block, int num)
522{
523 int i;
524
525 if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
526 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
527 block, bitmap->description);
528 return 0;
529 }
530 for (i=0; i < num; i++) {
531 if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
532 return 0;
533 }
534 return 1;
535}
536
537_INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
538 blk_t block, int num)
539{
540 int i;
541
542#ifdef EXT2FS_DEBUG_FAST_OPS
543 if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
544 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
545 block, bitmap->description);
546 return 0;
547 }
548#endif
549 for (i=0; i < num; i++) {
550 if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
551 return 0;
552 }
553 return 1;
554}
555
556_INLINE_ void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
557 blk_t block, int num)
558{
559 int i;
560
561 if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
562 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
563 bitmap->description);
564 return;
565 }
566 for (i=0; i < num; i++)
567 ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
568}
569
570_INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
571 blk_t block, int num)
572{
573 int i;
574
575#ifdef EXT2FS_DEBUG_FAST_OPS
576 if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
577 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
578 bitmap->description);
579 return;
580 }
581#endif
582 for (i=0; i < num; i++)
583 ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
584}
585
586_INLINE_ void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
587 blk_t block, int num)
588{
589 int i;
590
591 if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
592 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
593 bitmap->description);
594 return;
595 }
596 for (i=0; i < num; i++)
597 ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
598}
599
600_INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
601 blk_t block, int num)
602{
603 int i;
604
605#ifdef EXT2FS_DEBUG_FAST_OPS
606 if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
607 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
608 bitmap->description);
609 return;
610 }
611#endif
612 for (i=0; i < num; i++)
613 ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
614}
615#undef _INLINE_
616#endif
617
diff --git a/e2fsprogs/ext2fs/block.c b/e2fsprogs/ext2fs/block.c
new file mode 100644
index 000000000..7685680df
--- /dev/null
+++ b/e2fsprogs/ext2fs/block.c
@@ -0,0 +1,437 @@
1/*
2 * block.c --- iterate over all blocks in an inode
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21struct block_context {
22 ext2_filsys fs;
23 int (*func)(ext2_filsys fs,
24 blk_t *blocknr,
25 e2_blkcnt_t bcount,
26 blk_t ref_blk,
27 int ref_offset,
28 void *priv_data);
29 e2_blkcnt_t bcount;
30 int bsize;
31 int flags;
32 errcode_t errcode;
33 char *ind_buf;
34 char *dind_buf;
35 char *tind_buf;
36 void *priv_data;
37};
38
39static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
40 int ref_offset, struct block_context *ctx)
41{
42 int ret = 0, changed = 0;
43 int i, flags, limit, offset;
44 blk_t *block_nr;
45
46 limit = ctx->fs->blocksize >> 2;
47 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
48 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
49 ret = (*ctx->func)(ctx->fs, ind_block,
50 BLOCK_COUNT_IND, ref_block,
51 ref_offset, ctx->priv_data);
52 if (!*ind_block || (ret & BLOCK_ABORT)) {
53 ctx->bcount += limit;
54 return ret;
55 }
56 if (*ind_block >= ctx->fs->super->s_blocks_count ||
57 *ind_block < ctx->fs->super->s_first_data_block) {
58 ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
59 ret |= BLOCK_ERROR;
60 return ret;
61 }
62 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
63 ctx->ind_buf);
64 if (ctx->errcode) {
65 ret |= BLOCK_ERROR;
66 return ret;
67 }
68
69 block_nr = (blk_t *) ctx->ind_buf;
70 offset = 0;
71 if (ctx->flags & BLOCK_FLAG_APPEND) {
72 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
73 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
74 *ind_block, offset,
75 ctx->priv_data);
76 changed |= flags;
77 if (flags & BLOCK_ABORT) {
78 ret |= BLOCK_ABORT;
79 break;
80 }
81 offset += sizeof(blk_t);
82 }
83 } else {
84 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
85 if (*block_nr == 0)
86 continue;
87 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
88 *ind_block, offset,
89 ctx->priv_data);
90 changed |= flags;
91 if (flags & BLOCK_ABORT) {
92 ret |= BLOCK_ABORT;
93 break;
94 }
95 offset += sizeof(blk_t);
96 }
97 }
98 if (changed & BLOCK_CHANGED) {
99 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
100 ctx->ind_buf);
101 if (ctx->errcode)
102 ret |= BLOCK_ERROR | BLOCK_ABORT;
103 }
104 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
105 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
106 !(ret & BLOCK_ABORT))
107 ret |= (*ctx->func)(ctx->fs, ind_block,
108 BLOCK_COUNT_IND, ref_block,
109 ref_offset, ctx->priv_data);
110 return ret;
111}
112
113static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
114 int ref_offset, struct block_context *ctx)
115{
116 int ret = 0, changed = 0;
117 int i, flags, limit, offset;
118 blk_t *block_nr;
119
120 limit = ctx->fs->blocksize >> 2;
121 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
122 BLOCK_FLAG_DATA_ONLY)))
123 ret = (*ctx->func)(ctx->fs, dind_block,
124 BLOCK_COUNT_DIND, ref_block,
125 ref_offset, ctx->priv_data);
126 if (!*dind_block || (ret & BLOCK_ABORT)) {
127 ctx->bcount += limit*limit;
128 return ret;
129 }
130 if (*dind_block >= ctx->fs->super->s_blocks_count ||
131 *dind_block < ctx->fs->super->s_first_data_block) {
132 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
133 ret |= BLOCK_ERROR;
134 return ret;
135 }
136 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
137 ctx->dind_buf);
138 if (ctx->errcode) {
139 ret |= BLOCK_ERROR;
140 return ret;
141 }
142
143 block_nr = (blk_t *) ctx->dind_buf;
144 offset = 0;
145 if (ctx->flags & BLOCK_FLAG_APPEND) {
146 for (i = 0; i < limit; i++, block_nr++) {
147 flags = block_iterate_ind(block_nr,
148 *dind_block, offset,
149 ctx);
150 changed |= flags;
151 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
152 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
153 break;
154 }
155 offset += sizeof(blk_t);
156 }
157 } else {
158 for (i = 0; i < limit; i++, block_nr++) {
159 if (*block_nr == 0) {
160 ctx->bcount += limit;
161 continue;
162 }
163 flags = block_iterate_ind(block_nr,
164 *dind_block, offset,
165 ctx);
166 changed |= flags;
167 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
168 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
169 break;
170 }
171 offset += sizeof(blk_t);
172 }
173 }
174 if (changed & BLOCK_CHANGED) {
175 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
176 ctx->dind_buf);
177 if (ctx->errcode)
178 ret |= BLOCK_ERROR | BLOCK_ABORT;
179 }
180 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
181 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
182 !(ret & BLOCK_ABORT))
183 ret |= (*ctx->func)(ctx->fs, dind_block,
184 BLOCK_COUNT_DIND, ref_block,
185 ref_offset, ctx->priv_data);
186 return ret;
187}
188
189static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
190 int ref_offset, struct block_context *ctx)
191{
192 int ret = 0, changed = 0;
193 int i, flags, limit, offset;
194 blk_t *block_nr;
195
196 limit = ctx->fs->blocksize >> 2;
197 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
198 BLOCK_FLAG_DATA_ONLY)))
199 ret = (*ctx->func)(ctx->fs, tind_block,
200 BLOCK_COUNT_TIND, ref_block,
201 ref_offset, ctx->priv_data);
202 if (!*tind_block || (ret & BLOCK_ABORT)) {
203 ctx->bcount += limit*limit*limit;
204 return ret;
205 }
206 if (*tind_block >= ctx->fs->super->s_blocks_count ||
207 *tind_block < ctx->fs->super->s_first_data_block) {
208 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
209 ret |= BLOCK_ERROR;
210 return ret;
211 }
212 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
213 ctx->tind_buf);
214 if (ctx->errcode) {
215 ret |= BLOCK_ERROR;
216 return ret;
217 }
218
219 block_nr = (blk_t *) ctx->tind_buf;
220 offset = 0;
221 if (ctx->flags & BLOCK_FLAG_APPEND) {
222 for (i = 0; i < limit; i++, block_nr++) {
223 flags = block_iterate_dind(block_nr,
224 *tind_block,
225 offset, ctx);
226 changed |= flags;
227 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
228 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
229 break;
230 }
231 offset += sizeof(blk_t);
232 }
233 } else {
234 for (i = 0; i < limit; i++, block_nr++) {
235 if (*block_nr == 0) {
236 ctx->bcount += limit*limit;
237 continue;
238 }
239 flags = block_iterate_dind(block_nr,
240 *tind_block,
241 offset, ctx);
242 changed |= flags;
243 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
244 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
245 break;
246 }
247 offset += sizeof(blk_t);
248 }
249 }
250 if (changed & BLOCK_CHANGED) {
251 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
252 ctx->tind_buf);
253 if (ctx->errcode)
254 ret |= BLOCK_ERROR | BLOCK_ABORT;
255 }
256 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
257 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
258 !(ret & BLOCK_ABORT))
259 ret |= (*ctx->func)(ctx->fs, tind_block,
260 BLOCK_COUNT_TIND, ref_block,
261 ref_offset, ctx->priv_data);
262
263 return ret;
264}
265
266errcode_t ext2fs_block_iterate2(ext2_filsys fs,
267 ext2_ino_t ino,
268 int flags,
269 char *block_buf,
270 int (*func)(ext2_filsys fs,
271 blk_t *blocknr,
272 e2_blkcnt_t blockcnt,
273 blk_t ref_blk,
274 int ref_offset,
275 void *priv_data),
276 void *priv_data)
277{
278 int i;
279 int got_inode = 0;
280 int ret = 0;
281 blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
282 struct ext2_inode inode;
283 errcode_t retval;
284 struct block_context ctx;
285 int limit;
286
287 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
288
289 /*
290 * Check to see if we need to limit large files
291 */
292 if (flags & BLOCK_FLAG_NO_LARGE) {
293 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
294 if (ctx.errcode)
295 return ctx.errcode;
296 got_inode = 1;
297 if (!LINUX_S_ISDIR(inode.i_mode) &&
298 (inode.i_size_high != 0))
299 return EXT2_ET_FILE_TOO_BIG;
300 }
301
302 retval = ext2fs_get_blocks(fs, ino, blocks);
303 if (retval)
304 return retval;
305
306 limit = fs->blocksize >> 2;
307
308 ctx.fs = fs;
309 ctx.func = func;
310 ctx.priv_data = priv_data;
311 ctx.flags = flags;
312 ctx.bcount = 0;
313 if (block_buf) {
314 ctx.ind_buf = block_buf;
315 } else {
316 retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf);
317 if (retval)
318 return retval;
319 }
320 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
321 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
322
323 /*
324 * Iterate over the HURD translator block (if present)
325 */
326 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
327 !(flags & BLOCK_FLAG_DATA_ONLY)) {
328 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
329 if (ctx.errcode)
330 goto abort_exit;
331 got_inode = 1;
332 if (inode.osd1.hurd1.h_i_translator) {
333 ret |= (*ctx.func)(fs,
334 &inode.osd1.hurd1.h_i_translator,
335 BLOCK_COUNT_TRANSLATOR,
336 0, 0, priv_data);
337 if (ret & BLOCK_ABORT)
338 goto abort_exit;
339 }
340 }
341
342 /*
343 * Iterate over normal data blocks
344 */
345 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
346 if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
347 ret |= (*ctx.func)(fs, &blocks[i],
348 ctx.bcount, 0, i, priv_data);
349 if (ret & BLOCK_ABORT)
350 goto abort_exit;
351 }
352 }
353 if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
354 ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
355 0, EXT2_IND_BLOCK, &ctx);
356 if (ret & BLOCK_ABORT)
357 goto abort_exit;
358 } else
359 ctx.bcount += limit;
360 if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
361 ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
362 0, EXT2_DIND_BLOCK, &ctx);
363 if (ret & BLOCK_ABORT)
364 goto abort_exit;
365 } else
366 ctx.bcount += limit * limit;
367 if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
368 ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
369 0, EXT2_TIND_BLOCK, &ctx);
370 if (ret & BLOCK_ABORT)
371 goto abort_exit;
372 }
373
374abort_exit:
375 if (ret & BLOCK_CHANGED) {
376 if (!got_inode) {
377 retval = ext2fs_read_inode(fs, ino, &inode);
378 if (retval)
379 return retval;
380 }
381 for (i=0; i < EXT2_N_BLOCKS; i++)
382 inode.i_block[i] = blocks[i];
383 retval = ext2fs_write_inode(fs, ino, &inode);
384 if (retval)
385 return retval;
386 }
387
388 if (!block_buf)
389 ext2fs_free_mem(&ctx.ind_buf);
390
391 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
392}
393
394/*
395 * Emulate the old ext2fs_block_iterate function!
396 */
397
398struct xlate {
399 int (*func)(ext2_filsys fs,
400 blk_t *blocknr,
401 int bcount,
402 void *priv_data);
403 void *real_private;
404};
405
406#ifdef __TURBOC__
407 #pragma argsused
408#endif
409static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
410 blk_t ref_block EXT2FS_ATTR((unused)),
411 int ref_offset EXT2FS_ATTR((unused)),
412 void *priv_data)
413{
414 struct xlate *xl = (struct xlate *) priv_data;
415
416 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
417}
418
419errcode_t ext2fs_block_iterate(ext2_filsys fs,
420 ext2_ino_t ino,
421 int flags,
422 char *block_buf,
423 int (*func)(ext2_filsys fs,
424 blk_t *blocknr,
425 int blockcnt,
426 void *priv_data),
427 void *priv_data)
428{
429 struct xlate xl;
430
431 xl.real_private = priv_data;
432 xl.func = func;
433
434 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
435 block_buf, xlate_func, &xl);
436}
437
diff --git a/e2fsprogs/ext2fs/bmap.c b/e2fsprogs/ext2fs/bmap.c
new file mode 100644
index 000000000..e84004476
--- /dev/null
+++ b/e2fsprogs/ext2fs/bmap.c
@@ -0,0 +1,270 @@
1/*
2 * bmap.c --- logical to physical block mapping
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
22#define _BMAP_INLINE_ __inline__
23#else
24#define _BMAP_INLINE_
25#endif
26
27extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
28 struct ext2_inode *inode,
29 char *block_buf, int bmap_flags,
30 blk_t block, blk_t *phys_blk);
31
32#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
33
34static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags,
35 blk_t ind, char *block_buf,
36 int *blocks_alloc,
37 blk_t nr, blk_t *ret_blk)
38{
39 errcode_t retval;
40 blk_t b;
41
42 if (!ind) {
43 if (flags & BMAP_SET)
44 return EXT2_ET_SET_BMAP_NO_IND;
45 *ret_blk = 0;
46 return 0;
47 }
48 retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
49 if (retval)
50 return retval;
51
52 if (flags & BMAP_SET) {
53 b = *ret_blk;
54#ifdef EXT2FS_ENABLE_SWAPFS
55 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
56 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
57 b = ext2fs_swab32(b);
58#endif
59 ((blk_t *) block_buf)[nr] = b;
60 return io_channel_write_blk(fs->io, ind, 1, block_buf);
61 }
62
63 b = ((blk_t *) block_buf)[nr];
64
65#ifdef EXT2FS_ENABLE_SWAPFS
66 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
67 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
68 b = ext2fs_swab32(b);
69#endif
70
71 if (!b && (flags & BMAP_ALLOC)) {
72 b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
73 retval = ext2fs_alloc_block(fs, b,
74 block_buf + fs->blocksize, &b);
75 if (retval)
76 return retval;
77
78#ifdef EXT2FS_ENABLE_SWAPFS
79 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
80 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
81 ((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
82 else
83#endif
84 ((blk_t *) block_buf)[nr] = b;
85
86 retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
87 if (retval)
88 return retval;
89
90 (*blocks_alloc)++;
91 }
92
93 *ret_blk = b;
94 return 0;
95}
96
97static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags,
98 blk_t dind, char *block_buf,
99 int *blocks_alloc,
100 blk_t nr, blk_t *ret_blk)
101{
102 blk_t b;
103 errcode_t retval;
104 blk_t addr_per_block;
105
106 addr_per_block = (blk_t) fs->blocksize >> 2;
107
108 retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf,
109 blocks_alloc, nr / addr_per_block, &b);
110 if (retval)
111 return retval;
112 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
113 nr % addr_per_block, ret_blk);
114 return retval;
115}
116
117static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
118 blk_t tind, char *block_buf,
119 int *blocks_alloc,
120 blk_t nr, blk_t *ret_blk)
121{
122 blk_t b;
123 errcode_t retval;
124 blk_t addr_per_block;
125
126 addr_per_block = (blk_t) fs->blocksize >> 2;
127
128 retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf,
129 blocks_alloc, nr / addr_per_block, &b);
130 if (retval)
131 return retval;
132 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
133 nr % addr_per_block, ret_blk);
134 return retval;
135}
136
137errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
138 char *block_buf, int bmap_flags, blk_t block,
139 blk_t *phys_blk)
140{
141 struct ext2_inode inode_buf;
142 blk_t addr_per_block;
143 blk_t b;
144 char *buf = 0;
145 errcode_t retval = 0;
146 int blocks_alloc = 0, inode_dirty = 0;
147
148 if (!(bmap_flags & BMAP_SET))
149 *phys_blk = 0;
150
151 /* Read inode structure if necessary */
152 if (!inode) {
153 retval = ext2fs_read_inode(fs, ino, &inode_buf);
154 if (retval)
155 return retval;
156 inode = &inode_buf;
157 }
158 addr_per_block = (blk_t) fs->blocksize >> 2;
159
160 if (!block_buf) {
161 retval = ext2fs_get_mem(fs->blocksize * 2, &buf);
162 if (retval)
163 return retval;
164 block_buf = buf;
165 }
166
167 if (block < EXT2_NDIR_BLOCKS) {
168 if (bmap_flags & BMAP_SET) {
169 b = *phys_blk;
170#ifdef EXT2FS_ENABLE_SWAPFS
171 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
172 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
173 b = ext2fs_swab32(b);
174#endif
175 inode_bmap(inode, block) = b;
176 inode_dirty++;
177 goto done;
178 }
179
180 *phys_blk = inode_bmap(inode, block);
181 b = block ? inode_bmap(inode, block-1) : 0;
182
183 if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
184 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
185 if (retval)
186 goto done;
187 inode_bmap(inode, block) = b;
188 blocks_alloc++;
189 *phys_blk = b;
190 }
191 goto done;
192 }
193
194 /* Indirect block */
195 block -= EXT2_NDIR_BLOCKS;
196 if (block < addr_per_block) {
197 b = inode_bmap(inode, EXT2_IND_BLOCK);
198 if (!b) {
199 if (!(bmap_flags & BMAP_ALLOC)) {
200 if (bmap_flags & BMAP_SET)
201 retval = EXT2_ET_SET_BMAP_NO_IND;
202 goto done;
203 }
204
205 b = inode_bmap(inode, EXT2_IND_BLOCK-1);
206 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
207 if (retval)
208 goto done;
209 inode_bmap(inode, EXT2_IND_BLOCK) = b;
210 blocks_alloc++;
211 }
212 retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
213 &blocks_alloc, block, phys_blk);
214 goto done;
215 }
216
217 /* Doubly indirect block */
218 block -= addr_per_block;
219 if (block < addr_per_block * addr_per_block) {
220 b = inode_bmap(inode, EXT2_DIND_BLOCK);
221 if (!b) {
222 if (!(bmap_flags & BMAP_ALLOC)) {
223 if (bmap_flags & BMAP_SET)
224 retval = EXT2_ET_SET_BMAP_NO_IND;
225 goto done;
226 }
227
228 b = inode_bmap(inode, EXT2_IND_BLOCK);
229 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
230 if (retval)
231 goto done;
232 inode_bmap(inode, EXT2_DIND_BLOCK) = b;
233 blocks_alloc++;
234 }
235 retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
236 &blocks_alloc, block, phys_blk);
237 goto done;
238 }
239
240 /* Triply indirect block */
241 block -= addr_per_block * addr_per_block;
242 b = inode_bmap(inode, EXT2_TIND_BLOCK);
243 if (!b) {
244 if (!(bmap_flags & BMAP_ALLOC)) {
245 if (bmap_flags & BMAP_SET)
246 retval = EXT2_ET_SET_BMAP_NO_IND;
247 goto done;
248 }
249
250 b = inode_bmap(inode, EXT2_DIND_BLOCK);
251 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
252 if (retval)
253 goto done;
254 inode_bmap(inode, EXT2_TIND_BLOCK) = b;
255 blocks_alloc++;
256 }
257 retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
258 &blocks_alloc, block, phys_blk);
259done:
260 if (buf)
261 ext2fs_free_mem(&buf);
262 if ((retval == 0) && (blocks_alloc || inode_dirty)) {
263 inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
264 retval = ext2fs_write_inode(fs, ino, inode);
265 }
266 return retval;
267}
268
269
270
diff --git a/e2fsprogs/ext2fs/bmove.c b/e2fsprogs/ext2fs/bmove.c
new file mode 100644
index 000000000..0b2ebb183
--- /dev/null
+++ b/e2fsprogs/ext2fs/bmove.c
@@ -0,0 +1,160 @@
1/*
2 * bmove.c --- Move blocks around to make way for a particular
3 * filesystem structure.
4 *
5 * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed
6 * under the terms of the GNU Public License.
7 */
8
9#include <stdio.h>
10#include <string.h>
11#if HAVE_UNISTD_H
12#include <unistd.h>
13#endif
14#if HAVE_SYS_TYPES_H
15#include <sys/types.h>
16#endif
17#if HAVE_SYS_TIME_H
18#include <sys/time.h>
19#endif
20
21#include "ext2_fs.h"
22#include "ext2fsP.h"
23
24struct process_block_struct {
25 ext2_ino_t ino;
26 struct ext2_inode * inode;
27 ext2fs_block_bitmap reserve;
28 ext2fs_block_bitmap alloc_map;
29 errcode_t error;
30 char *buf;
31 int add_dir;
32 int flags;
33};
34
35static int process_block(ext2_filsys fs, blk_t *block_nr,
36 e2_blkcnt_t blockcnt, blk_t ref_block,
37 int ref_offset, void *priv_data)
38{
39 struct process_block_struct *pb;
40 errcode_t retval;
41 int ret;
42 blk_t block, orig;
43
44 pb = (struct process_block_struct *) priv_data;
45 block = orig = *block_nr;
46 ret = 0;
47
48 /*
49 * Let's see if this is one which we need to relocate
50 */
51 if (ext2fs_test_block_bitmap(pb->reserve, block)) {
52 do {
53 if (++block >= fs->super->s_blocks_count)
54 block = fs->super->s_first_data_block;
55 if (block == orig) {
56 pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
57 return BLOCK_ABORT;
58 }
59 } while (ext2fs_test_block_bitmap(pb->reserve, block) ||
60 ext2fs_test_block_bitmap(pb->alloc_map, block));
61
62 retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
63 if (retval) {
64 pb->error = retval;
65 return BLOCK_ABORT;
66 }
67 retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
68 if (retval) {
69 pb->error = retval;
70 return BLOCK_ABORT;
71 }
72 *block_nr = block;
73 ext2fs_mark_block_bitmap(pb->alloc_map, block);
74 ret = BLOCK_CHANGED;
75 if (pb->flags & EXT2_BMOVE_DEBUG)
76 printf("ino=%ld, blockcnt=%lld, %d->%d\n", pb->ino,
77 blockcnt, orig, block);
78 }
79 if (pb->add_dir) {
80 retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
81 block, (int) blockcnt);
82 if (retval) {
83 pb->error = retval;
84 ret |= BLOCK_ABORT;
85 }
86 }
87 return ret;
88}
89
90errcode_t ext2fs_move_blocks(ext2_filsys fs,
91 ext2fs_block_bitmap reserve,
92 ext2fs_block_bitmap alloc_map,
93 int flags)
94{
95 ext2_ino_t ino;
96 struct ext2_inode inode;
97 errcode_t retval;
98 struct process_block_struct pb;
99 ext2_inode_scan scan;
100 char *block_buf;
101
102 retval = ext2fs_open_inode_scan(fs, 0, &scan);
103 if (retval)
104 return retval;
105
106 pb.reserve = reserve;
107 pb.error = 0;
108 pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
109 pb.flags = flags;
110
111 retval = ext2fs_get_mem(fs->blocksize * 4, &block_buf);
112 if (retval)
113 return retval;
114 pb.buf = block_buf + fs->blocksize * 3;
115
116 /*
117 * If GET_DBLIST is set in the flags field, then we should
118 * gather directory block information while we're doing the
119 * block move.
120 */
121 if (flags & EXT2_BMOVE_GET_DBLIST) {
122 if (fs->dblist) {
123 ext2fs_free_dblist(fs->dblist);
124 fs->dblist = NULL;
125 }
126 retval = ext2fs_init_dblist(fs, 0);
127 if (retval)
128 return retval;
129 }
130
131 retval = ext2fs_get_next_inode(scan, &ino, &inode);
132 if (retval)
133 return retval;
134
135 while (ino) {
136 if ((inode.i_links_count == 0) ||
137 !ext2fs_inode_has_valid_blocks(&inode))
138 goto next;
139
140 pb.ino = ino;
141 pb.inode = &inode;
142
143 pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
144 flags & EXT2_BMOVE_GET_DBLIST);
145
146 retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
147 process_block, &pb);
148 if (retval)
149 return retval;
150 if (pb.error)
151 return pb.error;
152
153 next:
154 retval = ext2fs_get_next_inode(scan, &ino, &inode);
155 if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
156 goto next;
157 }
158 return 0;
159}
160
diff --git a/e2fsprogs/ext2fs/brel.h b/e2fsprogs/ext2fs/brel.h
new file mode 100644
index 000000000..be97243ca
--- /dev/null
+++ b/e2fsprogs/ext2fs/brel.h
@@ -0,0 +1,86 @@
1/*
2 * brel.h
3 *
4 * Copyright (C) 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12struct ext2_block_relocate_entry {
13 blk_t new;
14 __s16 offset;
15 __u16 flags;
16 union {
17 blk_t block_ref;
18 ext2_ino_t inode_ref;
19 } owner;
20};
21
22#define RELOCATE_TYPE_REF 0x0007
23#define RELOCATE_BLOCK_REF 0x0001
24#define RELOCATE_INODE_REF 0x0002
25
26typedef struct ext2_block_relocation_table *ext2_brel;
27
28struct ext2_block_relocation_table {
29 __u32 magic;
30 char *name;
31 blk_t current;
32 void *priv_data;
33
34 /*
35 * Add a block relocation entry.
36 */
37 errcode_t (*put)(ext2_brel brel, blk_t old,
38 struct ext2_block_relocate_entry *ent);
39
40 /*
41 * Get a block relocation entry.
42 */
43 errcode_t (*get)(ext2_brel brel, blk_t old,
44 struct ext2_block_relocate_entry *ent);
45
46 /*
47 * Initialize for iterating over the block relocation entries.
48 */
49 errcode_t (*start_iter)(ext2_brel brel);
50
51 /*
52 * The iterator function for the inode relocation entries.
53 * Returns an inode number of 0 when out of entries.
54 */
55 errcode_t (*next)(ext2_brel brel, blk_t *old,
56 struct ext2_block_relocate_entry *ent);
57
58 /*
59 * Move the inode relocation table from one block number to
60 * another.
61 */
62 errcode_t (*move)(ext2_brel brel, blk_t old, blk_t new);
63
64 /*
65 * Remove a block relocation entry.
66 */
67 errcode_t (*delete)(ext2_brel brel, blk_t old);
68
69
70 /*
71 * Free the block relocation table.
72 */
73 errcode_t (*free)(ext2_brel brel);
74};
75
76errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
77 ext2_brel *brel);
78
79#define ext2fs_brel_put(brel, old, ent) ((brel)->put((brel), old, ent))
80#define ext2fs_brel_get(brel, old, ent) ((brel)->get((brel), old, ent))
81#define ext2fs_brel_start_iter(brel) ((brel)->start_iter((brel)))
82#define ext2fs_brel_next(brel, old, ent) ((brel)->next((brel), old, ent))
83#define ext2fs_brel_move(brel, old, new) ((brel)->move((brel), old, new))
84#define ext2fs_brel_delete(brel, old) ((brel)->delete((brel), old))
85#define ext2fs_brel_free(brel) ((brel)->free((brel)))
86
diff --git a/e2fsprogs/ext2fs/brel_ma.c b/e2fsprogs/ext2fs/brel_ma.c
new file mode 100644
index 000000000..d422bb2e9
--- /dev/null
+++ b/e2fsprogs/ext2fs/brel_ma.c
@@ -0,0 +1,197 @@
1/*
2 * brel_ma.c
3 *
4 * Copyright (C) 1996, 1997 Theodore Ts'o.
5 *
6 * TODO: rewrite to not use a direct array!!! (Fortunately this
7 * module isn't really used yet.)
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 <fcntl.h>
16#include <stdio.h>
17#include <string.h>
18#if HAVE_UNISTD_H
19#include <unistd.h>
20#endif
21#if HAVE_ERRNO_H
22#include <errno.h>
23#endif
24
25#include "ext2_fs.h"
26#include "ext2fs.h"
27#include "brel.h"
28
29static errcode_t bma_put(ext2_brel brel, blk_t old,
30 struct ext2_block_relocate_entry *ent);
31static errcode_t bma_get(ext2_brel brel, blk_t old,
32 struct ext2_block_relocate_entry *ent);
33static errcode_t bma_start_iter(ext2_brel brel);
34static errcode_t bma_next(ext2_brel brel, blk_t *old,
35 struct ext2_block_relocate_entry *ent);
36static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new);
37static errcode_t bma_delete(ext2_brel brel, blk_t old);
38static errcode_t bma_free(ext2_brel brel);
39
40struct brel_ma {
41 __u32 magic;
42 blk_t max_block;
43 struct ext2_block_relocate_entry *entries;
44};
45
46errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
47 ext2_brel *new_brel)
48{
49 ext2_brel brel = 0;
50 errcode_t retval;
51 struct brel_ma *ma = 0;
52 size_t size;
53
54 *new_brel = 0;
55
56 /*
57 * Allocate memory structures
58 */
59 retval = ext2fs_get_mem(sizeof(struct ext2_block_relocation_table),
60 &brel);
61 if (retval)
62 goto errout;
63 memset(brel, 0, sizeof(struct ext2_block_relocation_table));
64
65 retval = ext2fs_get_mem(strlen(name)+1, &brel->name);
66 if (retval)
67 goto errout;
68 strcpy(brel->name, name);
69
70 retval = ext2fs_get_mem(sizeof(struct brel_ma), &ma);
71 if (retval)
72 goto errout;
73 memset(ma, 0, sizeof(struct brel_ma));
74 brel->priv_data = ma;
75
76 size = (size_t) (sizeof(struct ext2_block_relocate_entry) *
77 (max_block+1));
78 retval = ext2fs_get_mem(size, &ma->entries);
79 if (retval)
80 goto errout;
81 memset(ma->entries, 0, size);
82 ma->max_block = max_block;
83
84 /*
85 * Fill in the brel data structure
86 */
87 brel->put = bma_put;
88 brel->get = bma_get;
89 brel->start_iter = bma_start_iter;
90 brel->next = bma_next;
91 brel->move = bma_move;
92 brel->delete = bma_delete;
93 brel->free = bma_free;
94
95 *new_brel = brel;
96 return 0;
97
98errout:
99 bma_free(brel);
100 return retval;
101}
102
103static errcode_t bma_put(ext2_brel brel, blk_t old,
104 struct ext2_block_relocate_entry *ent)
105{
106 struct brel_ma *ma;
107
108 ma = brel->priv_data;
109 if (old > ma->max_block)
110 return EXT2_ET_INVALID_ARGUMENT;
111 ma->entries[(unsigned)old] = *ent;
112 return 0;
113}
114
115static errcode_t bma_get(ext2_brel brel, blk_t old,
116 struct ext2_block_relocate_entry *ent)
117{
118 struct brel_ma *ma;
119
120 ma = brel->priv_data;
121 if (old > ma->max_block)
122 return EXT2_ET_INVALID_ARGUMENT;
123 if (ma->entries[(unsigned)old].new == 0)
124 return ENOENT;
125 *ent = ma->entries[old];
126 return 0;
127}
128
129static errcode_t bma_start_iter(ext2_brel brel)
130{
131 brel->current = 0;
132 return 0;
133}
134
135static errcode_t bma_next(ext2_brel brel, blk_t *old,
136 struct ext2_block_relocate_entry *ent)
137{
138 struct brel_ma *ma;
139
140 ma = brel->priv_data;
141 while (++brel->current < ma->max_block) {
142 if (ma->entries[(unsigned)brel->current].new == 0)
143 continue;
144 *old = brel->current;
145 *ent = ma->entries[(unsigned)brel->current];
146 return 0;
147 }
148 *old = 0;
149 return 0;
150}
151
152static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new)
153{
154 struct brel_ma *ma;
155
156 ma = brel->priv_data;
157 if ((old > ma->max_block) || (new > ma->max_block))
158 return EXT2_ET_INVALID_ARGUMENT;
159 if (ma->entries[(unsigned)old].new == 0)
160 return ENOENT;
161 ma->entries[(unsigned)new] = ma->entries[old];
162 ma->entries[(unsigned)old].new = 0;
163 return 0;
164}
165
166static errcode_t bma_delete(ext2_brel brel, blk_t old)
167{
168 struct brel_ma *ma;
169
170 ma = brel->priv_data;
171 if (old > ma->max_block)
172 return EXT2_ET_INVALID_ARGUMENT;
173 if (ma->entries[(unsigned)old].new == 0)
174 return ENOENT;
175 ma->entries[(unsigned)old].new = 0;
176 return 0;
177}
178
179static errcode_t bma_free(ext2_brel brel)
180{
181 struct brel_ma *ma;
182
183 if (!brel)
184 return 0;
185
186 ma = brel->priv_data;
187
188 if (ma) {
189 if (ma->entries)
190 ext2fs_free_mem(&ma->entries);
191 ext2fs_free_mem(&ma);
192 }
193 if (brel->name)
194 ext2fs_free_mem(&brel->name);
195 ext2fs_free_mem(&brel);
196 return 0;
197}
diff --git a/e2fsprogs/ext2fs/check_desc.c b/e2fsprogs/ext2fs/check_desc.c
new file mode 100644
index 000000000..2a754c7f6
--- /dev/null
+++ b/e2fsprogs/ext2fs/check_desc.c
@@ -0,0 +1,68 @@
1/*
2 * check_desc.c --- Check the group descriptors of an ext2 filesystem
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28
29/*
30 * This routine sanity checks the group descriptors
31 */
32errcode_t ext2fs_check_desc(ext2_filsys fs)
33{
34 dgrp_t i;
35 blk_t block = fs->super->s_first_data_block;
36 blk_t next;
37
38 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
39
40 for (i = 0; i < fs->group_desc_count; i++) {
41 next = block + fs->super->s_blocks_per_group;
42 /*
43 * Check to make sure block bitmap for group is
44 * located within the group.
45 */
46 if (fs->group_desc[i].bg_block_bitmap < block ||
47 fs->group_desc[i].bg_block_bitmap >= next)
48 return EXT2_ET_GDESC_BAD_BLOCK_MAP;
49 /*
50 * Check to make sure inode bitmap for group is
51 * located within the group
52 */
53 if (fs->group_desc[i].bg_inode_bitmap < block ||
54 fs->group_desc[i].bg_inode_bitmap >= next)
55 return EXT2_ET_GDESC_BAD_INODE_MAP;
56 /*
57 * Check to make sure inode table for group is located
58 * within the group
59 */
60 if (fs->group_desc[i].bg_inode_table < block ||
61 ((fs->group_desc[i].bg_inode_table +
62 fs->inode_blocks_per_group) >= next))
63 return EXT2_ET_GDESC_BAD_INODE_TABLE;
64
65 block = next;
66 }
67 return 0;
68}
diff --git a/e2fsprogs/ext2fs/closefs.c b/e2fsprogs/ext2fs/closefs.c
new file mode 100644
index 000000000..8539a1c25
--- /dev/null
+++ b/e2fsprogs/ext2fs/closefs.c
@@ -0,0 +1,381 @@
1/*
2 * closefs.c --- close an ext2 filesystem
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#if HAVE_UNISTD_H
14#include <unistd.h>
15#endif
16#include <time.h>
17#include <string.h>
18
19#include "ext2_fs.h"
20#include "ext2fsP.h"
21
22static int test_root(int a, int b)
23{
24 if (a == 0)
25 return 1;
26 while (1) {
27 if (a == 1)
28 return 1;
29 if (a % b)
30 return 0;
31 a = a / b;
32 }
33}
34
35int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
36{
37 if (!(fs->super->s_feature_ro_compat &
38 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
39 return 1;
40
41 if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
42 test_root(group_block, 7))
43 return 1;
44
45 return 0;
46}
47
48int ext2fs_super_and_bgd_loc(ext2_filsys fs,
49 dgrp_t group,
50 blk_t *ret_super_blk,
51 blk_t *ret_old_desc_blk,
52 blk_t *ret_new_desc_blk,
53 int *ret_meta_bg)
54{
55 blk_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
56 unsigned int meta_bg, meta_bg_size;
57 int numblocks, has_super;
58 int old_desc_blocks;
59
60 group_block = fs->super->s_first_data_block +
61 (group * fs->super->s_blocks_per_group);
62
63 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
64 old_desc_blocks = fs->super->s_first_meta_bg;
65 else
66 old_desc_blocks =
67 fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
68
69 if (group == fs->group_desc_count-1) {
70 numblocks = (fs->super->s_blocks_count -
71 fs->super->s_first_data_block) %
72 fs->super->s_blocks_per_group;
73 if (!numblocks)
74 numblocks = fs->super->s_blocks_per_group;
75 } else
76 numblocks = fs->super->s_blocks_per_group;
77
78 has_super = ext2fs_bg_has_super(fs, group);
79
80 if (has_super) {
81 super_blk = group_block;
82 numblocks--;
83 }
84 meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
85 meta_bg = group / meta_bg_size;
86
87 if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
88 (meta_bg < fs->super->s_first_meta_bg)) {
89 if (has_super) {
90 old_desc_blk = group_block + 1;
91 numblocks -= old_desc_blocks;
92 }
93 } else {
94 if (((group % meta_bg_size) == 0) ||
95 ((group % meta_bg_size) == 1) ||
96 ((group % meta_bg_size) == (meta_bg_size-1))) {
97 if (has_super)
98 has_super = 1;
99 new_desc_blk = group_block + has_super;
100 numblocks--;
101 }
102 }
103
104 numblocks -= 2 + fs->inode_blocks_per_group;
105
106 if (ret_super_blk)
107 *ret_super_blk = super_blk;
108 if (ret_old_desc_blk)
109 *ret_old_desc_blk = old_desc_blk;
110 if (ret_new_desc_blk)
111 *ret_new_desc_blk = new_desc_blk;
112 if (ret_meta_bg)
113 *ret_meta_bg = meta_bg;
114 return (numblocks);
115}
116
117
118/*
119 * This function forces out the primary superblock. We need to only
120 * write out those fields which we have changed, since if the
121 * filesystem is mounted, it may have changed some of the other
122 * fields.
123 *
124 * It takes as input a superblock which has already been byte swapped
125 * (if necessary).
126 *
127 */
128static errcode_t write_primary_superblock(ext2_filsys fs,
129 struct ext2_super_block *super)
130{
131 __u16 *old_super, *new_super;
132 int check_idx, write_idx, size;
133 errcode_t retval;
134
135 if (!fs->io->manager->write_byte || !fs->orig_super) {
136 io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
137 retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
138 super);
139 io_channel_set_blksize(fs->io, fs->blocksize);
140 return retval;
141 }
142
143 old_super = (__u16 *) fs->orig_super;
144 new_super = (__u16 *) super;
145
146 for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) {
147 if (old_super[check_idx] == new_super[check_idx])
148 continue;
149 write_idx = check_idx;
150 for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++)
151 if (old_super[check_idx] == new_super[check_idx])
152 break;
153 size = 2 * (check_idx - write_idx);
154#if 0
155 printf("Writing %d bytes starting at %d\n",
156 size, write_idx*2);
157#endif
158 retval = io_channel_write_byte(fs->io,
159 SUPERBLOCK_OFFSET + (2 * write_idx), size,
160 new_super + write_idx);
161 if (retval)
162 return retval;
163 }
164 memcpy(fs->orig_super, super, SUPERBLOCK_SIZE);
165 return 0;
166}
167
168
169/*
170 * Updates the revision to EXT2_DYNAMIC_REV
171 */
172void ext2fs_update_dynamic_rev(ext2_filsys fs)
173{
174 struct ext2_super_block *sb = fs->super;
175
176 if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
177 return;
178
179 sb->s_rev_level = EXT2_DYNAMIC_REV;
180 sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
181 sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
182 /* s_uuid is handled by e2fsck already */
183 /* other fields should be left alone */
184}
185
186static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
187 blk_t group_block,
188 struct ext2_super_block *super_shadow)
189{
190 dgrp_t sgrp = group;
191
192 if (sgrp > ((1 << 16) - 1))
193 sgrp = (1 << 16) - 1;
194#ifdef EXT2FS_ENABLE_SWAPFS
195 if (fs->flags & EXT2_FLAG_SWAP_BYTES)
196 super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
197 else
198#endif
199 fs->super->s_block_group_nr = sgrp;
200
201 return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE,
202 super_shadow);
203}
204
205
206errcode_t ext2fs_flush(ext2_filsys fs)
207{
208 dgrp_t i,j;
209 blk_t group_block;
210 errcode_t retval;
211 unsigned long fs_state;
212 struct ext2_super_block *super_shadow = 0;
213 struct ext2_group_desc *group_shadow = 0;
214 struct ext2_group_desc *s, *t;
215 char *group_ptr;
216 int old_desc_blocks;
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#ifdef EXT2FS_ENABLE_SWAPFS
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#ifdef EXT2FS_ENABLE_SWAPFS
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#ifdef EXT2FS_ENABLE_SWAPFS
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/ext2fs/cmp_bitmaps.c b/e2fsprogs/ext2fs/cmp_bitmaps.c
new file mode 100644
index 000000000..51cc3d0a5
--- /dev/null
+++ b/e2fsprogs/ext2fs/cmp_bitmaps.c
@@ -0,0 +1,72 @@
1/*
2 * cmp_bitmaps.c --- routines to compare inode and block bitmaps.
3 *
4 * Copyright (C) 1995 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28
29errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
30 ext2fs_block_bitmap bm2)
31{
32 blk_t i;
33
34 EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_BLOCK_BITMAP);
35 EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_BLOCK_BITMAP);
36
37 if ((bm1->start != bm2->start) ||
38 (bm1->end != bm2->end) ||
39 (memcmp(bm1->bitmap, bm2->bitmap,
40 (size_t) (bm1->end - bm1->start)/8)))
41 return EXT2_ET_NEQ_BLOCK_BITMAP;
42
43 for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
44 if (ext2fs_fast_test_block_bitmap(bm1, i) !=
45 ext2fs_fast_test_block_bitmap(bm2, i))
46 return EXT2_ET_NEQ_BLOCK_BITMAP;
47
48 return 0;
49}
50
51errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
52 ext2fs_inode_bitmap bm2)
53{
54 ext2_ino_t i;
55
56 EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_INODE_BITMAP);
57 EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_INODE_BITMAP);
58
59 if ((bm1->start != bm2->start) ||
60 (bm1->end != bm2->end) ||
61 (memcmp(bm1->bitmap, bm2->bitmap,
62 (size_t) (bm1->end - bm1->start)/8)))
63 return EXT2_ET_NEQ_INODE_BITMAP;
64
65 for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
66 if (ext2fs_fast_test_inode_bitmap(bm1, i) !=
67 ext2fs_fast_test_inode_bitmap(bm2, i))
68 return EXT2_ET_NEQ_INODE_BITMAP;
69
70 return 0;
71}
72
diff --git a/e2fsprogs/ext2fs/dblist.c b/e2fsprogs/ext2fs/dblist.c
new file mode 100644
index 000000000..d5833d728
--- /dev/null
+++ b/e2fsprogs/ext2fs/dblist.c
@@ -0,0 +1,260 @@
1/*
2 * dblist.c -- directory block list functions
3 *
4 * Copyright 1997 by Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
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 "ext2fsP.h"
22
23static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b);
24
25/*
26 * Returns the number of directories in the filesystem as reported by
27 * the group descriptors. Of course, the group descriptors could be
28 * wrong!
29 */
30errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
31{
32 dgrp_t i;
33 ext2_ino_t num_dirs, max_dirs;
34
35 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
36
37 num_dirs = 0;
38 max_dirs = fs->super->s_inodes_per_group;
39 for (i = 0; i < fs->group_desc_count; i++) {
40 if (fs->group_desc[i].bg_used_dirs_count > max_dirs)
41 num_dirs += max_dirs / 8;
42 else
43 num_dirs += fs->group_desc[i].bg_used_dirs_count;
44 }
45 if (num_dirs > fs->super->s_inodes_count)
46 num_dirs = fs->super->s_inodes_count;
47
48 *ret_num_dirs = num_dirs;
49
50 return 0;
51}
52
53/*
54 * helper function for making a new directory block list (for
55 * initialize and copy).
56 */
57static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size, ext2_ino_t count,
58 struct ext2_db_entry *list,
59 ext2_dblist *ret_dblist)
60{
61 ext2_dblist dblist;
62 errcode_t retval;
63 size_t len;
64
65 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
66
67 if ((ret_dblist == 0) && fs->dblist &&
68 (fs->dblist->magic == EXT2_ET_MAGIC_DBLIST))
69 return 0;
70
71 retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist);
72 if (retval)
73 return retval;
74 memset(dblist, 0, sizeof(struct ext2_struct_dblist));
75
76 dblist->magic = EXT2_ET_MAGIC_DBLIST;
77 dblist->fs = fs;
78 if (size)
79 dblist->size = size;
80 else {
81 retval = ext2fs_get_num_dirs(fs, &dblist->size);
82 if (retval)
83 goto cleanup;
84 dblist->size = (dblist->size * 2) + 12;
85 }
86 len = (size_t) sizeof(struct ext2_db_entry) * dblist->size;
87 dblist->count = count;
88 retval = ext2fs_get_mem(len, &dblist->list);
89 if (retval)
90 goto cleanup;
91
92 if (list)
93 memcpy(dblist->list, list, len);
94 else
95 memset(dblist->list, 0, len);
96 if (ret_dblist)
97 *ret_dblist = dblist;
98 else
99 fs->dblist = dblist;
100 return 0;
101cleanup:
102 if (dblist)
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 EXT2_QSORT_TYPE (*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 EXT2_QSORT_TYPE 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/ext2fs/dblist_dir.c b/e2fsprogs/ext2fs/dblist_dir.c
new file mode 100644
index 000000000..f2e17a61d
--- /dev/null
+++ b/e2fsprogs/ext2fs/dblist_dir.c
@@ -0,0 +1,75 @@
1/*
2 * dblist_dir.c --- iterate by directory entry
3 *
4 * Copyright 1997 by Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
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 "ext2fsP.h"
22
23static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
24 void *priv_data);
25
26errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist,
27 int flags,
28 char *block_buf,
29 int (*func)(ext2_ino_t dir,
30 int entry,
31 struct ext2_dir_entry *dirent,
32 int offset,
33 int blocksize,
34 char *buf,
35 void *priv_data),
36 void *priv_data)
37{
38 errcode_t retval;
39 struct dir_context ctx;
40
41 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
42
43 ctx.dir = 0;
44 ctx.flags = flags;
45 if (block_buf)
46 ctx.buf = block_buf;
47 else {
48 retval = ext2fs_get_mem(dblist->fs->blocksize, &ctx.buf);
49 if (retval)
50 return retval;
51 }
52 ctx.func = func;
53 ctx.priv_data = priv_data;
54 ctx.errcode = 0;
55
56 retval = ext2fs_dblist_iterate(dblist, db_dir_proc, &ctx);
57
58 if (!block_buf)
59 ext2fs_free_mem(&ctx.buf);
60 if (retval)
61 return retval;
62 return ctx.errcode;
63}
64
65static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
66 void *priv_data)
67{
68 struct dir_context *ctx;
69
70 ctx = (struct dir_context *) priv_data;
71 ctx->dir = db_info->ino;
72
73 return ext2fs_process_dir_block(fs, &db_info->blk,
74 db_info->blockcnt, 0, 0, priv_data);
75}
diff --git a/e2fsprogs/ext2fs/dir_iterate.c b/e2fsprogs/ext2fs/dir_iterate.c
new file mode 100644
index 000000000..003c0a3bd
--- /dev/null
+++ b/e2fsprogs/ext2fs/dir_iterate.c
@@ -0,0 +1,219 @@
1/*
2 * dir_iterate.c --- ext2fs directory iteration operations
3 *
4 * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#if HAVE_ERRNO_H
18#include <errno.h>
19#endif
20
21#include "ext2_fs.h"
22#include "ext2fsP.h"
23
24/*
25 * This function checks to see whether or not a potential deleted
26 * directory entry looks valid. What we do is check the deleted entry
27 * and each successive entry to make sure that they all look valid and
28 * that the last deleted entry ends at the beginning of the next
29 * undeleted entry. Returns 1 if the deleted entry looks valid, zero
30 * if not valid.
31 */
32static int ext2fs_validate_entry(char *buf, int offset, int final_offset)
33{
34 struct ext2_dir_entry *dirent;
35
36 while (offset < final_offset) {
37 dirent = (struct ext2_dir_entry *)(buf + offset);
38 offset += dirent->rec_len;
39 if ((dirent->rec_len < 8) ||
40 ((dirent->rec_len % 4) != 0) ||
41 (((dirent->name_len & 0xFF)+8) > dirent->rec_len))
42 return 0;
43 }
44 return (offset == final_offset);
45}
46
47errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
48 ext2_ino_t dir,
49 int flags,
50 char *block_buf,
51 int (*func)(ext2_ino_t dir,
52 int entry,
53 struct ext2_dir_entry *dirent,
54 int offset,
55 int blocksize,
56 char *buf,
57 void *priv_data),
58 void *priv_data)
59{
60 struct dir_context ctx;
61 errcode_t retval;
62
63 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
64
65 retval = ext2fs_check_directory(fs, dir);
66 if (retval)
67 return retval;
68
69 ctx.dir = dir;
70 ctx.flags = flags;
71 if (block_buf)
72 ctx.buf = block_buf;
73 else {
74 retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
75 if (retval)
76 return retval;
77 }
78 ctx.func = func;
79 ctx.priv_data = priv_data;
80 ctx.errcode = 0;
81 retval = ext2fs_block_iterate2(fs, dir, 0, 0,
82 ext2fs_process_dir_block, &ctx);
83 if (!block_buf)
84 ext2fs_free_mem(&ctx.buf);
85 if (retval)
86 return retval;
87 return ctx.errcode;
88}
89
90struct xlate {
91 int (*func)(struct ext2_dir_entry *dirent,
92 int offset,
93 int blocksize,
94 char *buf,
95 void *priv_data);
96 void *real_private;
97};
98
99static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
100 int entry EXT2FS_ATTR((unused)),
101 struct ext2_dir_entry *dirent, int offset,
102 int blocksize, char *buf, void *priv_data)
103{
104 struct xlate *xl = (struct xlate *) priv_data;
105
106 return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
107}
108
109extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
110 ext2_ino_t dir,
111 int flags,
112 char *block_buf,
113 int (*func)(struct ext2_dir_entry *dirent,
114 int offset,
115 int blocksize,
116 char *buf,
117 void *priv_data),
118 void *priv_data)
119{
120 struct xlate xl;
121
122 xl.real_private = priv_data;
123 xl.func = func;
124
125 return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
126 xlate_func, &xl);
127}
128
129
130/*
131 * Helper function which is private to this module. Used by
132 * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
133 */
134int ext2fs_process_dir_block(ext2_filsys fs,
135 blk_t *blocknr,
136 e2_blkcnt_t blockcnt,
137 blk_t ref_block EXT2FS_ATTR((unused)),
138 int ref_offset EXT2FS_ATTR((unused)),
139 void *priv_data)
140{
141 struct dir_context *ctx = (struct dir_context *) priv_data;
142 unsigned int offset = 0;
143 unsigned int next_real_entry = 0;
144 int ret = 0;
145 int changed = 0;
146 int do_abort = 0;
147 int entry, size;
148 struct ext2_dir_entry *dirent;
149
150 if (blockcnt < 0)
151 return 0;
152
153 entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
154
155 ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf);
156 if (ctx->errcode)
157 return BLOCK_ABORT;
158
159 while (offset < fs->blocksize) {
160 dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
161 if (((offset + dirent->rec_len) > fs->blocksize) ||
162 (dirent->rec_len < 8) ||
163 ((dirent->rec_len % 4) != 0) ||
164 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
165 ctx->errcode = EXT2_ET_DIR_CORRUPTED;
166 return BLOCK_ABORT;
167 }
168 if (!dirent->inode &&
169 !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
170 goto next;
171
172 ret = (ctx->func)(ctx->dir,
173 (next_real_entry > offset) ?
174 DIRENT_DELETED_FILE : entry,
175 dirent, offset,
176 fs->blocksize, ctx->buf,
177 ctx->priv_data);
178 if (entry < DIRENT_OTHER_FILE)
179 entry++;
180
181 if (ret & DIRENT_CHANGED)
182 changed++;
183 if (ret & DIRENT_ABORT) {
184 do_abort++;
185 break;
186 }
187next:
188 if (next_real_entry == offset)
189 next_real_entry += dirent->rec_len;
190
191 if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
192 size = ((dirent->name_len & 0xFF) + 11) & ~3;
193
194 if (dirent->rec_len != size) {
195 unsigned int final_offset;
196
197 final_offset = offset + dirent->rec_len;
198 offset += size;
199 while (offset < final_offset &&
200 !ext2fs_validate_entry(ctx->buf,
201 offset,
202 final_offset))
203 offset += 4;
204 continue;
205 }
206 }
207 offset += dirent->rec_len;
208 }
209
210 if (changed) {
211 ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf);
212 if (ctx->errcode)
213 return BLOCK_ABORT;
214 }
215 if (do_abort)
216 return BLOCK_ABORT;
217 return 0;
218}
219
diff --git a/e2fsprogs/ext2fs/dirblock.c b/e2fsprogs/ext2fs/dirblock.c
new file mode 100644
index 000000000..ebfc72c5f
--- /dev/null
+++ b/e2fsprogs/ext2fs/dirblock.c
@@ -0,0 +1,130 @@
1/*
2 * dirblock.c --- directory block routines.
3 *
4 * Copyright (C) 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#if HAVE_UNISTD_H
14#include <unistd.h>
15#endif
16#include <string.h>
17#include <time.h>
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
23 void *buf, int flags EXT2FS_ATTR((unused)))
24{
25 errcode_t retval;
26 char *p, *end;
27 struct ext2_dir_entry *dirent;
28 unsigned int name_len, rec_len, do_swap;
29
30
31 retval = io_channel_read_blk(fs->io, block, 1, buf);
32 if (retval)
33 return retval;
34#ifdef EXT2FS_ENABLE_SWAPFS
35 do_swap = (fs->flags & (EXT2_FLAG_SWAP_BYTES|
36 EXT2_FLAG_SWAP_BYTES_READ)) != 0;
37#endif
38 p = (char *) buf;
39 end = (char *) buf + fs->blocksize;
40 while (p < end-8) {
41 dirent = (struct ext2_dir_entry *) p;
42#ifdef EXT2FS_ENABLE_SWAPFS
43 if (do_swap) {
44 dirent->inode = ext2fs_swab32(dirent->inode);
45 dirent->rec_len = ext2fs_swab16(dirent->rec_len);
46 dirent->name_len = ext2fs_swab16(dirent->name_len);
47 }
48#endif
49 name_len = dirent->name_len;
50#ifdef WORDS_BIGENDIAN
51 if (flags & EXT2_DIRBLOCK_V2_STRUCT)
52 dirent->name_len = ext2fs_swab16(dirent->name_len);
53#endif
54 rec_len = dirent->rec_len;
55 if ((rec_len < 8) || (rec_len % 4)) {
56 rec_len = 8;
57 retval = EXT2_ET_DIR_CORRUPTED;
58 }
59 if (((name_len & 0xFF) + 8) > dirent->rec_len)
60 retval = EXT2_ET_DIR_CORRUPTED;
61 p += rec_len;
62 }
63 return retval;
64}
65
66errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
67 void *buf)
68{
69 return ext2fs_read_dir_block2(fs, block, buf, 0);
70}
71
72
73errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
74 void *inbuf, int flags EXT2FS_ATTR((unused)))
75{
76#ifdef EXT2FS_ENABLE_SWAPFS
77 int do_swap = 0;
78 errcode_t retval;
79 char *p, *end;
80 char *buf = 0;
81 struct ext2_dir_entry *dirent;
82
83 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
84 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
85 do_swap = 1;
86
87#ifndef WORDS_BIGENDIAN
88 if (!do_swap)
89 return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
90#endif
91
92 retval = ext2fs_get_mem(fs->blocksize, &buf);
93 if (retval)
94 return retval;
95 memcpy(buf, inbuf, fs->blocksize);
96 p = buf;
97 end = buf + fs->blocksize;
98 while (p < end) {
99 dirent = (struct ext2_dir_entry *) p;
100 if ((dirent->rec_len < 8) ||
101 (dirent->rec_len % 4)) {
102 ext2fs_free_mem(&buf);
103 return (EXT2_ET_DIR_CORRUPTED);
104 }
105 p += dirent->rec_len;
106 if (do_swap) {
107 dirent->inode = ext2fs_swab32(dirent->inode);
108 dirent->rec_len = ext2fs_swab16(dirent->rec_len);
109 dirent->name_len = ext2fs_swab16(dirent->name_len);
110 }
111#ifdef WORDS_BIGENDIAN
112 if (flags & EXT2_DIRBLOCK_V2_STRUCT)
113 dirent->name_len = ext2fs_swab16(dirent->name_len);
114#endif
115 }
116 retval = io_channel_write_blk(fs->io, block, 1, buf);
117 ext2fs_free_mem(&buf);
118 return retval;
119#else
120 return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
121#endif
122}
123
124
125errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
126 void *inbuf)
127{
128 return ext2fs_write_dir_block2(fs, block, inbuf, 0);
129}
130
diff --git a/e2fsprogs/ext2fs/dirhash.c b/e2fsprogs/ext2fs/dirhash.c
new file mode 100644
index 000000000..4d18593f5
--- /dev/null
+++ b/e2fsprogs/ext2fs/dirhash.c
@@ -0,0 +1,233 @@
1/*
2 * dirhash.c -- Calculate the hash of a directory entry
3 *
4 * Copyright (c) 2001 Daniel Phillips
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
17#include "ext2_fs.h"
18#include "ext2fs.h"
19
20/*
21 * Keyed 32-bit hash function using TEA in a Davis-Meyer function
22 * H0 = Key
23 * Hi = E Mi(Hi-1) + Hi-1
24 *
25 * (see Applied Cryptography, 2nd edition, p448).
26 *
27 * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
28 *
29 * This code is made available under the terms of the GPL
30 */
31#define DELTA 0x9E3779B9
32
33static void TEA_transform(__u32 buf[4], __u32 const in[])
34{
35 __u32 sum = 0;
36 __u32 b0 = buf[0], b1 = buf[1];
37 __u32 a = in[0], b = in[1], c = in[2], d = in[3];
38 int n = 16;
39
40 do {
41 sum += DELTA;
42 b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
43 b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
44 } while(--n);
45
46 buf[0] += b0;
47 buf[1] += b1;
48}
49
50/* F, G and H are basic MD4 functions: selection, majority, parity */
51#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
52#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
53#define H(x, y, z) ((x) ^ (y) ^ (z))
54
55/*
56 * The generic round function. The application is so specific that
57 * we don't bother protecting all the arguments with parens, as is generally
58 * good macro practice, in favor of extra legibility.
59 * Rotation is separate from addition to prevent recomputation
60 */
61#define ROUND(f, a, b, c, d, x, s) \
62 (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
63#define K1 0
64#define K2 013240474631UL
65#define K3 015666365641UL
66
67/*
68 * Basic cut-down MD4 transform. Returns only 32 bits of result.
69 */
70static void halfMD4Transform (__u32 buf[4], __u32 const in[])
71{
72 __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
73
74 /* Round 1 */
75 ROUND(F, a, b, c, d, in[0] + K1, 3);
76 ROUND(F, d, a, b, c, in[1] + K1, 7);
77 ROUND(F, c, d, a, b, in[2] + K1, 11);
78 ROUND(F, b, c, d, a, in[3] + K1, 19);
79 ROUND(F, a, b, c, d, in[4] + K1, 3);
80 ROUND(F, d, a, b, c, in[5] + K1, 7);
81 ROUND(F, c, d, a, b, in[6] + K1, 11);
82 ROUND(F, b, c, d, a, in[7] + K1, 19);
83
84 /* Round 2 */
85 ROUND(G, a, b, c, d, in[1] + K2, 3);
86 ROUND(G, d, a, b, c, in[3] + K2, 5);
87 ROUND(G, c, d, a, b, in[5] + K2, 9);
88 ROUND(G, b, c, d, a, in[7] + K2, 13);
89 ROUND(G, a, b, c, d, in[0] + K2, 3);
90 ROUND(G, d, a, b, c, in[2] + K2, 5);
91 ROUND(G, c, d, a, b, in[4] + K2, 9);
92 ROUND(G, b, c, d, a, in[6] + K2, 13);
93
94 /* Round 3 */
95 ROUND(H, a, b, c, d, in[3] + K3, 3);
96 ROUND(H, d, a, b, c, in[7] + K3, 9);
97 ROUND(H, c, d, a, b, in[2] + K3, 11);
98 ROUND(H, b, c, d, a, in[6] + K3, 15);
99 ROUND(H, a, b, c, d, in[1] + K3, 3);
100 ROUND(H, d, a, b, c, in[5] + K3, 9);
101 ROUND(H, c, d, a, b, in[0] + K3, 11);
102 ROUND(H, b, c, d, a, in[4] + K3, 15);
103
104 buf[0] += a;
105 buf[1] += b;
106 buf[2] += c;
107 buf[3] += d;
108}
109
110#undef ROUND
111#undef F
112#undef G
113#undef H
114#undef K1
115#undef K2
116#undef K3
117
118/* The old legacy hash */
119static ext2_dirhash_t dx_hack_hash (const char *name, int len)
120{
121 __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
122 while (len--) {
123 __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
124
125 if (hash & 0x80000000) hash -= 0x7fffffff;
126 hash1 = hash0;
127 hash0 = hash;
128 }
129 return (hash0 << 1);
130}
131
132static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
133{
134 __u32 pad, val;
135 int i;
136
137 pad = (__u32)len | ((__u32)len << 8);
138 pad |= pad << 16;
139
140 val = pad;
141 if (len > num*4)
142 len = num * 4;
143 for (i=0; i < len; i++) {
144 if ((i % 4) == 0)
145 val = pad;
146 val = msg[i] + (val << 8);
147 if ((i % 4) == 3) {
148 *buf++ = val;
149 val = pad;
150 num--;
151 }
152 }
153 if (--num >= 0)
154 *buf++ = val;
155 while (--num >= 0)
156 *buf++ = pad;
157}
158
159/*
160 * Returns the hash of a filename. If len is 0 and name is NULL, then
161 * this function can be used to test whether or not a hash version is
162 * supported.
163 *
164 * The seed is an 4 longword (32 bits) "secret" which can be used to
165 * uniquify a hash. If the seed is all zero's, then some default seed
166 * may be used.
167 *
168 * A particular hash version specifies whether or not the seed is
169 * represented, and whether or not the returned hash is 32 bits or 64
170 * bits. 32 bit hashes will return 0 for the minor hash.
171 */
172errcode_t ext2fs_dirhash(int version, const char *name, int len,
173 const __u32 *seed,
174 ext2_dirhash_t *ret_hash,
175 ext2_dirhash_t *ret_minor_hash)
176{
177 __u32 hash;
178 __u32 minor_hash = 0;
179 const char *p;
180 int i;
181 __u32 in[8], buf[4];
182
183 /* Initialize the default seed for the hash checksum functions */
184 buf[0] = 0x67452301;
185 buf[1] = 0xefcdab89;
186 buf[2] = 0x98badcfe;
187 buf[3] = 0x10325476;
188
189 /* Check to see if the seed is all zero's */
190 if (seed) {
191 for (i=0; i < 4; i++) {
192 if (seed[i])
193 break;
194 }
195 if (i < 4)
196 memcpy(buf, seed, sizeof(buf));
197 }
198
199 switch (version) {
200 case EXT2_HASH_LEGACY:
201 hash = dx_hack_hash(name, len);
202 break;
203 case EXT2_HASH_HALF_MD4:
204 p = name;
205 while (len > 0) {
206 str2hashbuf(p, len, in, 8);
207 halfMD4Transform(buf, in);
208 len -= 32;
209 p += 32;
210 }
211 minor_hash = buf[2];
212 hash = buf[1];
213 break;
214 case EXT2_HASH_TEA:
215 p = name;
216 while (len > 0) {
217 str2hashbuf(p, len, in, 4);
218 TEA_transform(buf, in);
219 len -= 16;
220 p += 16;
221 }
222 hash = buf[0];
223 minor_hash = buf[1];
224 break;
225 default:
226 *ret_hash = 0;
227 return EXT2_ET_DIRHASH_UNSUPP;
228 }
229 *ret_hash = hash & ~1;
230 if (ret_minor_hash)
231 *ret_minor_hash = minor_hash;
232 return 0;
233}
diff --git a/e2fsprogs/ext2fs/dosio.c b/e2fsprogs/ext2fs/dosio.c
new file mode 100644
index 000000000..d695b18ef
--- /dev/null
+++ b/e2fsprogs/ext2fs/dosio.c
@@ -0,0 +1,456 @@
1/*
2 * dosio.c -- Disk I/O module for the ext2fs/DOS library.
3 *
4 * Copyright (c) 1997 by Theodore Ts'o.
5 *
6 * Copyright (c) 1997 Mark Habersack
7 * This file may be distributed under the terms of the GNU Public License.
8 *
9 */
10
11#include <stdio.h>
12#include <bios.h>
13#include <string.h>
14#include <ctype.h>
15#include <io.h>
16#ifdef HAVE_ERRNO_H
17#include <errno.h>
18#endif
19
20#include <ext2fs/ext2_types.h>
21#include "utils.h"
22#include "dosio.h"
23#include "et/com_err.h"
24#include "ext2_err.h"
25#include "ext2fs/io.h"
26
27/*
28 * Some helper macros
29 */
30#define LINUX_EXT2FS 0x83
31#define LINUX_SWAP 0x82
32#define WRITE_ERR(_msg_) write(2, _msg_, strlen(_msg_))
33#define WRITE_ERR_S(_msg_) write(2, _msg_, sizeof(_msg_))
34
35/*
36 * Exported variables
37 */
38unsigned long _dio_error;
39unsigned long _dio_hw_error;
40
41/*
42 * Array of all opened partitions
43 */
44static PARTITION **partitions = NULL;
45static unsigned short npart = 0; /* Number of mapped partitions */
46static PARTITION *active = NULL;
47
48/*
49 * I/O Manager routine prototypes
50 */
51static errcode_t dos_open(const char *dev, int flags, io_channel *channel);
52static errcode_t dos_close(io_channel channel);
53static errcode_t dos_set_blksize(io_channel channel, int blksize);
54static errcode_t dos_read_blk(io_channel channel, unsigned long block,
55 int count, void *buf);
56static errcode_t dos_write_blk(io_channel channel, unsigned long block,
57 int count, const void *buf);
58static errcode_t dos_flush(io_channel channel);
59
60static struct struct_io_manager struct_dos_manager = {
61 EXT2_ET_MAGIC_IO_MANAGER,
62 "DOS I/O Manager",
63 dos_open,
64 dos_close,
65 dos_set_blksize,
66 dos_read_blk,
67 dos_write_blk,
68 dos_flush
69};
70io_manager dos_io_manager = &struct_dos_manager;
71
72/*
73 * Macro taken from unix_io.c
74 */
75/*
76 * For checking structure magic numbers...
77 */
78
79#define EXT2_CHECK_MAGIC(struct, code) \
80 if ((struct)->magic != (code)) return (code)
81
82/*
83 * Calculates a CHS address of a sector from its LBA
84 * offset for the given partition.
85 */
86static void lba2chs(unsigned long lba_addr, CHS *chs, PARTITION *part)
87{
88 unsigned long abss;
89
90 chs->offset = lba_addr & 0x000001FF;
91 abss = (lba_addr >> 9) + part->start;
92 chs->cyl = abss / (part->sects * part->heads);
93 chs->head = (abss / part->sects) % part->heads;
94 chs->sector = (abss % part->sects) + 1;
95}
96
97#ifdef __TURBOC__
98#pragma argsused
99#endif
100/*
101 * Scans the passed partition table looking for *pno partition
102 * that has LINUX_EXT2FS type.
103 *
104 * TODO:
105 * For partition numbers >5 Linux uses DOS extended partitions -
106 * dive into them an return an appropriate entry. Also dive into
107 * extended partitions when scanning for a first Linux/ext2fs.
108 */
109static PTABLE_ENTRY *scan_partition_table(PTABLE_ENTRY *pentry,
110 unsigned short phys,
111 unsigned char *pno)
112{
113 unsigned i;
114
115 if(*pno != 0xFF && *pno >= 5)
116 return NULL; /* We don't support extended partitions for now */
117
118 if(*pno != 0xFF)
119 {
120 if(pentry[*pno].type == LINUX_EXT2FS)
121 return &pentry[*pno];
122 else
123 {
124 if(!pentry[*pno].type)
125 *pno = 0xFE;
126 else if(pentry[*pno].type == LINUX_SWAP)
127 *pno = 0xFD;
128 return NULL;
129 }
130 }
131
132 for(i = 0; i < 4; i++)
133 if(pentry[i].type == LINUX_EXT2FS)
134 {
135 *pno = i;
136 return &pentry[i];
137 }
138
139 return NULL;
140}
141
142/*
143 * Allocate libext2fs structures associated with I/O manager
144 */
145static io_channel alloc_io_channel(PARTITION *part)
146{
147 io_channel ioch;
148
149 ioch = (io_channel)malloc(sizeof(struct struct_io_channel));
150 if (!ioch)
151 return NULL;
152 memset(ioch, 0, sizeof(struct struct_io_channel));
153 ioch->magic = EXT2_ET_MAGIC_IO_CHANNEL;
154 ioch->manager = dos_io_manager;
155 ioch->name = (char *)malloc(strlen(part->dev)+1);
156 if (!ioch->name) {
157 free(ioch);
158 return NULL;
159 }
160 strcpy(ioch->name, part->dev);
161 ioch->private_data = part;
162 ioch->block_size = 1024; /* The smallest ext2fs block size */
163 ioch->read_error = 0;
164 ioch->write_error = 0;
165
166 return ioch;
167}
168
169#ifdef __TURBOC__
170#pragma argsused
171#endif
172/*
173 * Open the 'name' partition, initialize all information structures
174 * we need to keep and create libext2fs I/O manager.
175 */
176static errcode_t dos_open(const char *dev, int flags, io_channel *channel)
177{
178 unsigned char *tmp, sec[512];
179 PARTITION *part;
180 PTABLE_ENTRY *pent;
181 PARTITION **newparts;
182
183 if(!dev)
184 {
185 _dio_error = ERR_BADDEV;
186 return EXT2_ET_BAD_DEVICE_NAME;
187 }
188
189 /*
190 * First check whether the dev name is OK
191 */
192 tmp = (unsigned char*)strrchr(dev, '/');
193 if(!tmp)
194 {
195 _dio_error = ERR_BADDEV;
196 return EXT2_ET_BAD_DEVICE_NAME;
197 }
198 *tmp = 0;
199 if(strcmp(dev, "/dev"))
200 {
201 _dio_error = ERR_BADDEV;
202 return EXT2_ET_BAD_DEVICE_NAME;
203 }
204 *tmp++ = '/';
205
206 /*
207 * Check whether the partition data is already in cache
208 */
209
210 part = (PARTITION*)malloc(sizeof(PARTITION));
211 if (!part)
212 return ENOMEM;
213 {
214 int i = 0;
215
216 for(;i < npart; i++)
217 if(!strcmp(partitions[i]->dev, dev))
218 {
219 /* Found it! Make it the active one */
220 active = partitions[i];
221 *channel = alloc_io_channel(active);
222 if (!*channel)
223 return ENOMEM;
224 return 0;
225 }
226 }
227
228 /*
229 * Drive number & optionally partn number
230 */
231 switch(tmp[0])
232 {
233 case 'h':
234 case 's':
235 part->phys = 0x80;
236 part->phys += toupper(tmp[2]) - 'A';
237 /*
238 * Do we have the partition number?
239 */
240 if(tmp[3])
241 part->pno = isdigit((int)tmp[3]) ? tmp[3] - '0' - 1: 0;
242 else
243 part->pno = 0xFF;
244 break;
245
246 case 'f':
247 if(tmp[2])
248 part->phys = isdigit((int)tmp[2]) ? tmp[2] - '0' : 0;
249 else
250 part->phys = 0x00; /* We'll assume /dev/fd0 */
251 break;
252
253 default:
254 _dio_error = ERR_BADDEV;
255 return ENODEV;
256 }
257
258 if(part->phys < 0x80)
259 {
260 /* We don't support floppies for now */
261 _dio_error = ERR_NOTSUPP;
262 return EINVAL;
263 }
264
265 part->dev = strdup(dev);
266
267 /*
268 * Get drive's geometry
269 */
270 _dio_hw_error = biosdisk(DISK_GET_GEOMETRY,
271 part->phys,
272 0, /* head */
273 0, /* cylinder */
274 1, /* sector */
275 1, /* just one sector */
276 sec);
277
278 if(!HW_OK())
279 {
280 _dio_error = ERR_HARDWARE;
281 if (part)
282 free(part);
283 return EFAULT;
284 }
285
286 /*
287 * Calculate the geometry
288 */
289 part->cyls = (unsigned short)(((sec[0] >> 6) << 8) + sec[1] + 1);
290 part->heads = sec[3] + 1;
291 part->sects = sec[0] & 0x3F;
292
293 /*
294 * Now that we know all we need, let's look for the partition
295 */
296 _dio_hw_error = biosdisk(DISK_READ, part->phys, 0, 0, 1, 1, sec);
297
298 if(!HW_OK())
299 {
300 _dio_error = ERR_HARDWARE;
301 if (part)
302 free(part);
303 return EFAULT;
304 }
305
306 pent = (PTABLE_ENTRY*)&sec[0x1BE];
307 pent = scan_partition_table(pent, part->phys, &part->pno);
308
309 if(!pent)
310 {
311 _dio_error = part->pno == 0xFE ? ERR_EMPTYPART :
312 part->pno == 0xFD ? ERR_LINUXSWAP : ERR_NOTEXT2FS;
313 if (part)
314 free(part);
315 return ENODEV;
316 }
317
318 /*
319 * Calculate the remaining figures
320 */
321 {
322 unsigned long fsec, fhead, fcyl;
323
324 fsec = (unsigned long)(pent->start_sec & 0x3F);
325 fhead = (unsigned long)pent->start_head;
326 fcyl = ((pent->start_sec >> 6) << 8) + pent->start_cyl;
327 part->start = fsec + fhead * part->sects + fcyl *
328 (part->heads * part->sects) - 1;
329 part->len = pent->size;
330 }
331
332 /*
333 * Add the partition to the table
334 */
335 newparts = (PARTITION**)realloc(partitions, sizeof(PARTITION) * npart);
336 if (!newparts) {
337 free(part);
338 return ENOMEM;
339 }
340 partitions = newparts;
341 partitions[npart++] = active = part;
342
343 /*
344 * Now alloc all libe2fs structures
345 */
346 *channel = alloc_io_channel(active);
347 if (!*channel)
348 return ENOMEM;
349
350 return 0;
351}
352
353static errcode_t dos_close(io_channel channel)
354{
355 if (channel->name)
356 free(channel->name);
357 if (channel)
358 free(channel);
359
360 return 0;
361}
362
363static errcode_t dos_set_blksize(io_channel channel, int blksize)
364{
365 channel->block_size = blksize;
366
367 return 0;
368}
369
370static errcode_t dos_read_blk(io_channel channel, unsigned long block,
371 int count, void *buf)
372{
373 PARTITION *part;
374 size_t size;
375 ext2_loff_t loc;
376 CHS chs;
377
378 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
379 part = (PARTITION*)channel->private_data;
380
381 size = (size_t)((count < 0) ? -count : count * channel->block_size);
382 loc = (ext2_loff_t) block * channel->block_size;
383
384 lba2chs(loc, &chs, part);
385 /*
386 * Potential bug here:
387 * If DJGPP is used then reads of >18 sectors will fail!
388 * Have to rewrite biosdisk.
389 */
390 _dio_hw_error = biosdisk(DISK_READ,
391 part->phys,
392 chs.head,
393 chs.cyl,
394 chs.sector,
395 size < 512 ? 1 : size/512,
396 buf);
397
398 if(!HW_OK())
399 {
400 _dio_error = ERR_HARDWARE;
401 return EFAULT;
402 }
403
404 return 0;
405}
406
407static errcode_t dos_write_blk(io_channel channel, unsigned long block,
408 int count, const void *buf)
409{
410 PARTITION *part;
411 size_t size;
412 ext2_loff_t loc;
413 CHS chs;
414
415 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
416 part = (PARTITION*)channel->private_data;
417
418 if(count == 1)
419 size = (size_t)channel->block_size;
420 else
421 {
422 if (count < 0)
423 size = (size_t)-count;
424 else
425 size = (size_t)(count * channel->block_size);
426 }
427
428 loc = (ext2_loff_t)block * channel->block_size;
429 lba2chs(loc, &chs, part);
430 _dio_hw_error = biosdisk(DISK_WRITE,
431 part->phys,
432 chs.head,
433 chs.cyl,
434 chs.sector,
435 size < 512 ? 1 : size/512,
436 (void*)buf);
437
438 if(!HW_OK())
439 {
440 _dio_error = ERR_HARDWARE;
441 return EFAULT;
442 }
443
444 return 0;
445}
446
447#ifdef __TURBOC__
448#pragma argsused
449#endif
450static errcode_t dos_flush(io_channel channel)
451{
452 /*
453 * No buffers, no flush...
454 */
455 return 0;
456}
diff --git a/e2fsprogs/ext2fs/dosio.h b/e2fsprogs/ext2fs/dosio.h
new file mode 100644
index 000000000..a0d652d5b
--- /dev/null
+++ b/e2fsprogs/ext2fs/dosio.h
@@ -0,0 +1,153 @@
1/*
2 * v1.0
3 *
4 * Disk I/O include file for the ext2fs/DOS library.
5 *
6 * Copyright (c) 1997 Mark Habersack
7 * This file may be distributed under the terms of the GNU Public License.
8 *
9 */
10#ifndef __diskio_h
11#define __diskio_h
12#ifdef __TURBOC__
13#ifndef __LARGE__
14# error "ext2fs/DOS library requires LARGE model!"
15#endif
16#endif
17
18#ifdef __TURBOC__
19#include "msdos.h"
20#endif
21
22/*
23 * A helper structure used in LBA => CHS conversion
24 */
25typedef struct
26{
27 unsigned short cyl; /* Cylinder (or track) */
28 unsigned short head;
29 unsigned short sector;
30 unsigned short offset; /* Offset of byte within the sector */
31} CHS;
32
33/*
34 * All partition data we need is here
35 */
36typedef struct
37{
38 char *dev; /* _Linux_ device name (like "/dev/hda1") */
39 unsigned char phys; /* Physical DOS drive number */
40 unsigned long start; /* LBA address of partition start */
41 unsigned long len; /* length of partition in sectors */
42 unsigned char pno; /* Partition number (read from *dev) */
43
44 /* This partition's drive geometry */
45 unsigned short cyls;
46 unsigned short heads;
47 unsigned short sects;
48} PARTITION;
49
50/*
51 * PC partition table entry format
52 */
53#ifdef __DJGPP__
54#pragma pack(1)
55#endif
56typedef struct
57{
58 unsigned char active;
59 unsigned char start_head;
60 unsigned char start_sec;
61 unsigned char start_cyl;
62 unsigned char type;
63 unsigned char end_head;
64 unsigned char end_sec;
65 unsigned char end_cyl;
66 unsigned long first_sec_rel;
67 unsigned long size;
68} PTABLE_ENTRY;
69#ifdef __DJGPP__
70#pragma pack()
71#endif
72
73/*
74 * INT 0x13 operation codes
75 */
76#define DISK_READ 0x02
77#define DISK_WRITE 0x03
78#define DISK_GET_GEOMETRY 0x08
79#define DISK_READY 0x10
80
81/*
82 * Errors to put in _dio_error
83 */
84#define ERR_BADDEV 0x00000001L
85#define ERR_HARDWARE 0x00000002L
86#define ERR_NOTSUPP 0x00000003L
87#define ERR_NOTEXT2FS 0x00000004L
88#define ERR_EMPTYPART 0x00000005L
89#define ERR_LINUXSWAP 0x00000006L
90
91/*
92 * Functions in diskio.c
93 */
94
95/*
96 * Variable contains last module's error
97 */
98extern unsigned long _dio_error;
99
100/*
101 * This one contains last hardware error (if _dio_error == ERR_HARDWARE)
102 */
103extern unsigned long _dio_hw_error;
104
105/*
106 * Macros to check for disk hardware errors
107 */
108#define HW_OK() ((unsigned char)_dio_hw_error == 0x00)
109#define HW_BAD_CMD() ((unsigned char)_dio_hw_error == 0x01)
110#define HW_NO_ADDR_MARK() ((unsigned char)_dio_hw_error == 0x02)
111#define HW_WRITE_PROT() ((unsigned char)_dio_hw_error == 0x03)
112#define HW_NO_SECTOR() ((unsigned char)_dio_hw_error == 0x04)
113#define HW_RESET_FAIL() ((unsigned char)_dio_hw_error == 0x05)
114#define HW_DISK_CHANGED() ((unsigned char)_dio_hw_error == 0x06)
115#define HW_DRIVE_FAIL() ((unsigned char)_dio_hw_error == 0x07)
116#define HW_DMA_OVERRUN() ((unsigned char)_dio_hw_error == 0x08)
117#define HW_DMA_BOUNDARY() ((unsigned char)_dio_hw_error == 0x09)
118#define HW_BAD_SECTOR() ((unsigned char)_dio_hw_error == 0x0A)
119#define HW_BAD_TRACK() ((unsigned char)_dio_hw_error == 0x0B)
120#define HW_UNSUPP_TRACK() ((unsigned char)_dio_hw_error == 0x0C)
121#define HW_BAD_CRC_ECC() ((unsigned char)_dio_hw_error == 0x10)
122#define HW_CRC_ECC_CORR() ((unsigned char)_dio_hw_error == 0x11)
123#define HW_CONTR_FAIL() ((unsigned char)_dio_hw_error == 0x20)
124#define HW_SEEK_FAIL() ((unsigned char)_dio_hw_error == 0x40)
125#define HW_ATTACH_FAIL() ((unsigned char)_dio_hw_error == 0x80)
126#define HW_DRIVE_NREADY() ((unsigned char)_dio_hw_error == 0xAA)
127#define HW_UNDEF_ERROR() ((unsigned char)_dio_hw_error == 0xBB)
128#define HW_WRITE_FAULT() ((unsigned char)_dio_hw_error == 0xCC)
129#define HW_STATUS_ERROR() ((unsigned char)_dio_hw_error == 0xE0)
130#define HW_SENSE_FAIL() ((unsigned char)_dio_hw_error == 0xFF)
131
132
133/*
134 * Open the specified partition.
135 * String 'dev' must have a format:
136 *
137 * /dev/{sd|hd|fd}[X]
138 *
139 * where,
140 *
141 * only one of the option in curly braces can be used and X is an optional
142 * partition number for the given device. If X is not specified, function
143 * scans the drive's partition table in search for the first Linux ext2fs
144 * partition (signature 0x83). Along the way it dives into every extended
145 * partition encountered.
146 * Scan ends if either (a) there are no more used partition entries, or
147 * (b) there is no Xth partition.
148 *
149 * Routine returns 0 on success and !=0 otherwise.
150 */
151int open_partition(char *dev);
152
153#endif /* __diskio_h */
diff --git a/e2fsprogs/ext2fs/dupfs.c b/e2fsprogs/ext2fs/dupfs.c
new file mode 100644
index 000000000..f8919c222
--- /dev/null
+++ b/e2fsprogs/ext2fs/dupfs.c
@@ -0,0 +1,96 @@
1/*
2 * dupfs.c --- duplicate a ext2 filesystem handle
3 *
4 * Copyright (C) 1997, 1998, 2001, 2003, 2005 by Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#if HAVE_UNISTD_H
14#include <unistd.h>
15#endif
16#include <time.h>
17#include <string.h>
18
19#include "ext2_fs.h"
20#include "ext2fsP.h"
21
22errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest)
23{
24 ext2_filsys fs;
25 errcode_t retval;
26
27 EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS);
28
29 retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
30 if (retval)
31 return retval;
32
33 *fs = *src;
34 fs->device_name = 0;
35 fs->super = 0;
36 fs->orig_super = 0;
37 fs->group_desc = 0;
38 fs->inode_map = 0;
39 fs->block_map = 0;
40 fs->badblocks = 0;
41 fs->dblist = 0;
42
43 io_channel_bumpcount(fs->io);
44 if (fs->icache)
45 fs->icache->refcount++;
46
47 retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name);
48 if (retval)
49 goto errout;
50 strcpy(fs->device_name, src->device_name);
51
52 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
53 if (retval)
54 goto errout;
55 memcpy(fs->super, src->super, SUPERBLOCK_SIZE);
56
57 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
58 if (retval)
59 goto errout;
60 memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE);
61
62 retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
63 &fs->group_desc);
64 if (retval)
65 goto errout;
66 memcpy(fs->group_desc, src->group_desc,
67 (size_t) fs->desc_blocks * fs->blocksize);
68
69 if (src->inode_map) {
70 retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map);
71 if (retval)
72 goto errout;
73 }
74 if (src->block_map) {
75 retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map);
76 if (retval)
77 goto errout;
78 }
79 if (src->badblocks) {
80 retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks);
81 if (retval)
82 goto errout;
83 }
84 if (src->dblist) {
85 retval = ext2fs_copy_dblist(src->dblist, &fs->dblist);
86 if (retval)
87 goto errout;
88 }
89 *dest = fs;
90 return 0;
91errout:
92 ext2fs_free(fs);
93 return retval;
94
95}
96
diff --git a/e2fsprogs/ext2fs/e2image.h b/e2fsprogs/ext2fs/e2image.h
new file mode 100644
index 000000000..e12b7d69b
--- /dev/null
+++ b/e2fsprogs/ext2fs/e2image.h
@@ -0,0 +1,51 @@
1/*
2 * e2image.h --- header file describing the ext2 image format
3 *
4 * Copyright (C) 2000 Theodore Ts'o.
5 *
6 * Note: this uses the POSIX IO interfaces, unlike most of the other
7 * functions in this library. So sue me.
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
16struct ext2_image_hdr {
17 __u32 magic_number; /* This must be EXT2_ET_MAGIC_E2IMAGE */
18 char magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */
19 char fs_hostname[64];/* Hostname of machine of image */
20 char fs_netaddr[32]; /* Network address */
21 __u32 fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */
22 __u32 fs_device; /* Device number of image */
23 char fs_device_name[64]; /* Device name */
24 char fs_uuid[16]; /* UUID of filesystem */
25 __u32 fs_blocksize; /* Block size of the filesystem */
26 __u32 fs_reserved[8];
27
28 __u32 image_device; /* Device number of image file */
29 __u32 image_inode; /* Inode number of image file */
30 __u32 image_time; /* Time of image creation */
31 __u32 image_reserved[8];
32
33 __u32 offset_super; /* Byte offset of the sb and descriptors */
34 __u32 offset_inode; /* Byte offset of the inode table */
35 __u32 offset_inodemap; /* Byte offset of the inode bitmaps */
36 __u32 offset_blockmap; /* Byte offset of the inode bitmaps */
37 __u32 offset_reserved[8];
38};
39
40
41
42
43
44
45
46
47
48
49
50
51
diff --git a/e2fsprogs/ext2fs/expanddir.c b/e2fsprogs/ext2fs/expanddir.c
new file mode 100644
index 000000000..10a5149cf
--- /dev/null
+++ b/e2fsprogs/ext2fs/expanddir.c
@@ -0,0 +1,126 @@
1/*
2 * expand.c --- expand an ext2fs directory
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21struct expand_dir_struct {
22 int done;
23 int newblocks;
24 errcode_t err;
25};
26
27static int expand_dir_proc(ext2_filsys fs,
28 blk_t *blocknr,
29 e2_blkcnt_t blockcnt,
30 blk_t ref_block EXT2FS_ATTR((unused)),
31 int ref_offset EXT2FS_ATTR((unused)),
32 void *priv_data)
33{
34 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
35 blk_t new_blk;
36 static blk_t last_blk = 0;
37 char *block;
38 errcode_t retval;
39
40 if (*blocknr) {
41 last_blk = *blocknr;
42 return 0;
43 }
44 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
45 if (retval) {
46 es->err = retval;
47 return BLOCK_ABORT;
48 }
49 if (blockcnt > 0) {
50 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
51 if (retval) {
52 es->err = retval;
53 return BLOCK_ABORT;
54 }
55 es->done = 1;
56 retval = ext2fs_write_dir_block(fs, new_blk, block);
57 } else {
58 retval = ext2fs_get_mem(fs->blocksize, &block);
59 if (retval) {
60 es->err = retval;
61 return BLOCK_ABORT;
62 }
63 memset(block, 0, fs->blocksize);
64 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
65 }
66 if (retval) {
67 es->err = retval;
68 return BLOCK_ABORT;
69 }
70 ext2fs_free_mem(&block);
71 *blocknr = new_blk;
72 ext2fs_block_alloc_stats(fs, new_blk, +1);
73 es->newblocks++;
74
75 if (es->done)
76 return (BLOCK_CHANGED | BLOCK_ABORT);
77 else
78 return BLOCK_CHANGED;
79}
80
81errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
82{
83 errcode_t retval;
84 struct expand_dir_struct es;
85 struct ext2_inode inode;
86
87 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
88
89 if (!(fs->flags & EXT2_FLAG_RW))
90 return EXT2_ET_RO_FILSYS;
91
92 if (!fs->block_map)
93 return EXT2_ET_NO_BLOCK_BITMAP;
94
95 retval = ext2fs_check_directory(fs, dir);
96 if (retval)
97 return retval;
98
99 es.done = 0;
100 es.err = 0;
101 es.newblocks = 0;
102
103 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
104 0, expand_dir_proc, &es);
105
106 if (es.err)
107 return es.err;
108 if (!es.done)
109 return EXT2_ET_EXPAND_DIR_ERR;
110
111 /*
112 * Update the size and block count fields in the inode.
113 */
114 retval = ext2fs_read_inode(fs, dir, &inode);
115 if (retval)
116 return retval;
117
118 inode.i_size += fs->blocksize;
119 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
120
121 retval = ext2fs_write_inode(fs, dir, &inode);
122 if (retval)
123 return retval;
124
125 return 0;
126}
diff --git a/e2fsprogs/ext2fs/ext2_err.h b/e2fsprogs/ext2fs/ext2_err.h
new file mode 100644
index 000000000..57b44e164
--- /dev/null
+++ b/e2fsprogs/ext2fs/ext2_err.h
@@ -0,0 +1,117 @@
1/*
2 * ext2_err.h:
3 * This file is automatically generated; please do not edit it.
4 */
5
6#include <et/com_err.h>
7
8#define EXT2_ET_BASE (2133571328L)
9#define EXT2_ET_MAGIC_EXT2FS_FILSYS (2133571329L)
10#define EXT2_ET_MAGIC_BADBLOCKS_LIST (2133571330L)
11#define EXT2_ET_MAGIC_BADBLOCKS_ITERATE (2133571331L)
12#define EXT2_ET_MAGIC_INODE_SCAN (2133571332L)
13#define EXT2_ET_MAGIC_IO_CHANNEL (2133571333L)
14#define EXT2_ET_MAGIC_UNIX_IO_CHANNEL (2133571334L)
15#define EXT2_ET_MAGIC_IO_MANAGER (2133571335L)
16#define EXT2_ET_MAGIC_BLOCK_BITMAP (2133571336L)
17#define EXT2_ET_MAGIC_INODE_BITMAP (2133571337L)
18#define EXT2_ET_MAGIC_GENERIC_BITMAP (2133571338L)
19#define EXT2_ET_MAGIC_TEST_IO_CHANNEL (2133571339L)
20#define EXT2_ET_MAGIC_DBLIST (2133571340L)
21#define EXT2_ET_MAGIC_ICOUNT (2133571341L)
22#define EXT2_ET_MAGIC_PQ_IO_CHANNEL (2133571342L)
23#define EXT2_ET_MAGIC_EXT2_FILE (2133571343L)
24#define EXT2_ET_MAGIC_E2IMAGE (2133571344L)
25#define EXT2_ET_MAGIC_INODE_IO_CHANNEL (2133571345L)
26#define EXT2_ET_MAGIC_RESERVED_9 (2133571346L)
27#define EXT2_ET_BAD_MAGIC (2133571347L)
28#define EXT2_ET_REV_TOO_HIGH (2133571348L)
29#define EXT2_ET_RO_FILSYS (2133571349L)
30#define EXT2_ET_GDESC_READ (2133571350L)
31#define EXT2_ET_GDESC_WRITE (2133571351L)
32#define EXT2_ET_GDESC_BAD_BLOCK_MAP (2133571352L)
33#define EXT2_ET_GDESC_BAD_INODE_MAP (2133571353L)
34#define EXT2_ET_GDESC_BAD_INODE_TABLE (2133571354L)
35#define EXT2_ET_INODE_BITMAP_WRITE (2133571355L)
36#define EXT2_ET_INODE_BITMAP_READ (2133571356L)
37#define EXT2_ET_BLOCK_BITMAP_WRITE (2133571357L)
38#define EXT2_ET_BLOCK_BITMAP_READ (2133571358L)
39#define EXT2_ET_INODE_TABLE_WRITE (2133571359L)
40#define EXT2_ET_INODE_TABLE_READ (2133571360L)
41#define EXT2_ET_NEXT_INODE_READ (2133571361L)
42#define EXT2_ET_UNEXPECTED_BLOCK_SIZE (2133571362L)
43#define EXT2_ET_DIR_CORRUPTED (2133571363L)
44#define EXT2_ET_SHORT_READ (2133571364L)
45#define EXT2_ET_SHORT_WRITE (2133571365L)
46#define EXT2_ET_DIR_NO_SPACE (2133571366L)
47#define EXT2_ET_NO_INODE_BITMAP (2133571367L)
48#define EXT2_ET_NO_BLOCK_BITMAP (2133571368L)
49#define EXT2_ET_BAD_INODE_NUM (2133571369L)
50#define EXT2_ET_BAD_BLOCK_NUM (2133571370L)
51#define EXT2_ET_EXPAND_DIR_ERR (2133571371L)
52#define EXT2_ET_TOOSMALL (2133571372L)
53#define EXT2_ET_BAD_BLOCK_MARK (2133571373L)
54#define EXT2_ET_BAD_BLOCK_UNMARK (2133571374L)
55#define EXT2_ET_BAD_BLOCK_TEST (2133571375L)
56#define EXT2_ET_BAD_INODE_MARK (2133571376L)
57#define EXT2_ET_BAD_INODE_UNMARK (2133571377L)
58#define EXT2_ET_BAD_INODE_TEST (2133571378L)
59#define EXT2_ET_FUDGE_BLOCK_BITMAP_END (2133571379L)
60#define EXT2_ET_FUDGE_INODE_BITMAP_END (2133571380L)
61#define EXT2_ET_BAD_IND_BLOCK (2133571381L)
62#define EXT2_ET_BAD_DIND_BLOCK (2133571382L)
63#define EXT2_ET_BAD_TIND_BLOCK (2133571383L)
64#define EXT2_ET_NEQ_BLOCK_BITMAP (2133571384L)
65#define EXT2_ET_NEQ_INODE_BITMAP (2133571385L)
66#define EXT2_ET_BAD_DEVICE_NAME (2133571386L)
67#define EXT2_ET_MISSING_INODE_TABLE (2133571387L)
68#define EXT2_ET_CORRUPT_SUPERBLOCK (2133571388L)
69#define EXT2_ET_BAD_GENERIC_MARK (2133571389L)
70#define EXT2_ET_BAD_GENERIC_UNMARK (2133571390L)
71#define EXT2_ET_BAD_GENERIC_TEST (2133571391L)
72#define EXT2_ET_SYMLINK_LOOP (2133571392L)
73#define EXT2_ET_CALLBACK_NOTHANDLED (2133571393L)
74#define EXT2_ET_BAD_BLOCK_IN_INODE_TABLE (2133571394L)
75#define EXT2_ET_UNSUPP_FEATURE (2133571395L)
76#define EXT2_ET_RO_UNSUPP_FEATURE (2133571396L)
77#define EXT2_ET_LLSEEK_FAILED (2133571397L)
78#define EXT2_ET_NO_MEMORY (2133571398L)
79#define EXT2_ET_INVALID_ARGUMENT (2133571399L)
80#define EXT2_ET_BLOCK_ALLOC_FAIL (2133571400L)
81#define EXT2_ET_INODE_ALLOC_FAIL (2133571401L)
82#define EXT2_ET_NO_DIRECTORY (2133571402L)
83#define EXT2_ET_TOO_MANY_REFS (2133571403L)
84#define EXT2_ET_FILE_NOT_FOUND (2133571404L)
85#define EXT2_ET_FILE_RO (2133571405L)
86#define EXT2_ET_DB_NOT_FOUND (2133571406L)
87#define EXT2_ET_DIR_EXISTS (2133571407L)
88#define EXT2_ET_UNIMPLEMENTED (2133571408L)
89#define EXT2_ET_CANCEL_REQUESTED (2133571409L)
90#define EXT2_ET_FILE_TOO_BIG (2133571410L)
91#define EXT2_ET_JOURNAL_NOT_BLOCK (2133571411L)
92#define EXT2_ET_NO_JOURNAL_SB (2133571412L)
93#define EXT2_ET_JOURNAL_TOO_SMALL (2133571413L)
94#define EXT2_ET_JOURNAL_UNSUPP_VERSION (2133571414L)
95#define EXT2_ET_LOAD_EXT_JOURNAL (2133571415L)
96#define EXT2_ET_NO_JOURNAL (2133571416L)
97#define EXT2_ET_DIRHASH_UNSUPP (2133571417L)
98#define EXT2_ET_BAD_EA_BLOCK_NUM (2133571418L)
99#define EXT2_ET_TOO_MANY_INODES (2133571419L)
100#define EXT2_ET_NOT_IMAGE_FILE (2133571420L)
101#define EXT2_ET_RES_GDT_BLOCKS (2133571421L)
102#define EXT2_ET_RESIZE_INODE_CORRUPT (2133571422L)
103#define EXT2_ET_SET_BMAP_NO_IND (2133571423L)
104
105#if 0
106extern const struct error_table et_ext2_error_table;
107extern void initialize_ext2_error_table(void);
108
109/* For compatibility with Heimdal */
110extern void initialize_ext2_error_table_r(struct et_list **list);
111
112#define ERROR_TABLE_BASE_ext2 (2133571328L)
113
114/* for compatibility with older versions... */
115#define init_ext2_err_tbl initialize_ext2_error_table
116#define ext2_err_base ERROR_TABLE_BASE_ext2
117#endif
diff --git a/e2fsprogs/ext2fs/ext2_ext_attr.h b/e2fsprogs/ext2fs/ext2_ext_attr.h
new file mode 100644
index 000000000..23444c508
--- /dev/null
+++ b/e2fsprogs/ext2fs/ext2_ext_attr.h
@@ -0,0 +1,69 @@
1/*
2 File: linux/ext2_ext_attr.h
3
4 On-disk format of extended attributes for the ext2 filesystem.
5
6 (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org>
7*/
8
9/* Magic value in attribute blocks */
10#define EXT2_EXT_ATTR_MAGIC_v1 0xEA010000
11#define EXT2_EXT_ATTR_MAGIC 0xEA020000
12
13/* Maximum number of references to one attribute block */
14#define EXT2_EXT_ATTR_REFCOUNT_MAX 1024
15
16struct ext2_ext_attr_header {
17 __u32 h_magic; /* magic number for identification */
18 __u32 h_refcount; /* reference count */
19 __u32 h_blocks; /* number of disk blocks used */
20 __u32 h_hash; /* hash value of all attributes */
21 __u32 h_reserved[4]; /* zero right now */
22};
23
24struct ext2_ext_attr_entry {
25 __u8 e_name_len; /* length of name */
26 __u8 e_name_index; /* attribute name index */
27 __u16 e_value_offs; /* offset in disk block of value */
28 __u32 e_value_block; /* disk block attribute is stored on (n/i) */
29 __u32 e_value_size; /* size of attribute value */
30 __u32 e_hash; /* hash value of name and value */
31#if 0
32 char e_name[0]; /* attribute name */
33#endif
34};
35
36#define EXT2_EXT_ATTR_PAD_BITS 2
37#define EXT2_EXT_ATTR_PAD (1<<EXT2_EXT_ATTR_PAD_BITS)
38#define EXT2_EXT_ATTR_ROUND (EXT2_EXT_ATTR_PAD-1)
39#define EXT2_EXT_ATTR_LEN(name_len) \
40 (((name_len) + EXT2_EXT_ATTR_ROUND + \
41 sizeof(struct ext2_ext_attr_entry)) & ~EXT2_EXT_ATTR_ROUND)
42#define EXT2_EXT_ATTR_NEXT(entry) \
43 ( (struct ext2_ext_attr_entry *)( \
44 (char *)(entry) + EXT2_EXT_ATTR_LEN((entry)->e_name_len)) )
45#define EXT2_EXT_ATTR_SIZE(size) \
46 (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
47#define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL)
48#define EXT2_EXT_ATTR_NAME(entry) \
49 (((char *) (entry)) + sizeof(struct ext2_ext_attr_entry))
50#define EXT2_XATTR_LEN(name_len) \
51 (((name_len) + EXT2_EXT_ATTR_ROUND + \
52 sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND)
53#define EXT2_XATTR_SIZE(size) \
54 (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
55
56#ifdef __KERNEL__
57# ifdef CONFIG_EXT2_FS_EXT_ATTR
58extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int);
59extern int ext2_set_ext_attr(struct inode *, const char *, char *, size_t, int);
60extern void ext2_ext_attr_free_inode(struct inode *inode);
61extern void ext2_ext_attr_put_super(struct super_block *sb);
62extern int ext2_ext_attr_init(void);
63extern void ext2_ext_attr_done(void);
64# else
65# define ext2_get_ext_attr NULL
66# define ext2_set_ext_attr NULL
67# endif
68#endif /* __KERNEL__ */
69
diff --git a/e2fsprogs/ext2fs/ext2_fs.h b/e2fsprogs/ext2fs/ext2_fs.h
new file mode 100644
index 000000000..ff615c4bd
--- /dev/null
+++ b/e2fsprogs/ext2fs/ext2_fs.h
@@ -0,0 +1,644 @@
1/*
2 * linux/include/linux/ext2_fs.h
3 *
4 * Copyright (C) 1992, 1993, 1994, 1995
5 * Remy Card (card@masi.ibp.fr)
6 * Laboratoire MASI - Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * from
10 *
11 * linux/include/linux/minix_fs.h
12 *
13 * Copyright (C) 1991, 1992 Linus Torvalds
14 */
15
16#ifndef _LINUX_EXT2_FS_H
17#define _LINUX_EXT2_FS_H
18
19#include <ext2fs/ext2_types.h> /* Changed from linux/types.h */
20
21/*
22 * The second extended filesystem constants/structures
23 */
24
25/*
26 * Define EXT2FS_DEBUG to produce debug messages
27 */
28#undef EXT2FS_DEBUG
29
30/*
31 * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
32 */
33#define EXT2_PREALLOCATE
34#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
35
36/*
37 * The second extended file system version
38 */
39#define EXT2FS_DATE "95/08/09"
40#define EXT2FS_VERSION "0.5b"
41
42/*
43 * Special inode numbers
44 */
45#define EXT2_BAD_INO 1 /* Bad blocks inode */
46#define EXT2_ROOT_INO 2 /* Root inode */
47#define EXT2_ACL_IDX_INO 3 /* ACL inode */
48#define EXT2_ACL_DATA_INO 4 /* ACL inode */
49#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
50#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
51#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */
52#define EXT2_JOURNAL_INO 8 /* Journal inode */
53
54/* First non-reserved inode for old ext2 filesystems */
55#define EXT2_GOOD_OLD_FIRST_INO 11
56
57/*
58 * The second extended file system magic number
59 */
60#define EXT2_SUPER_MAGIC 0xEF53
61
62#ifdef __KERNEL__
63#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
64#else
65/* Assume that user mode programs are passing in an ext2fs superblock, not
66 * a kernel struct super_block. This will allow us to call the feature-test
67 * macros from user land. */
68#define EXT2_SB(sb) (sb)
69#endif
70
71/*
72 * Maximal count of links to a file
73 */
74#define EXT2_LINK_MAX 32000
75
76/*
77 * Macro-instructions used to manage several block sizes
78 */
79#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
80#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */
81#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE)
82#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE)
83#ifdef __KERNEL__
84#define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
85#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
86#define EXT2_ADDR_PER_BLOCK_BITS(s) (EXT2_SB(s)->addr_per_block_bits)
87#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size)
88#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino)
89#else
90#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
91#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
92#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
93 EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
94#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
95 EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
96#endif
97#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(__u32))
98
99/*
100 * Macro-instructions used to manage fragments
101 */
102#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE
103#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE
104#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE
105#ifdef __KERNEL__
106# define EXT2_FRAG_SIZE(s) (EXT2_SB(s)->s_frag_size)
107# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_SB(s)->s_frags_per_block)
108#else
109# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
110# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
111#endif
112
113/*
114 * ACL structures
115 */
116struct ext2_acl_header /* Header of Access Control Lists */
117{
118 __u32 aclh_size;
119 __u32 aclh_file_count;
120 __u32 aclh_acle_count;
121 __u32 aclh_first_acle;
122};
123
124struct ext2_acl_entry /* Access Control List Entry */
125{
126 __u32 acle_size;
127 __u16 acle_perms; /* Access permissions */
128 __u16 acle_type; /* Type of entry */
129 __u16 acle_tag; /* User or group identity */
130 __u16 acle_pad1;
131 __u32 acle_next; /* Pointer on next entry for the */
132 /* same inode or on next free entry */
133};
134
135/*
136 * Structure of a blocks group descriptor
137 */
138struct ext2_group_desc
139{
140 __u32 bg_block_bitmap; /* Blocks bitmap block */
141 __u32 bg_inode_bitmap; /* Inodes bitmap block */
142 __u32 bg_inode_table; /* Inodes table block */
143 __u16 bg_free_blocks_count; /* Free blocks count */
144 __u16 bg_free_inodes_count; /* Free inodes count */
145 __u16 bg_used_dirs_count; /* Directories count */
146 __u16 bg_pad;
147 __u32 bg_reserved[3];
148};
149
150/*
151 * Data structures used by the directory indexing feature
152 *
153 * Note: all of the multibyte integer fields are little endian.
154 */
155
156/*
157 * Note: dx_root_info is laid out so that if it should somehow get
158 * overlaid by a dirent the two low bits of the hash version will be
159 * zero. Therefore, the hash version mod 4 should never be 0.
160 * Sincerely, the paranoia department.
161 */
162struct ext2_dx_root_info {
163 __u32 reserved_zero;
164 __u8 hash_version; /* 0 now, 1 at release */
165 __u8 info_length; /* 8 */
166 __u8 indirect_levels;
167 __u8 unused_flags;
168};
169
170#define EXT2_HASH_LEGACY 0
171#define EXT2_HASH_HALF_MD4 1
172#define EXT2_HASH_TEA 2
173
174#define EXT2_HASH_FLAG_INCOMPAT 0x1
175
176struct ext2_dx_entry {
177 __u32 hash;
178 __u32 block;
179};
180
181struct ext2_dx_countlimit {
182 __u16 limit;
183 __u16 count;
184};
185
186
187/*
188 * Macro-instructions used to manage group descriptors
189 */
190#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group)
191#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group)
192#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
193/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
194#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((1 << 16) - 8)
195#define EXT2_MAX_INODES_PER_GROUP(s) ((1 << 16) - EXT2_INODES_PER_BLOCK(s))
196#ifdef __KERNEL__
197#define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->s_desc_per_block)
198#define EXT2_DESC_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_desc_per_block_bits)
199#else
200#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
201#endif
202
203/*
204 * Constants relative to the data blocks
205 */
206#define EXT2_NDIR_BLOCKS 12
207#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
208#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
209#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
210#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
211
212/*
213 * Inode flags
214 */
215#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
216#define EXT2_UNRM_FL 0x00000002 /* Undelete */
217#define EXT2_COMPR_FL 0x00000004 /* Compress file */
218#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
219#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
220#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
221#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
222#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
223/* Reserved for compression usage... */
224#define EXT2_DIRTY_FL 0x00000100
225#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
226#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */
227#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
228/* End compression flags --- maybe not all used */
229#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
230#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
231#define EXT2_IMAGIC_FL 0x00002000
232#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
233#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
234#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */
235#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
236#define EXT3_EXTENTS_FL 0x00080000 /* Inode uses extents */
237#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
238
239#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
240#define EXT2_FL_USER_MODIFIABLE 0x000080FF /* User modifiable flags */
241
242/*
243 * ioctl commands
244 */
245#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
246#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
247#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
248#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
249
250/*
251 * Structure of an inode on the disk
252 */
253struct ext2_inode {
254 __u16 i_mode; /* File mode */
255 __u16 i_uid; /* Low 16 bits of Owner Uid */
256 __u32 i_size; /* Size in bytes */
257 __u32 i_atime; /* Access time */
258 __u32 i_ctime; /* Creation time */
259 __u32 i_mtime; /* Modification time */
260 __u32 i_dtime; /* Deletion Time */
261 __u16 i_gid; /* Low 16 bits of Group Id */
262 __u16 i_links_count; /* Links count */
263 __u32 i_blocks; /* Blocks count */
264 __u32 i_flags; /* File flags */
265 union {
266 struct {
267 __u32 l_i_reserved1;
268 } linux1;
269 struct {
270 __u32 h_i_translator;
271 } hurd1;
272 struct {
273 __u32 m_i_reserved1;
274 } masix1;
275 } osd1; /* OS dependent 1 */
276 __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
277 __u32 i_generation; /* File version (for NFS) */
278 __u32 i_file_acl; /* File ACL */
279 __u32 i_dir_acl; /* Directory ACL */
280 __u32 i_faddr; /* Fragment address */
281 union {
282 struct {
283 __u8 l_i_frag; /* Fragment number */
284 __u8 l_i_fsize; /* Fragment size */
285 __u16 i_pad1;
286 __u16 l_i_uid_high; /* these 2 fields */
287 __u16 l_i_gid_high; /* were reserved2[0] */
288 __u32 l_i_reserved2;
289 } linux2;
290 struct {
291 __u8 h_i_frag; /* Fragment number */
292 __u8 h_i_fsize; /* Fragment size */
293 __u16 h_i_mode_high;
294 __u16 h_i_uid_high;
295 __u16 h_i_gid_high;
296 __u32 h_i_author;
297 } hurd2;
298 struct {
299 __u8 m_i_frag; /* Fragment number */
300 __u8 m_i_fsize; /* Fragment size */
301 __u16 m_pad1;
302 __u32 m_i_reserved2[2];
303 } masix2;
304 } osd2; /* OS dependent 2 */
305};
306
307/*
308 * Permanent part of an large inode on the disk
309 */
310struct ext2_inode_large {
311 __u16 i_mode; /* File mode */
312 __u16 i_uid; /* Low 16 bits of Owner Uid */
313 __u32 i_size; /* Size in bytes */
314 __u32 i_atime; /* Access time */
315 __u32 i_ctime; /* Creation time */
316 __u32 i_mtime; /* Modification time */
317 __u32 i_dtime; /* Deletion Time */
318 __u16 i_gid; /* Low 16 bits of Group Id */
319 __u16 i_links_count; /* Links count */
320 __u32 i_blocks; /* Blocks count */
321 __u32 i_flags; /* File flags */
322 union {
323 struct {
324 __u32 l_i_reserved1;
325 } linux1;
326 struct {
327 __u32 h_i_translator;
328 } hurd1;
329 struct {
330 __u32 m_i_reserved1;
331 } masix1;
332 } osd1; /* OS dependent 1 */
333 __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
334 __u32 i_generation; /* File version (for NFS) */
335 __u32 i_file_acl; /* File ACL */
336 __u32 i_dir_acl; /* Directory ACL */
337 __u32 i_faddr; /* Fragment address */
338 union {
339 struct {
340 __u8 l_i_frag; /* Fragment number */
341 __u8 l_i_fsize; /* Fragment size */
342 __u16 i_pad1;
343 __u16 l_i_uid_high; /* these 2 fields */
344 __u16 l_i_gid_high; /* were reserved2[0] */
345 __u32 l_i_reserved2;
346 } linux2;
347 struct {
348 __u8 h_i_frag; /* Fragment number */
349 __u8 h_i_fsize; /* Fragment size */
350 __u16 h_i_mode_high;
351 __u16 h_i_uid_high;
352 __u16 h_i_gid_high;
353 __u32 h_i_author;
354 } hurd2;
355 struct {
356 __u8 m_i_frag; /* Fragment number */
357 __u8 m_i_fsize; /* Fragment size */
358 __u16 m_pad1;
359 __u32 m_i_reserved2[2];
360 } masix2;
361 } osd2; /* OS dependent 2 */
362 __u16 i_extra_isize;
363 __u16 i_pad1;
364};
365
366#define i_size_high i_dir_acl
367
368#if defined(__KERNEL__) || defined(__linux__)
369#define i_reserved1 osd1.linux1.l_i_reserved1
370#define i_frag osd2.linux2.l_i_frag
371#define i_fsize osd2.linux2.l_i_fsize
372#define i_uid_low i_uid
373#define i_gid_low i_gid
374#define i_uid_high osd2.linux2.l_i_uid_high
375#define i_gid_high osd2.linux2.l_i_gid_high
376#define i_reserved2 osd2.linux2.l_i_reserved2
377
378#else
379#if defined(__GNU__)
380
381#define i_translator osd1.hurd1.h_i_translator
382#define i_frag osd2.hurd2.h_i_frag;
383#define i_fsize osd2.hurd2.h_i_fsize;
384#define i_uid_high osd2.hurd2.h_i_uid_high
385#define i_gid_high osd2.hurd2.h_i_gid_high
386#define i_author osd2.hurd2.h_i_author
387
388#else
389#if defined(__masix__)
390
391#define i_reserved1 osd1.masix1.m_i_reserved1
392#define i_frag osd2.masix2.m_i_frag
393#define i_fsize osd2.masix2.m_i_fsize
394#define i_reserved2 osd2.masix2.m_i_reserved2
395
396#endif /* __masix__ */
397#endif /* __GNU__ */
398#endif /* defined(__KERNEL__) || defined(__linux__) */
399
400/*
401 * File system states
402 */
403#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
404#define EXT2_ERROR_FS 0x0002 /* Errors detected */
405
406/*
407 * Mount flags
408 */
409#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
410#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
411#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
412#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
413#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
414#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
415#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
416#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
417
418#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
419#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
420#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
421 EXT2_MOUNT_##opt)
422/*
423 * Maximal mount counts between two filesystem checks
424 */
425#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
426#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
427
428/*
429 * Behaviour when detecting errors
430 */
431#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
432#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
433#define EXT2_ERRORS_PANIC 3 /* Panic */
434#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
435
436/*
437 * Structure of the super block
438 */
439struct ext2_super_block {
440 __u32 s_inodes_count; /* Inodes count */
441 __u32 s_blocks_count; /* Blocks count */
442 __u32 s_r_blocks_count; /* Reserved blocks count */
443 __u32 s_free_blocks_count; /* Free blocks count */
444 __u32 s_free_inodes_count; /* Free inodes count */
445 __u32 s_first_data_block; /* First Data Block */
446 __u32 s_log_block_size; /* Block size */
447 __s32 s_log_frag_size; /* Fragment size */
448 __u32 s_blocks_per_group; /* # Blocks per group */
449 __u32 s_frags_per_group; /* # Fragments per group */
450 __u32 s_inodes_per_group; /* # Inodes per group */
451 __u32 s_mtime; /* Mount time */
452 __u32 s_wtime; /* Write time */
453 __u16 s_mnt_count; /* Mount count */
454 __s16 s_max_mnt_count; /* Maximal mount count */
455 __u16 s_magic; /* Magic signature */
456 __u16 s_state; /* File system state */
457 __u16 s_errors; /* Behaviour when detecting errors */
458 __u16 s_minor_rev_level; /* minor revision level */
459 __u32 s_lastcheck; /* time of last check */
460 __u32 s_checkinterval; /* max. time between checks */
461 __u32 s_creator_os; /* OS */
462 __u32 s_rev_level; /* Revision level */
463 __u16 s_def_resuid; /* Default uid for reserved blocks */
464 __u16 s_def_resgid; /* Default gid for reserved blocks */
465 /*
466 * These fields are for EXT2_DYNAMIC_REV superblocks only.
467 *
468 * Note: the difference between the compatible feature set and
469 * the incompatible feature set is that if there is a bit set
470 * in the incompatible feature set that the kernel doesn't
471 * know about, it should refuse to mount the filesystem.
472 *
473 * e2fsck's requirements are more strict; if it doesn't know
474 * about a feature in either the compatible or incompatible
475 * feature set, it must abort and not try to meddle with
476 * things it doesn't understand...
477 */
478 __u32 s_first_ino; /* First non-reserved inode */
479 __u16 s_inode_size; /* size of inode structure */
480 __u16 s_block_group_nr; /* block group # of this superblock */
481 __u32 s_feature_compat; /* compatible feature set */
482 __u32 s_feature_incompat; /* incompatible feature set */
483 __u32 s_feature_ro_compat; /* readonly-compatible feature set */
484 __u8 s_uuid[16]; /* 128-bit uuid for volume */
485 char s_volume_name[16]; /* volume name */
486 char s_last_mounted[64]; /* directory where last mounted */
487 __u32 s_algorithm_usage_bitmap; /* For compression */
488 /*
489 * Performance hints. Directory preallocation should only
490 * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
491 */
492 __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
493 __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
494 __u16 s_reserved_gdt_blocks; /* Per group table for online growth */
495 /*
496 * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
497 */
498 __u8 s_journal_uuid[16]; /* uuid of journal superblock */
499 __u32 s_journal_inum; /* inode number of journal file */
500 __u32 s_journal_dev; /* device number of journal file */
501 __u32 s_last_orphan; /* start of list of inodes to delete */
502 __u32 s_hash_seed[4]; /* HTREE hash seed */
503 __u8 s_def_hash_version; /* Default hash version to use */
504 __u8 s_jnl_backup_type; /* Default type of journal backup */
505 __u16 s_reserved_word_pad;
506 __u32 s_default_mount_opts;
507 __u32 s_first_meta_bg; /* First metablock group */
508 __u32 s_mkfs_time; /* When the filesystem was created */
509 __u32 s_jnl_blocks[17]; /* Backup of the journal inode */
510 __u32 s_reserved[172]; /* Padding to the end of the block */
511};
512
513/*
514 * Codes for operating systems
515 */
516#define EXT2_OS_LINUX 0
517#define EXT2_OS_HURD 1
518#define EXT2_OS_MASIX 2
519#define EXT2_OS_FREEBSD 3
520#define EXT2_OS_LITES 4
521
522/*
523 * Revision levels
524 */
525#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
526#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
527
528#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
529#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
530
531#define EXT2_GOOD_OLD_INODE_SIZE 128
532
533/*
534 * Journal inode backup types
535 */
536#define EXT3_JNL_BACKUP_BLOCKS 1
537
538/*
539 * Feature set definitions
540 */
541
542#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
543 ( EXT2_SB(sb)->s_feature_compat & (mask) )
544#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
545 ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
546#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
547 ( EXT2_SB(sb)->s_feature_incompat & (mask) )
548
549#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
550#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
551#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
552#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
553#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
554#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
555
556#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
557#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
558/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */
559
560#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
561#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
562#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
563#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
564#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
565#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
566
567
568#define EXT2_FEATURE_COMPAT_SUPP 0
569#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE)
570#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
571 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
572 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
573
574/*
575 * Default values for user and/or group using reserved blocks
576 */
577#define EXT2_DEF_RESUID 0
578#define EXT2_DEF_RESGID 0
579
580/*
581 * Default mount options
582 */
583#define EXT2_DEFM_DEBUG 0x0001
584#define EXT2_DEFM_BSDGROUPS 0x0002
585#define EXT2_DEFM_XATTR_USER 0x0004
586#define EXT2_DEFM_ACL 0x0008
587#define EXT2_DEFM_UID16 0x0010
588#define EXT3_DEFM_JMODE 0x0060
589#define EXT3_DEFM_JMODE_DATA 0x0020
590#define EXT3_DEFM_JMODE_ORDERED 0x0040
591#define EXT3_DEFM_JMODE_WBACK 0x0060
592
593/*
594 * Structure of a directory entry
595 */
596#define EXT2_NAME_LEN 255
597
598struct ext2_dir_entry {
599 __u32 inode; /* Inode number */
600 __u16 rec_len; /* Directory entry length */
601 __u16 name_len; /* Name length */
602 char name[EXT2_NAME_LEN]; /* File name */
603};
604
605/*
606 * The new version of the directory entry. Since EXT2 structures are
607 * stored in intel byte order, and the name_len field could never be
608 * bigger than 255 chars, it's safe to reclaim the extra byte for the
609 * file_type field.
610 */
611struct ext2_dir_entry_2 {
612 __u32 inode; /* Inode number */
613 __u16 rec_len; /* Directory entry length */
614 __u8 name_len; /* Name length */
615 __u8 file_type;
616 char name[EXT2_NAME_LEN]; /* File name */
617};
618
619/*
620 * Ext2 directory file types. Only the low 3 bits are used. The
621 * other bits are reserved for now.
622 */
623#define EXT2_FT_UNKNOWN 0
624#define EXT2_FT_REG_FILE 1
625#define EXT2_FT_DIR 2
626#define EXT2_FT_CHRDEV 3
627#define EXT2_FT_BLKDEV 4
628#define EXT2_FT_FIFO 5
629#define EXT2_FT_SOCK 6
630#define EXT2_FT_SYMLINK 7
631
632#define EXT2_FT_MAX 8
633
634/*
635 * EXT2_DIR_PAD defines the directory entries boundaries
636 *
637 * NOTE: It must be a multiple of 4
638 */
639#define EXT2_DIR_PAD 4
640#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
641#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
642 ~EXT2_DIR_ROUND)
643
644#endif /* _LINUX_EXT2_FS_H */
diff --git a/e2fsprogs/ext2fs/ext2_io.h b/e2fsprogs/ext2fs/ext2_io.h
new file mode 100644
index 000000000..e17886c85
--- /dev/null
+++ b/e2fsprogs/ext2fs/ext2_io.h
@@ -0,0 +1,108 @@
1/*
2 * io.h --- the I/O manager abstraction
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#ifndef _EXT2FS_EXT2_IO_H
13#define _EXT2FS_EXT2_IO_H
14
15/*
16 * ext2_loff_t is defined here since unix_io.c needs it.
17 */
18#if defined(__GNUC__) || defined(HAS_LONG_LONG)
19typedef long long ext2_loff_t;
20#else
21typedef long ext2_loff_t;
22#endif
23
24/* llseek.c */
25ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int);
26
27typedef struct struct_io_manager *io_manager;
28typedef struct struct_io_channel *io_channel;
29
30#define CHANNEL_FLAGS_WRITETHROUGH 0x01
31
32struct struct_io_channel {
33 errcode_t magic;
34 io_manager manager;
35 char *name;
36 int block_size;
37 errcode_t (*read_error)(io_channel channel,
38 unsigned long block,
39 int count,
40 void *data,
41 size_t size,
42 int actual_bytes_read,
43 errcode_t error);
44 errcode_t (*write_error)(io_channel channel,
45 unsigned long block,
46 int count,
47 const void *data,
48 size_t size,
49 int actual_bytes_written,
50 errcode_t error);
51 int refcount;
52 int flags;
53 int reserved[14];
54 void *private_data;
55 void *app_data;
56};
57
58struct struct_io_manager {
59 errcode_t magic;
60 const char *name;
61 errcode_t (*open)(const char *name, int flags, io_channel *channel);
62 errcode_t (*close)(io_channel channel);
63 errcode_t (*set_blksize)(io_channel channel, int blksize);
64 errcode_t (*read_blk)(io_channel channel, unsigned long block,
65 int count, void *data);
66 errcode_t (*write_blk)(io_channel channel, unsigned long block,
67 int count, const void *data);
68 errcode_t (*flush)(io_channel channel);
69 errcode_t (*write_byte)(io_channel channel, unsigned long offset,
70 int count, const void *data);
71 errcode_t (*set_option)(io_channel channel, const char *option,
72 const char *arg);
73 int reserved[14];
74};
75
76#define IO_FLAG_RW 1
77
78/*
79 * Convenience functions....
80 */
81#define io_channel_close(c) ((c)->manager->close((c)))
82#define io_channel_set_blksize(c,s) ((c)->manager->set_blksize((c),s))
83#define io_channel_read_blk(c,b,n,d) ((c)->manager->read_blk((c),b,n,d))
84#define io_channel_write_blk(c,b,n,d) ((c)->manager->write_blk((c),b,n,d))
85#define io_channel_flush(c) ((c)->manager->flush((c)))
86#define io_channel_bumpcount(c) ((c)->refcount++)
87
88/* io_manager.c */
89extern errcode_t io_channel_set_options(io_channel channel,
90 const char *options);
91extern errcode_t io_channel_write_byte(io_channel channel,
92 unsigned long offset,
93 int count, const void *data);
94
95/* unix_io.c */
96extern io_manager unix_io_manager;
97
98/* test_io.c */
99extern io_manager test_io_manager, test_io_backing_manager;
100extern void (*test_io_cb_read_blk)
101 (unsigned long block, int count, errcode_t err);
102extern void (*test_io_cb_write_blk)
103 (unsigned long block, int count, errcode_t err);
104extern void (*test_io_cb_set_blksize)
105 (int blksize, errcode_t err);
106
107#endif /* _EXT2FS_EXT2_IO_H */
108
diff --git a/e2fsprogs/ext2fs/ext2_types.h b/e2fsprogs/ext2fs/ext2_types.h
new file mode 100644
index 000000000..ee9b980a2
--- /dev/null
+++ b/e2fsprogs/ext2fs/ext2_types.h
@@ -0,0 +1 @@
#include <linux/types.h>
diff --git a/e2fsprogs/ext2fs/ext2fs.h b/e2fsprogs/ext2fs/ext2fs.h
new file mode 100644
index 000000000..0832bc286
--- /dev/null
+++ b/e2fsprogs/ext2fs/ext2fs.h
@@ -0,0 +1,1137 @@
1/*
2 * ext2fs.h --- ext2fs
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#ifndef _EXT2FS_EXT2FS_H
13#define _EXT2FS_EXT2FS_H
14
15#ifdef __GNUC__
16#define EXT2FS_ATTR(x) __attribute__(x)
17#else
18#define EXT2FS_ATTR(x)
19#endif
20
21#ifdef __cplusplus
22extern "C" {
23#endif
24
25/*
26 * Non-GNU C compilers won't necessarily understand inline
27 */
28#if (!defined(__GNUC__) && !defined(__WATCOMC__))
29#define NO_INLINE_FUNCS
30#endif
31
32/*
33 * Build in support for byte-swapping filesystems if we the feature
34 * has been configured or if we're being built on a CPU architecture
35 * with a non-native byte order.
36 */
37#if defined(ENABLE_SWAPFS) || defined(WORDS_BIGENDIAN)
38#define EXT2FS_ENABLE_SWAPFS
39#endif
40
41/*
42 * Where the master copy of the superblock is located, and how big
43 * superblocks are supposed to be. We define SUPERBLOCK_SIZE because
44 * the size of the superblock structure is not necessarily trustworthy
45 * (some versions have the padding set up so that the superblock is
46 * 1032 bytes long).
47 */
48#define SUPERBLOCK_OFFSET 1024
49#define SUPERBLOCK_SIZE 1024
50
51/*
52 * The last ext2fs revision level that this version of the library is
53 * able to support.
54 */
55#define EXT2_LIB_CURRENT_REV EXT2_DYNAMIC_REV
56
57#ifdef HAVE_SYS_TYPES_H
58#include <sys/types.h>
59#endif
60
61#include <stdio.h>
62#include <stdlib.h>
63
64#if EXT2_FLAT_INCLUDES
65#include "e2_types.h"
66#include "ext2_fs.h"
67#else
68#include <ext2fs/ext2_types.h>
69#include <ext2fs/ext2_fs.h>
70#endif /* EXT2_FLAT_INCLUDES */
71
72typedef __u32 ext2_ino_t;
73typedef __u32 blk_t;
74typedef __u32 dgrp_t;
75typedef __u32 ext2_off_t;
76typedef __s64 e2_blkcnt_t;
77typedef __u32 ext2_dirhash_t;
78
79#if EXT2_FLAT_INCLUDES
80#include "com_err.h"
81#include "ext2_io.h"
82#include "ext2_err.h"
83#else
84#include <et/com_err.h>
85#include <ext2fs/ext2_io.h>
86#include <ext2fs/ext2_err.h>
87#endif
88
89/*
90 * Portability help for Microsoft Visual C++
91 */
92#ifdef _MSC_VER
93#define EXT2_QSORT_TYPE int __cdecl
94#else
95#define EXT2_QSORT_TYPE int
96#endif
97
98typedef struct struct_ext2_filsys *ext2_filsys;
99
100struct ext2fs_struct_generic_bitmap {
101 errcode_t magic;
102 ext2_filsys fs;
103 __u32 start, end;
104 __u32 real_end;
105 char * description;
106 char * bitmap;
107 errcode_t base_error_code;
108 __u32 reserved[7];
109};
110
111#define EXT2FS_MARK_ERROR 0
112#define EXT2FS_UNMARK_ERROR 1
113#define EXT2FS_TEST_ERROR 2
114
115typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap;
116typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap;
117typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap;
118
119#ifdef EXT2_DYNAMIC_REV
120#define EXT2_FIRST_INODE(s) EXT2_FIRST_INO(s)
121#else
122#define EXT2_FIRST_INODE(s) EXT2_FIRST_INO
123#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode)
124#endif
125
126/*
127 * badblocks list definitions
128 */
129
130typedef struct ext2_struct_u32_list *ext2_badblocks_list;
131typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate;
132
133typedef struct ext2_struct_u32_list *ext2_u32_list;
134typedef struct ext2_struct_u32_iterate *ext2_u32_iterate;
135
136/* old */
137typedef struct ext2_struct_u32_list *badblocks_list;
138typedef struct ext2_struct_u32_iterate *badblocks_iterate;
139
140#define BADBLOCKS_FLAG_DIRTY 1
141
142/*
143 * ext2_dblist structure and abstractions (see dblist.c)
144 */
145struct ext2_db_entry {
146 ext2_ino_t ino;
147 blk_t blk;
148 int blockcnt;
149};
150
151typedef struct ext2_struct_dblist *ext2_dblist;
152
153#define DBLIST_ABORT 1
154
155/*
156 * ext2_fileio definitions
157 */
158
159#define EXT2_FILE_WRITE 0x0001
160#define EXT2_FILE_CREATE 0x0002
161
162#define EXT2_FILE_MASK 0x00FF
163
164#define EXT2_FILE_BUF_DIRTY 0x4000
165#define EXT2_FILE_BUF_VALID 0x2000
166
167typedef struct ext2_file *ext2_file_t;
168
169#define EXT2_SEEK_SET 0
170#define EXT2_SEEK_CUR 1
171#define EXT2_SEEK_END 2
172
173/*
174 * Flags for the ext2_filsys structure and for ext2fs_open()
175 */
176#define EXT2_FLAG_RW 0x01
177#define EXT2_FLAG_CHANGED 0x02
178#define EXT2_FLAG_DIRTY 0x04
179#define EXT2_FLAG_VALID 0x08
180#define EXT2_FLAG_IB_DIRTY 0x10
181#define EXT2_FLAG_BB_DIRTY 0x20
182#define EXT2_FLAG_SWAP_BYTES 0x40
183#define EXT2_FLAG_SWAP_BYTES_READ 0x80
184#define EXT2_FLAG_SWAP_BYTES_WRITE 0x100
185#define EXT2_FLAG_MASTER_SB_ONLY 0x200
186#define EXT2_FLAG_FORCE 0x400
187#define EXT2_FLAG_SUPER_ONLY 0x800
188#define EXT2_FLAG_JOURNAL_DEV_OK 0x1000
189#define EXT2_FLAG_IMAGE_FILE 0x2000
190
191/*
192 * Special flag in the ext2 inode i_flag field that means that this is
193 * a new inode. (So that ext2_write_inode() can clear extra fields.)
194 */
195#define EXT2_NEW_INODE_FL 0x80000000
196
197/*
198 * Flags for mkjournal
199 *
200 * EXT2_MKJOURNAL_V1_SUPER Make a (deprecated) V1 journal superblock
201 */
202#define EXT2_MKJOURNAL_V1_SUPER 0x0000001
203
204struct struct_ext2_filsys {
205 errcode_t magic;
206 io_channel io;
207 int flags;
208 char * device_name;
209 struct ext2_super_block * super;
210 unsigned int blocksize;
211 int fragsize;
212 dgrp_t group_desc_count;
213 unsigned long desc_blocks;
214 struct ext2_group_desc * group_desc;
215 int inode_blocks_per_group;
216 ext2fs_inode_bitmap inode_map;
217 ext2fs_block_bitmap block_map;
218 errcode_t (*get_blocks)(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
219 errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino);
220 errcode_t (*write_bitmaps)(ext2_filsys fs);
221 errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino,
222 struct ext2_inode *inode);
223 errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino,
224 struct ext2_inode *inode);
225 ext2_badblocks_list badblocks;
226 ext2_dblist dblist;
227 __u32 stride; /* for mke2fs */
228 struct ext2_super_block * orig_super;
229 struct ext2_image_hdr * image_header;
230 __u32 umask;
231 /*
232 * Reserved for future expansion
233 */
234 __u32 reserved[8];
235
236 /*
237 * Reserved for the use of the calling application.
238 */
239 void * priv_data;
240
241 /*
242 * Inode cache
243 */
244 struct ext2_inode_cache *icache;
245 io_channel image_io;
246};
247
248#if EXT2_FLAT_INCLUDES
249#include "e2_bitops.h"
250#else
251#include <ext2fs/bitops.h>
252#endif
253
254/*
255 * Return flags for the block iterator functions
256 */
257#define BLOCK_CHANGED 1
258#define BLOCK_ABORT 2
259#define BLOCK_ERROR 4
260
261/*
262 * Block interate flags
263 *
264 * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the interator
265 * function should be called on blocks where the block number is zero.
266 * This is used by ext2fs_expand_dir() to be able to add a new block
267 * to an inode. It can also be used for programs that want to be able
268 * to deal with files that contain "holes".
269 *
270 * BLOCK_FLAG_TRAVERSE indicates that the iterator function for the
271 * indirect, doubly indirect, etc. blocks should be called after all
272 * of the blocks containined in the indirect blocks are processed.
273 * This is useful if you are going to be deallocating blocks from an
274 * inode.
275 *
276 * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be
277 * called for data blocks only.
278 *
279 * BLOCK_FLAG_NO_LARGE is for internal use only. It informs
280 * ext2fs_block_iterate2 that large files won't be accepted.
281 */
282#define BLOCK_FLAG_APPEND 1
283#define BLOCK_FLAG_HOLE 1
284#define BLOCK_FLAG_DEPTH_TRAVERSE 2
285#define BLOCK_FLAG_DATA_ONLY 4
286
287#define BLOCK_FLAG_NO_LARGE 0x1000
288
289/*
290 * Magic "block count" return values for the block iterator function.
291 */
292#define BLOCK_COUNT_IND (-1)
293#define BLOCK_COUNT_DIND (-2)
294#define BLOCK_COUNT_TIND (-3)
295#define BLOCK_COUNT_TRANSLATOR (-4)
296
297#if 0
298/*
299 * Flags for ext2fs_move_blocks
300 */
301#define EXT2_BMOVE_GET_DBLIST 0x0001
302#define EXT2_BMOVE_DEBUG 0x0002
303#endif
304
305/*
306 * Flags for directory block reading and writing functions
307 */
308#define EXT2_DIRBLOCK_V2_STRUCT 0x0001
309
310/*
311 * Return flags for the directory iterator functions
312 */
313#define DIRENT_CHANGED 1
314#define DIRENT_ABORT 2
315#define DIRENT_ERROR 3
316
317/*
318 * Directory iterator flags
319 */
320
321#define DIRENT_FLAG_INCLUDE_EMPTY 1
322#define DIRENT_FLAG_INCLUDE_REMOVED 2
323
324#define DIRENT_DOT_FILE 1
325#define DIRENT_DOT_DOT_FILE 2
326#define DIRENT_OTHER_FILE 3
327#define DIRENT_DELETED_FILE 4
328
329/*
330 * Inode scan definitions
331 */
332typedef struct ext2_struct_inode_scan *ext2_inode_scan;
333
334/*
335 * ext2fs_scan flags
336 */
337#define EXT2_SF_CHK_BADBLOCKS 0x0001
338#define EXT2_SF_BAD_INODE_BLK 0x0002
339#define EXT2_SF_BAD_EXTRA_BYTES 0x0004
340#define EXT2_SF_SKIP_MISSING_ITABLE 0x0008
341
342/*
343 * ext2fs_check_if_mounted flags
344 */
345#define EXT2_MF_MOUNTED 1
346#define EXT2_MF_ISROOT 2
347#define EXT2_MF_READONLY 4
348#define EXT2_MF_SWAP 8
349
350/*
351 * Ext2/linux mode flags. We define them here so that we don't need
352 * to depend on the OS's sys/stat.h, since we may be compiling on a
353 * non-Linux system.
354 */
355#define LINUX_S_IFMT 00170000
356#define LINUX_S_IFSOCK 0140000
357#define LINUX_S_IFLNK 0120000
358#define LINUX_S_IFREG 0100000
359#define LINUX_S_IFBLK 0060000
360#define LINUX_S_IFDIR 0040000
361#define LINUX_S_IFCHR 0020000
362#define LINUX_S_IFIFO 0010000
363#define LINUX_S_ISUID 0004000
364#define LINUX_S_ISGID 0002000
365#define LINUX_S_ISVTX 0001000
366
367#define LINUX_S_IRWXU 00700
368#define LINUX_S_IRUSR 00400
369#define LINUX_S_IWUSR 00200
370#define LINUX_S_IXUSR 00100
371
372#define LINUX_S_IRWXG 00070
373#define LINUX_S_IRGRP 00040
374#define LINUX_S_IWGRP 00020
375#define LINUX_S_IXGRP 00010
376
377#define LINUX_S_IRWXO 00007
378#define LINUX_S_IROTH 00004
379#define LINUX_S_IWOTH 00002
380#define LINUX_S_IXOTH 00001
381
382#define LINUX_S_ISLNK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK)
383#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG)
384#define LINUX_S_ISDIR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR)
385#define LINUX_S_ISCHR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR)
386#define LINUX_S_ISBLK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK)
387#define LINUX_S_ISFIFO(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO)
388#define LINUX_S_ISSOCK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK)
389
390/*
391 * ext2 size of an inode
392 */
393#define EXT2_I_SIZE(i) ((i)->i_size | ((__u64) (i)->i_size_high << 32))
394
395/*
396 * ext2_icount_t abstraction
397 */
398#define EXT2_ICOUNT_OPT_INCREMENT 0x01
399
400typedef struct ext2_icount *ext2_icount_t;
401
402/*
403 * Flags for ext2fs_bmap
404 */
405#define BMAP_ALLOC 0x0001
406#define BMAP_SET 0x0002
407
408/*
409 * Flags for imager.c functions
410 */
411#define IMAGER_FLAG_INODEMAP 1
412#define IMAGER_FLAG_SPARSEWRITE 2
413
414/*
415 * For checking structure magic numbers...
416 */
417
418#define EXT2_CHECK_MAGIC(struct, code) \
419 if ((struct)->magic != (code)) return (code)
420
421
422/*
423 * For ext2 compression support
424 */
425#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) 0xffffffff)
426#define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR)
427
428/*
429 * Features supported by this version of the library
430 */
431#define EXT2_LIB_FEATURE_COMPAT_SUPP (EXT2_FEATURE_COMPAT_DIR_PREALLOC|\
432 EXT2_FEATURE_COMPAT_IMAGIC_INODES|\
433 EXT3_FEATURE_COMPAT_HAS_JOURNAL|\
434 EXT2_FEATURE_COMPAT_RESIZE_INODE|\
435 EXT2_FEATURE_COMPAT_DIR_INDEX|\
436 EXT2_FEATURE_COMPAT_EXT_ATTR)
437
438/* This #ifdef is temporary until compression is fully supported */
439#ifdef ENABLE_COMPRESSION
440#ifndef I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL
441/* If the below warning bugs you, then have
442 `CPPFLAGS=-DI_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL' in your
443 environment at configure time. */
444 #warning "Compression support is experimental"
445#endif
446#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
447 EXT2_FEATURE_INCOMPAT_COMPRESSION|\
448 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
449 EXT2_FEATURE_INCOMPAT_META_BG|\
450 EXT3_FEATURE_INCOMPAT_RECOVER)
451#else
452#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
453 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
454 EXT2_FEATURE_INCOMPAT_META_BG|\
455 EXT3_FEATURE_INCOMPAT_RECOVER)
456#endif
457#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
458 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
459/*
460 * function prototypes
461 */
462
463/* alloc.c */
464extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode,
465 ext2fs_inode_bitmap map, ext2_ino_t *ret);
466extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
467 ext2fs_block_bitmap map, blk_t *ret);
468extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start,
469 blk_t finish, int num,
470 ext2fs_block_bitmap map,
471 blk_t *ret);
472extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
473 char *block_buf, blk_t *ret);
474
475/* alloc_sb.c */
476extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
477 dgrp_t group,
478 ext2fs_block_bitmap bmap);
479
480/* alloc_stats.c */
481void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse);
482void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
483 int inuse, int isdir);
484void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse);
485
486/* alloc_tables.c */
487extern errcode_t ext2fs_allocate_tables(ext2_filsys fs);
488extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
489 ext2fs_block_bitmap bmap);
490
491/* badblocks.c */
492extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size);
493extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk);
494extern int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk);
495extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk);
496extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
497 ext2_u32_iterate *ret);
498extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk);
499extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter);
500extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest);
501extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2);
502
503extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret,
504 int size);
505extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb,
506 blk_t blk);
507extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb,
508 blk_t blk);
509extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk);
510extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk);
511extern errcode_t
512 ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
513 ext2_badblocks_iterate *ret);
514extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter,
515 blk_t *blk);
516extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter);
517extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
518 ext2_badblocks_list *dest);
519extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1,
520 ext2_badblocks_list bb2);
521extern int ext2fs_u32_list_count(ext2_u32_list bb);
522
523/* bb_compat */
524extern errcode_t badblocks_list_create(badblocks_list *ret, int size);
525extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk);
526extern int badblocks_list_test(badblocks_list bb, blk_t blk);
527extern errcode_t badblocks_list_iterate_begin(badblocks_list bb,
528 badblocks_iterate *ret);
529extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk);
530extern void badblocks_list_iterate_end(badblocks_iterate iter);
531extern void badblocks_list_free(badblocks_list bb);
532
533/* bb_inode.c */
534extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs,
535 ext2_badblocks_list bb_list);
536
537/* bitmaps.c */
538extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs);
539extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs);
540extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs);
541extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs);
542extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
543 __u32 end,
544 __u32 real_end,
545 const char *descr,
546 ext2fs_generic_bitmap *ret);
547extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
548 const char *descr,
549 ext2fs_block_bitmap *ret);
550extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
551 const char *descr,
552 ext2fs_inode_bitmap *ret);
553extern errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
554 ext2_ino_t end, ext2_ino_t *oend);
555extern errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
556 blk_t end, blk_t *oend);
557extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap);
558extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap);
559extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs);
560extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs);
561
562/* block.c */
563extern errcode_t ext2fs_block_iterate(ext2_filsys fs,
564 ext2_ino_t ino,
565 int flags,
566 char *block_buf,
567 int (*func)(ext2_filsys fs,
568 blk_t *blocknr,
569 int blockcnt,
570 void *priv_data),
571 void *priv_data);
572errcode_t ext2fs_block_iterate2(ext2_filsys fs,
573 ext2_ino_t ino,
574 int flags,
575 char *block_buf,
576 int (*func)(ext2_filsys fs,
577 blk_t *blocknr,
578 e2_blkcnt_t blockcnt,
579 blk_t ref_blk,
580 int ref_offset,
581 void *priv_data),
582 void *priv_data);
583
584/* bmap.c */
585extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
586 struct ext2_inode *inode,
587 char *block_buf, int bmap_flags,
588 blk_t block, blk_t *phys_blk);
589
590
591#if 0
592/* bmove.c */
593extern errcode_t ext2fs_move_blocks(ext2_filsys fs,
594 ext2fs_block_bitmap reserve,
595 ext2fs_block_bitmap alloc_map,
596 int flags);
597#endif
598
599/* check_desc.c */
600extern errcode_t ext2fs_check_desc(ext2_filsys fs);
601
602/* closefs.c */
603extern errcode_t ext2fs_close(ext2_filsys fs);
604extern errcode_t ext2fs_flush(ext2_filsys fs);
605extern int ext2fs_bg_has_super(ext2_filsys fs, int group_block);
606extern int ext2fs_super_and_bgd_loc(ext2_filsys fs,
607 dgrp_t group,
608 blk_t *ret_super_blk,
609 blk_t *ret_old_desc_blk,
610 blk_t *ret_new_desc_blk,
611 int *ret_meta_bg);
612extern void ext2fs_update_dynamic_rev(ext2_filsys fs);
613
614/* cmp_bitmaps.c */
615extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
616 ext2fs_block_bitmap bm2);
617extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
618 ext2fs_inode_bitmap bm2);
619
620/* dblist.c */
621
622extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
623extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist);
624extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino,
625 blk_t blk, int blockcnt);
626extern void ext2fs_dblist_sort(ext2_dblist dblist,
627 EXT2_QSORT_TYPE (*sortfunc)(const void *,
628 const void *));
629extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
630 int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info,
631 void *priv_data),
632 void *priv_data);
633extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino,
634 blk_t blk, int blockcnt);
635extern errcode_t ext2fs_copy_dblist(ext2_dblist src,
636 ext2_dblist *dest);
637extern int ext2fs_dblist_count(ext2_dblist dblist);
638
639/* dblist_dir.c */
640extern errcode_t
641 ext2fs_dblist_dir_iterate(ext2_dblist dblist,
642 int flags,
643 char *block_buf,
644 int (*func)(ext2_ino_t dir,
645 int entry,
646 struct ext2_dir_entry *dirent,
647 int offset,
648 int blocksize,
649 char *buf,
650 void *priv_data),
651 void *priv_data);
652
653/* dirblock.c */
654extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
655 void *buf);
656extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
657 void *buf, int flags);
658extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
659 void *buf);
660extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
661 void *buf, int flags);
662
663/* dirhash.c */
664extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
665 const __u32 *seed,
666 ext2_dirhash_t *ret_hash,
667 ext2_dirhash_t *ret_minor_hash);
668
669
670/* dir_iterate.c */
671extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
672 ext2_ino_t dir,
673 int flags,
674 char *block_buf,
675 int (*func)(struct ext2_dir_entry *dirent,
676 int offset,
677 int blocksize,
678 char *buf,
679 void *priv_data),
680 void *priv_data);
681extern errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
682 ext2_ino_t dir,
683 int flags,
684 char *block_buf,
685 int (*func)(ext2_ino_t dir,
686 int entry,
687 struct ext2_dir_entry *dirent,
688 int offset,
689 int blocksize,
690 char *buf,
691 void *priv_data),
692 void *priv_data);
693
694/* dupfs.c */
695extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest);
696
697/* expanddir.c */
698extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
699
700/* ext_attr.c */
701extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
702extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
703 void *buf);
704extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
705 char *block_buf,
706 int adjust, __u32 *newcount);
707
708/* fileio.c */
709extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
710 struct ext2_inode *inode,
711 int flags, ext2_file_t *ret);
712extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
713 int flags, ext2_file_t *ret);
714extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file);
715extern errcode_t ext2fs_file_close(ext2_file_t file);
716extern errcode_t ext2fs_file_flush(ext2_file_t file);
717extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
718 unsigned int wanted, unsigned int *got);
719extern errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
720 unsigned int nbytes, unsigned int *written);
721extern errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
722 int whence, __u64 *ret_pos);
723extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
724 int whence, ext2_off_t *ret_pos);
725errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size);
726extern ext2_off_t ext2fs_file_get_size(ext2_file_t file);
727extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size);
728
729/* finddev.c */
730extern char *ext2fs_find_block_device(dev_t device);
731
732/* flushb.c */
733extern errcode_t ext2fs_sync_device(int fd, int flushb);
734
735/* freefs.c */
736extern void ext2fs_free(ext2_filsys fs);
737extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap);
738extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
739extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
740extern void ext2fs_free_dblist(ext2_dblist dblist);
741extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb);
742extern void ext2fs_u32_list_free(ext2_u32_list bb);
743
744/* getsize.c */
745extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
746 blk_t *retblocks);
747
748/* getsectsize.c */
749errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize);
750
751/* imager.c */
752extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags);
753extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags);
754extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags);
755extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags);
756extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags);
757extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags);
758
759/* ind_block.c */
760errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf);
761errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf);
762
763/* initialize.c */
764extern errcode_t ext2fs_initialize(const char *name, int flags,
765 struct ext2_super_block *param,
766 io_manager manager, ext2_filsys *ret_fs);
767
768/* icount.c */
769extern void ext2fs_free_icount(ext2_icount_t icount);
770extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags,
771 unsigned int size,
772 ext2_icount_t hint, ext2_icount_t *ret);
773extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags,
774 unsigned int size,
775 ext2_icount_t *ret);
776extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino,
777 __u16 *ret);
778extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
779 __u16 *ret);
780extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
781 __u16 *ret);
782extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
783 __u16 count);
784extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
785errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
786
787/* inode.c */
788extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
789extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
790 ext2_ino_t *ino,
791 struct ext2_inode *inode,
792 int bufsize);
793extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
794 ext2_inode_scan *ret_scan);
795extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
796extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
797 struct ext2_inode *inode);
798extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
799 int group);
800extern void ext2fs_set_inode_callback
801 (ext2_inode_scan scan,
802 errcode_t (*done_group)(ext2_filsys fs,
803 ext2_inode_scan scan,
804 dgrp_t group,
805 void * priv_data),
806 void *done_group_data);
807extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
808 int clear_flags);
809extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
810 struct ext2_inode * inode,
811 int bufsize);
812extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
813 struct ext2_inode * inode);
814extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
815 struct ext2_inode * inode,
816 int bufsize);
817extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
818 struct ext2_inode * inode);
819extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
820 struct ext2_inode * inode);
821extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
822extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino);
823
824/* inode_io.c */
825extern io_manager inode_io_manager;
826extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
827 char **name);
828extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
829 struct ext2_inode *inode,
830 char **name);
831
832/* ismounted.c */
833extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags);
834extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
835 char *mtpt, int mtlen);
836
837/* namei.c */
838extern errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
839 int namelen, char *buf, ext2_ino_t *inode);
840extern errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
841 const char *name, ext2_ino_t *inode);
842errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
843 const char *name, ext2_ino_t *inode);
844extern errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
845 ext2_ino_t inode, ext2_ino_t *res_inode);
846
847/* native.c */
848int ext2fs_native_flag(void);
849
850/* newdir.c */
851extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
852 ext2_ino_t parent_ino, char **block);
853
854/* mkdir.c */
855extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
856 const char *name);
857
858/* mkjournal.c */
859extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
860 __u32 size, int flags,
861 char **ret_jsb);
862extern errcode_t ext2fs_add_journal_device(ext2_filsys fs,
863 ext2_filsys journal_dev);
864extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size,
865 int flags);
866
867/* openfs.c */
868extern errcode_t ext2fs_open(const char *name, int flags, int superblock,
869 unsigned int block_size, io_manager manager,
870 ext2_filsys *ret_fs);
871extern errcode_t ext2fs_open2(const char *name, const char *io_options,
872 int flags, int superblock,
873 unsigned int block_size, io_manager manager,
874 ext2_filsys *ret_fs);
875extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block,
876 dgrp_t i);
877errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io);
878errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io);
879errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io);
880
881/* get_pathname.c */
882extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
883 char **name);
884
885/* link.c */
886errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
887 ext2_ino_t ino, int flags);
888errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name,
889 ext2_ino_t ino, int flags);
890
891/* read_bb.c */
892extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs,
893 ext2_badblocks_list *bb_list);
894
895/* read_bb_file.c */
896extern errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
897 ext2_badblocks_list *bb_list,
898 void *priv_data,
899 void (*invalid)(ext2_filsys fs,
900 blk_t blk,
901 char *badstr,
902 void *priv_data));
903extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
904 ext2_badblocks_list *bb_list,
905 void (*invalid)(ext2_filsys fs,
906 blk_t blk));
907
908/* res_gdt.c */
909extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
910
911/* rs_bitmap.c */
912extern errcode_t ext2fs_resize_generic_bitmap(__u32 new_end,
913 __u32 new_real_end,
914 ext2fs_generic_bitmap bmap);
915extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
916 ext2fs_inode_bitmap bmap);
917extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
918 ext2fs_block_bitmap bmap);
919extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
920 ext2fs_generic_bitmap *dest);
921
922/* swapfs.c */
923extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize,
924 int has_header);
925extern void ext2fs_swap_super(struct ext2_super_block * super);
926extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp);
927extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
928 struct ext2_inode_large *f, int hostorder,
929 int bufsize);
930extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
931 struct ext2_inode *f, int hostorder);
932
933/* valid_blk.c */
934extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
935
936/* version.c */
937extern int ext2fs_parse_version_string(const char *ver_string);
938extern int ext2fs_get_library_version(const char **ver_string,
939 const char **date_string);
940
941/* write_bb_file.c */
942extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
943 unsigned int flags,
944 FILE *f);
945
946
947/* inline functions */
948extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr);
949extern errcode_t ext2fs_free_mem(void *ptr);
950extern errcode_t ext2fs_resize_mem(unsigned long old_size,
951 unsigned long size, void *ptr);
952extern void ext2fs_mark_super_dirty(ext2_filsys fs);
953extern void ext2fs_mark_changed(ext2_filsys fs);
954extern int ext2fs_test_changed(ext2_filsys fs);
955extern void ext2fs_mark_valid(ext2_filsys fs);
956extern void ext2fs_unmark_valid(ext2_filsys fs);
957extern int ext2fs_test_valid(ext2_filsys fs);
958extern void ext2fs_mark_ib_dirty(ext2_filsys fs);
959extern void ext2fs_mark_bb_dirty(ext2_filsys fs);
960extern int ext2fs_test_ib_dirty(ext2_filsys fs);
961extern int ext2fs_test_bb_dirty(ext2_filsys fs);
962extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
963extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
964extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
965 struct ext2_inode *inode);
966
967/*
968 * The actual inlined functions definitions themselves...
969 *
970 * If NO_INLINE_FUNCS is defined, then we won't try to do inline
971 * functions at all!
972 */
973#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
974#ifdef INCLUDE_INLINE_FUNCS
975#define _INLINE_ extern
976#else
977#ifdef __GNUC__
978#define _INLINE_ extern __inline__
979#else /* For Watcom C */
980#define _INLINE_ extern inline
981#endif
982#endif
983
984#ifndef EXT2_CUSTOM_MEMORY_ROUTINES
985/*
986 * Allocate memory
987 */
988_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
989{
990 void **pp = (void **)ptr;
991
992 *pp = malloc(size);
993 if (!*pp)
994 return EXT2_ET_NO_MEMORY;
995 return 0;
996}
997
998/*
999 * Free memory
1000 */
1001_INLINE_ errcode_t ext2fs_free_mem(void *ptr)
1002{
1003 void **pp = (void **)ptr;
1004
1005 free(*pp);
1006 *pp = 0;
1007 return 0;
1008}
1009
1010/*
1011 * Resize memory
1012 */
1013_INLINE_ errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size,
1014 unsigned long size, void *ptr)
1015{
1016 void *p;
1017 void **pp = (void **)ptr;
1018
1019 p = realloc(*pp, size);
1020 if (!p)
1021 return EXT2_ET_NO_MEMORY;
1022 *pp = p;
1023 return 0;
1024}
1025#endif /* Custom memory routines */
1026
1027/*
1028 * Mark a filesystem superblock as dirty
1029 */
1030_INLINE_ void ext2fs_mark_super_dirty(ext2_filsys fs)
1031{
1032 fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_CHANGED;
1033}
1034
1035/*
1036 * Mark a filesystem as changed
1037 */
1038_INLINE_ void ext2fs_mark_changed(ext2_filsys fs)
1039{
1040 fs->flags |= EXT2_FLAG_CHANGED;
1041}
1042
1043/*
1044 * Check to see if a filesystem has changed
1045 */
1046_INLINE_ int ext2fs_test_changed(ext2_filsys fs)
1047{
1048 return (fs->flags & EXT2_FLAG_CHANGED);
1049}
1050
1051/*
1052 * Mark a filesystem as valid
1053 */
1054_INLINE_ void ext2fs_mark_valid(ext2_filsys fs)
1055{
1056 fs->flags |= EXT2_FLAG_VALID;
1057}
1058
1059/*
1060 * Mark a filesystem as NOT valid
1061 */
1062_INLINE_ void ext2fs_unmark_valid(ext2_filsys fs)
1063{
1064 fs->flags &= ~EXT2_FLAG_VALID;
1065}
1066
1067/*
1068 * Check to see if a filesystem is valid
1069 */
1070_INLINE_ int ext2fs_test_valid(ext2_filsys fs)
1071{
1072 return (fs->flags & EXT2_FLAG_VALID);
1073}
1074
1075/*
1076 * Mark the inode bitmap as dirty
1077 */
1078_INLINE_ void ext2fs_mark_ib_dirty(ext2_filsys fs)
1079{
1080 fs->flags |= EXT2_FLAG_IB_DIRTY | EXT2_FLAG_CHANGED;
1081}
1082
1083/*
1084 * Mark the block bitmap as dirty
1085 */
1086_INLINE_ void ext2fs_mark_bb_dirty(ext2_filsys fs)
1087{
1088 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_CHANGED;
1089}
1090
1091/*
1092 * Check to see if a filesystem's inode bitmap is dirty
1093 */
1094_INLINE_ int ext2fs_test_ib_dirty(ext2_filsys fs)
1095{
1096 return (fs->flags & EXT2_FLAG_IB_DIRTY);
1097}
1098
1099/*
1100 * Check to see if a filesystem's block bitmap is dirty
1101 */
1102_INLINE_ int ext2fs_test_bb_dirty(ext2_filsys fs)
1103{
1104 return (fs->flags & EXT2_FLAG_BB_DIRTY);
1105}
1106
1107/*
1108 * Return the group # of a block
1109 */
1110_INLINE_ int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk)
1111{
1112 return (blk - fs->super->s_first_data_block) /
1113 fs->super->s_blocks_per_group;
1114}
1115
1116/*
1117 * Return the group # of an inode number
1118 */
1119_INLINE_ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
1120{
1121 return (ino - 1) / fs->super->s_inodes_per_group;
1122}
1123
1124_INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
1125 struct ext2_inode *inode)
1126{
1127 return inode->i_blocks -
1128 (inode->i_file_acl ? fs->blocksize >> 9 : 0);
1129}
1130#undef _INLINE_
1131#endif
1132
1133#ifdef __cplusplus
1134}
1135#endif
1136
1137#endif /* _EXT2FS_EXT2FS_H */
diff --git a/e2fsprogs/ext2fs/ext2fsP.h b/e2fsprogs/ext2fs/ext2fsP.h
new file mode 100644
index 000000000..eea32d632
--- /dev/null
+++ b/e2fsprogs/ext2fs/ext2fsP.h
@@ -0,0 +1,88 @@
1/*
2 * ext2fsP.h --- private header file for ext2 library
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include "ext2fs.h"
13
14/*
15 * Badblocks list
16 */
17struct ext2_struct_u32_list {
18 int magic;
19 int num;
20 int size;
21 __u32 *list;
22 int badblocks_flags;
23};
24
25struct ext2_struct_u32_iterate {
26 int magic;
27 ext2_u32_list bb;
28 int ptr;
29};
30
31
32/*
33 * Directory block iterator definition
34 */
35struct ext2_struct_dblist {
36 int magic;
37 ext2_filsys fs;
38 ext2_ino_t size;
39 ext2_ino_t count;
40 int sorted;
41 struct ext2_db_entry * list;
42};
43
44/*
45 * For directory iterators
46 */
47struct dir_context {
48 ext2_ino_t dir;
49 int flags;
50 char *buf;
51 int (*func)(ext2_ino_t dir,
52 int entry,
53 struct ext2_dir_entry *dirent,
54 int offset,
55 int blocksize,
56 char *buf,
57 void *priv_data);
58 void *priv_data;
59 errcode_t errcode;
60};
61
62/*
63 * Inode cache structure
64 */
65struct ext2_inode_cache {
66 void * buffer;
67 blk_t buffer_blk;
68 int cache_last;
69 int cache_size;
70 int refcount;
71 struct ext2_inode_cache_ent *cache;
72};
73
74struct ext2_inode_cache_ent {
75 ext2_ino_t ino;
76 struct ext2_inode inode;
77};
78
79/* Function prototypes */
80
81extern int ext2fs_process_dir_block(ext2_filsys fs,
82 blk_t *blocknr,
83 e2_blkcnt_t blockcnt,
84 blk_t ref_block,
85 int ref_offset,
86 void *priv_data);
87
88
diff --git a/e2fsprogs/ext2fs/ext_attr.c b/e2fsprogs/ext2fs/ext_attr.c
new file mode 100644
index 000000000..08211c316
--- /dev/null
+++ b/e2fsprogs/ext2fs/ext_attr.c
@@ -0,0 +1,105 @@
1/*
2 * ext_attr.c --- extended attribute blocks
3 *
4 * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
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#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 "ext2_ext_attr.h"
23
24#include "ext2fs.h"
25
26errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
27{
28 errcode_t retval;
29
30 retval = io_channel_read_blk(fs->io, block, 1, buf);
31 if (retval)
32 return retval;
33#ifdef EXT2FS_ENABLE_SWAPFS
34 if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
35 EXT2_FLAG_SWAP_BYTES_READ)) != 0)
36 ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
37#endif
38 return 0;
39}
40
41errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
42{
43 errcode_t retval;
44 char *write_buf;
45 char *buf = NULL;
46
47#ifdef EXT2FS_ENABLE_SWAPFS
48 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
49 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
50 retval = ext2fs_get_mem(fs->blocksize, &buf);
51 if (retval)
52 return retval;
53 write_buf = buf;
54 ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
55 } else
56#endif
57 write_buf = (char *) inbuf;
58 retval = io_channel_write_blk(fs->io, block, 1, write_buf);
59 if (buf)
60 ext2fs_free_mem(&buf);
61 if (!retval)
62 ext2fs_mark_changed(fs);
63 return retval;
64}
65
66/*
67 * This function adjusts the reference count of the EA block.
68 */
69errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
70 char *block_buf, int adjust,
71 __u32 *newcount)
72{
73 errcode_t retval;
74 struct ext2_ext_attr_header *header;
75 char *buf = 0;
76
77 if ((blk >= fs->super->s_blocks_count) ||
78 (blk < fs->super->s_first_data_block))
79 return EXT2_ET_BAD_EA_BLOCK_NUM;
80
81 if (!block_buf) {
82 retval = ext2fs_get_mem(fs->blocksize, &buf);
83 if (retval)
84 return retval;
85 block_buf = buf;
86 }
87
88 retval = ext2fs_read_ext_attr(fs, blk, block_buf);
89 if (retval)
90 goto errout;
91
92 header = (struct ext2_ext_attr_header *) block_buf;
93 header->h_refcount += adjust;
94 if (newcount)
95 *newcount = header->h_refcount;
96
97 retval = ext2fs_write_ext_attr(fs, blk, block_buf);
98 if (retval)
99 goto errout;
100
101errout:
102 if (buf)
103 ext2fs_free_mem(&buf);
104 return retval;
105}
diff --git a/e2fsprogs/ext2fs/fileio.c b/e2fsprogs/ext2fs/fileio.c
new file mode 100644
index 000000000..3e42cbc32
--- /dev/null
+++ b/e2fsprogs/ext2fs/fileio.c
@@ -0,0 +1,378 @@
1/*
2 * fileio.c --- Simple file I/O routines
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21struct ext2_file {
22 errcode_t magic;
23 ext2_filsys fs;
24 ext2_ino_t ino;
25 struct ext2_inode inode;
26 int flags;
27 __u64 pos;
28 blk_t blockno;
29 blk_t physblock;
30 char *buf;
31};
32
33#define BMAP_BUFFER (file->buf + fs->blocksize)
34
35errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
36 struct ext2_inode *inode,
37 int flags, ext2_file_t *ret)
38{
39 ext2_file_t file;
40 errcode_t retval;
41
42 /*
43 * Don't let caller create or open a file for writing if the
44 * filesystem is read-only.
45 */
46 if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
47 !(fs->flags & EXT2_FLAG_RW))
48 return EXT2_ET_RO_FILSYS;
49
50 retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
51 if (retval)
52 return retval;
53
54 memset(file, 0, sizeof(struct ext2_file));
55 file->magic = EXT2_ET_MAGIC_EXT2_FILE;
56 file->fs = fs;
57 file->ino = ino;
58 file->flags = flags & EXT2_FILE_MASK;
59
60 if (inode) {
61 memcpy(&file->inode, inode, sizeof(struct ext2_inode));
62 } else {
63 retval = ext2fs_read_inode(fs, ino, &file->inode);
64 if (retval)
65 goto fail;
66 }
67
68 retval = ext2fs_get_mem(fs->blocksize * 3, &file->buf);
69 if (retval)
70 goto fail;
71
72 *ret = file;
73 return 0;
74
75fail:
76 if (file->buf)
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 if (file->buf)
201 ext2fs_free_mem(&file->buf);
202 ext2fs_free_mem(&file);
203
204 return retval;
205}
206
207
208errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
209 unsigned int wanted, unsigned int *got)
210{
211 ext2_filsys fs;
212 errcode_t retval = 0;
213 unsigned int start, c, count = 0;
214 __u64 left;
215 char *ptr = (char *) buf;
216
217 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
218 fs = file->fs;
219
220 while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
221 retval = sync_buffer_position(file);
222 if (retval)
223 goto fail;
224 retval = load_buffer(file, 0);
225 if (retval)
226 goto fail;
227
228 start = file->pos % fs->blocksize;
229 c = fs->blocksize - start;
230 if (c > wanted)
231 c = wanted;
232 left = EXT2_I_SIZE(&file->inode) - file->pos ;
233 if (c > left)
234 c = left;
235
236 memcpy(ptr, file->buf+start, c);
237 file->pos += c;
238 ptr += c;
239 count += c;
240 wanted -= c;
241 }
242
243fail:
244 if (got)
245 *got = count;
246 return retval;
247}
248
249
250errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
251 unsigned int nbytes, unsigned int *written)
252{
253 ext2_filsys fs;
254 errcode_t retval = 0;
255 unsigned int start, c, count = 0;
256 const char *ptr = (const char *) buf;
257
258 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
259 fs = file->fs;
260
261 if (!(file->flags & EXT2_FILE_WRITE))
262 return EXT2_ET_FILE_RO;
263
264 while (nbytes > 0) {
265 retval = sync_buffer_position(file);
266 if (retval)
267 goto fail;
268
269 start = file->pos % fs->blocksize;
270 c = fs->blocksize - start;
271 if (c > nbytes)
272 c = nbytes;
273
274 /*
275 * We only need to do a read-modify-update cycle if
276 * we're doing a partial write.
277 */
278 retval = load_buffer(file, (c == fs->blocksize));
279 if (retval)
280 goto fail;
281
282 file->flags |= EXT2_FILE_BUF_DIRTY;
283 memcpy(file->buf+start, ptr, c);
284 file->pos += c;
285 ptr += c;
286 count += c;
287 nbytes -= c;
288 }
289
290fail:
291 if (written)
292 *written = count;
293 return retval;
294}
295
296errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
297 int whence, __u64 *ret_pos)
298{
299 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
300
301 if (whence == EXT2_SEEK_SET)
302 file->pos = offset;
303 else if (whence == EXT2_SEEK_CUR)
304 file->pos += offset;
305 else if (whence == EXT2_SEEK_END)
306 file->pos = EXT2_I_SIZE(&file->inode) + offset;
307 else
308 return EXT2_ET_INVALID_ARGUMENT;
309
310 if (ret_pos)
311 *ret_pos = file->pos;
312
313 return 0;
314}
315
316errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
317 int whence, ext2_off_t *ret_pos)
318{
319 __u64 loffset, ret_loffset;
320 errcode_t retval;
321
322 loffset = offset;
323 retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset);
324 if (ret_pos)
325 *ret_pos = (ext2_off_t) ret_loffset;
326 return retval;
327}
328
329
330/*
331 * This function returns the size of the file, according to the inode
332 */
333errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size)
334{
335 if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
336 return EXT2_ET_MAGIC_EXT2_FILE;
337 *ret_size = EXT2_I_SIZE(&file->inode);
338 return 0;
339}
340
341/*
342 * This function returns the size of the file, according to the inode
343 */
344ext2_off_t ext2fs_file_get_size(ext2_file_t file)
345{
346 __u64 size;
347
348 if (ext2fs_file_get_lsize(file, &size))
349 return 0;
350 if ((size >> 32) != 0)
351 return 0;
352 return size;
353}
354
355/*
356 * This function sets the size of the file, truncating it if necessary
357 *
358 * XXX still need to call truncate
359 */
360errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
361{
362 errcode_t retval;
363 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
364
365 file->inode.i_size = size;
366 file->inode.i_size_high = 0;
367 if (file->ino) {
368 retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
369 if (retval)
370 return retval;
371 }
372
373 /*
374 * XXX truncate inode if necessary
375 */
376
377 return 0;
378}
diff --git a/e2fsprogs/ext2fs/finddev.c b/e2fsprogs/ext2fs/finddev.c
new file mode 100644
index 000000000..fa2cadde4
--- /dev/null
+++ b/e2fsprogs/ext2fs/finddev.c
@@ -0,0 +1,208 @@
1/*
2 * finddev.c -- this routine attempts to find a particular device in
3 * /dev
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#include <stdlib.h>
19#include <string.h>
20#if HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#if HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#include <dirent.h>
27#if HAVE_ERRNO_H
28#include <errno.h>
29#endif
30#if HAVE_SYS_MKDEV_H
31#include <sys/mkdev.h>
32#endif
33
34#include "ext2_fs.h"
35#include "ext2fs.h"
36
37struct dir_list {
38 char *name;
39 struct dir_list *next;
40};
41
42/*
43 * This function adds an entry to the directory list
44 */
45static void add_to_dirlist(const char *name, struct dir_list **list)
46{
47 struct dir_list *dp;
48
49 dp = malloc(sizeof(struct dir_list));
50 if (!dp)
51 return;
52 dp->name = malloc(strlen(name)+1);
53 if (!dp->name) {
54 free(dp);
55 return;
56 }
57 strcpy(dp->name, name);
58 dp->next = *list;
59 *list = dp;
60}
61
62/*
63 * This function frees a directory list
64 */
65static void free_dirlist(struct dir_list **list)
66{
67 struct dir_list *dp, *next;
68
69 for (dp = *list; dp; dp = next) {
70 next = dp->next;
71 free(dp->name);
72 free(dp);
73 }
74 *list = 0;
75}
76
77static int scan_dir(char *dir_name, dev_t device, struct dir_list **list,
78 char **ret_path)
79{
80 DIR *dir;
81 struct dirent *dp;
82 char path[1024], *cp;
83 int dirlen;
84 struct stat st;
85
86 dirlen = strlen(dir_name);
87 if ((dir = opendir(dir_name)) == NULL)
88 return errno;
89 dp = readdir(dir);
90 while (dp) {
91 if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path))
92 goto skip_to_next;
93 if (dp->d_name[0] == '.' &&
94 ((dp->d_name[1] == 0) ||
95 ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
96 goto skip_to_next;
97 sprintf(path, "%s/%s", dir_name, dp->d_name);
98 if (stat(path, &st) < 0)
99 goto skip_to_next;
100 if (S_ISDIR(st.st_mode))
101 add_to_dirlist(path, list);
102 if (S_ISBLK(st.st_mode) && st.st_rdev == device) {
103 cp = malloc(strlen(path)+1);
104 if (!cp) {
105 closedir(dir);
106 return ENOMEM;
107 }
108 strcpy(cp, path);
109 *ret_path = cp;
110 goto success;
111 }
112 skip_to_next:
113 dp = readdir(dir);
114 }
115success:
116 closedir(dir);
117 return 0;
118}
119
120/*
121 * This function finds the pathname to a block device with a given
122 * device number. It returns a pointer to allocated memory to the
123 * pathname on success, and NULL on failure.
124 */
125char *ext2fs_find_block_device(dev_t device)
126{
127 struct dir_list *list = 0, *new_list = 0;
128 struct dir_list *current;
129 char *ret_path = 0;
130
131 /*
132 * Add the starting directories to search...
133 */
134 add_to_dirlist("/devices", &list);
135 add_to_dirlist("/devfs", &list);
136 add_to_dirlist("/dev", &list);
137
138 while (list) {
139 current = list;
140 list = list->next;
141#ifdef DEBUG
142 printf("Scanning directory %s\n", current->name);
143#endif
144 scan_dir(current->name, device, &new_list, &ret_path);
145 free(current->name);
146 free(current);
147 if (ret_path)
148 break;
149 /*
150 * If we're done checking at this level, descend to
151 * the next level of subdirectories. (breadth-first)
152 */
153 if (list == 0) {
154 list = new_list;
155 new_list = 0;
156 }
157 }
158 free_dirlist(&list);
159 free_dirlist(&new_list);
160 return ret_path;
161}
162
163
164#ifdef DEBUG
165int main(int argc, char** argv)
166{
167 char *devname, *tmp;
168 int major, minor;
169 dev_t device;
170 const char *errmsg = "Couldn't parse %s: %s\n";
171
172 if ((argc != 2) && (argc != 3)) {
173 fprintf(stderr, "Usage: %s device_number\n", argv[0]);
174 fprintf(stderr, "\t: %s major minor\n", argv[0]);
175 exit(1);
176 }
177 if (argc == 2) {
178 device = strtoul(argv[1], &tmp, 0);
179 if (*tmp) {
180 fprintf(stderr, errmsg, "device number", argv[1]);
181 exit(1);
182 }
183 } else {
184 major = strtoul(argv[1], &tmp, 0);
185 if (*tmp) {
186 fprintf(stderr, errmsg, "major number", argv[1]);
187 exit(1);
188 }
189 minor = strtoul(argv[2], &tmp, 0);
190 if (*tmp) {
191 fprintf(stderr, errmsg, "minor number", argv[2]);
192 exit(1);
193 }
194 device = makedev(major, minor);
195 printf("Looking for device 0x%04x (%d:%d)\n", device,
196 major, minor);
197 }
198 devname = ext2fs_find_block_device(device);
199 if (devname) {
200 printf("Found device! %s\n", devname);
201 free(devname);
202 } else {
203 printf("Couldn't find device.\n");
204 }
205 return 0;
206}
207
208#endif
diff --git a/e2fsprogs/ext2fs/flushb.c b/e2fsprogs/ext2fs/flushb.c
new file mode 100644
index 000000000..18827955f
--- /dev/null
+++ b/e2fsprogs/ext2fs/flushb.c
@@ -0,0 +1,82 @@
1/*
2 * flushb.c --- Hides system-dependent information for both syncing a
3 * device to disk and to flush any buffers from disk cache.
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#if HAVE_ERRNO_H
15#include <errno.h>
16#endif
17#if HAVE_UNISTD_H
18#include <unistd.h>
19#endif
20#if HAVE_SYS_IOCTL_H
21#include <sys/ioctl.h>
22#endif
23#if HAVE_SYS_MOUNT_H
24#include <sys/param.h>
25#include <sys/mount.h> /* This may define BLKFLSBUF */
26#endif
27
28#include "ext2_fs.h"
29#include "ext2fs.h"
30
31/*
32 * For Linux, define BLKFLSBUF and FDFLUSH if necessary, since
33 * not all portable header file does so for us. This really should be
34 * fixed in the glibc header files. (Recent glibcs appear to define
35 * BLKFLSBUF in sys/mount.h, but FDFLUSH still doesn't seem to be
36 * defined anywhere portable.) Until then....
37 */
38#ifdef __linux__
39#ifndef BLKFLSBUF
40#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
41#endif
42#ifndef FDFLUSH
43#define FDFLUSH _IO(2,0x4b) /* flush floppy disk */
44#endif
45#endif
46
47/*
48 * This function will sync a device/file, and optionally attempt to
49 * flush the buffer cache. The latter is basically only useful for
50 * system benchmarks and for torturing systems in burn-in tests. :)
51 */
52errcode_t ext2fs_sync_device(int fd, int flushb)
53{
54 /*
55 * We always sync the device in case we're running on old
56 * kernels for which we can lose data if we don't. (There
57 * still is a race condition for those kernels, but this
58 * reduces it greatly.)
59 */
60 if (fsync (fd) == -1)
61 return errno;
62
63 if (flushb) {
64
65#ifdef BLKFLSBUF
66 if (ioctl (fd, BLKFLSBUF, 0) == 0)
67 return 0;
68#else
69#ifdef __GNUC__
70 #warning BLKFLSBUF not defined
71#endif /* __GNUC__ */
72#endif
73#ifdef FDFLUSH
74 ioctl (fd, FDFLUSH, 0); /* In case this is a floppy */
75#else
76#ifdef __GNUC__
77 #warning FDFLUSH not defined
78#endif /* __GNUC__ */
79#endif
80 }
81 return 0;
82}
diff --git a/e2fsprogs/ext2fs/freefs.c b/e2fsprogs/ext2fs/freefs.c
new file mode 100644
index 000000000..029ffaae1
--- /dev/null
+++ b/e2fsprogs/ext2fs/freefs.c
@@ -0,0 +1,147 @@
1/*
2 * freefs.c --- free an ext2 filesystem
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#if HAVE_UNISTD_H
14#include <unistd.h>
15#endif
16
17#include "ext2_fs.h"
18#include "ext2fsP.h"
19
20static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
21
22void ext2fs_free(ext2_filsys fs)
23{
24 if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
25 return;
26 if (fs->image_io != fs->io) {
27 if (fs->image_io)
28 io_channel_close(fs->image_io);
29 }
30 if (fs->io) {
31 io_channel_close(fs->io);
32 }
33 if (fs->device_name)
34 ext2fs_free_mem(&fs->device_name);
35 if (fs->super)
36 ext2fs_free_mem(&fs->super);
37 if (fs->orig_super)
38 ext2fs_free_mem(&fs->orig_super);
39 if (fs->group_desc)
40 ext2fs_free_mem(&fs->group_desc);
41 if (fs->block_map)
42 ext2fs_free_block_bitmap(fs->block_map);
43 if (fs->inode_map)
44 ext2fs_free_inode_bitmap(fs->inode_map);
45
46 if (fs->badblocks)
47 ext2fs_badblocks_list_free(fs->badblocks);
48 fs->badblocks = 0;
49
50 if (fs->dblist)
51 ext2fs_free_dblist(fs->dblist);
52
53 if (fs->icache)
54 ext2fs_free_inode_cache(fs->icache);
55
56 fs->magic = 0;
57
58 ext2fs_free_mem(&fs);
59}
60
61void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
62{
63 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_GENERIC_BITMAP))
64 return;
65
66 bitmap->magic = 0;
67 if (bitmap->description) {
68 ext2fs_free_mem(&bitmap->description);
69 bitmap->description = 0;
70 }
71 if (bitmap->bitmap) {
72 ext2fs_free_mem(&bitmap->bitmap);
73 bitmap->bitmap = 0;
74 }
75 ext2fs_free_mem(&bitmap);
76}
77
78void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
79{
80 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
81 return;
82
83 bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
84 ext2fs_free_generic_bitmap(bitmap);
85}
86
87void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
88{
89 if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
90 return;
91
92 bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
93 ext2fs_free_generic_bitmap(bitmap);
94}
95
96/*
97 * Free the inode cache structure
98 */
99static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
100{
101 if (--icache->refcount)
102 return;
103 if (icache->buffer)
104 ext2fs_free_mem(&icache->buffer);
105 if (icache->cache)
106 ext2fs_free_mem(&icache->cache);
107 icache->buffer_blk = 0;
108 ext2fs_free_mem(&icache);
109}
110
111/*
112 * This procedure frees a badblocks list.
113 */
114void ext2fs_u32_list_free(ext2_u32_list bb)
115{
116 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
117 return;
118
119 if (bb->list)
120 ext2fs_free_mem(&bb->list);
121 bb->list = 0;
122 ext2fs_free_mem(&bb);
123}
124
125void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
126{
127 ext2fs_u32_list_free((ext2_u32_list) bb);
128}
129
130
131/*
132 * Free a directory block list
133 */
134void ext2fs_free_dblist(ext2_dblist dblist)
135{
136 if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST))
137 return;
138
139 if (dblist->list)
140 ext2fs_free_mem(&dblist->list);
141 dblist->list = 0;
142 if (dblist->fs && dblist->fs->dblist == dblist)
143 dblist->fs->dblist = 0;
144 dblist->magic = 0;
145 ext2fs_free_mem(&dblist);
146}
147
diff --git a/e2fsprogs/ext2fs/gen_bitmap.c b/e2fsprogs/ext2fs/gen_bitmap.c
new file mode 100644
index 000000000..700affa19
--- /dev/null
+++ b/e2fsprogs/ext2fs/gen_bitmap.c
@@ -0,0 +1,48 @@
1/*
2 * gen_bitmap.c --- Generic bitmap routines that used to be inlined.
3 *
4 * Copyright (C) 2001 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
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
30int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
31 __u32 bitno)
32{
33 if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
34 ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
35 return 0;
36 }
37 return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
38}
39
40int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
41 blk_t bitno)
42{
43 if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
44 ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
45 return 0;
46 }
47 return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
48}
diff --git a/e2fsprogs/ext2fs/get_pathname.c b/e2fsprogs/ext2fs/get_pathname.c
new file mode 100644
index 000000000..23f593f67
--- /dev/null
+++ b/e2fsprogs/ext2fs/get_pathname.c
@@ -0,0 +1,157 @@
1/*
2 * get_pathname.c --- do directry/inode -> name translation
3 *
4 * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 * ext2fs_get_pathname(fs, dir, ino, name)
12 *
13 * This function translates takes two inode numbers into a
14 * string, placing the result in <name>. <dir> is the containing
15 * directory inode, and <ino> is the inode number itself. If
16 * <ino> is zero, then ext2fs_get_pathname will return pathname
17 * of the the directory <dir>.
18 *
19 */
20
21#include <stdio.h>
22#include <string.h>
23#if HAVE_UNISTD_H
24#include <unistd.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fs.h"
29
30struct get_pathname_struct {
31 ext2_ino_t search_ino;
32 ext2_ino_t parent;
33 char *name;
34 errcode_t errcode;
35};
36
37#ifdef __TURBOC__
38 #pragma argsused
39#endif
40static int get_pathname_proc(struct ext2_dir_entry *dirent,
41 int offset EXT2FS_ATTR((unused)),
42 int blocksize EXT2FS_ATTR((unused)),
43 char *buf EXT2FS_ATTR((unused)),
44 void *priv_data)
45{
46 struct get_pathname_struct *gp;
47 errcode_t retval;
48
49 gp = (struct get_pathname_struct *) priv_data;
50
51 if (((dirent->name_len & 0xFF) == 2) &&
52 !strncmp(dirent->name, "..", 2))
53 gp->parent = dirent->inode;
54 if (dirent->inode == gp->search_ino) {
55 retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1,
56 &gp->name);
57 if (retval) {
58 gp->errcode = retval;
59 return DIRENT_ABORT;
60 }
61 strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF));
62 gp->name[dirent->name_len & 0xFF] = '\0';
63 return DIRENT_ABORT;
64 }
65 return 0;
66}
67
68static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir,
69 ext2_ino_t ino, int maxdepth,
70 char *buf, char **name)
71{
72 struct get_pathname_struct gp;
73 char *parent_name, *ret;
74 errcode_t retval;
75
76 if (dir == ino) {
77 retval = ext2fs_get_mem(2, name);
78 if (retval)
79 return retval;
80 strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : ".");
81 return 0;
82 }
83
84 if (!dir || (maxdepth < 0)) {
85 retval = ext2fs_get_mem(4, name);
86 if (retval)
87 return retval;
88 strcpy(*name, "...");
89 return 0;
90 }
91
92 gp.search_ino = ino;
93 gp.parent = 0;
94 gp.name = 0;
95 gp.errcode = 0;
96
97 retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
98 if (retval)
99 goto cleanup;
100 if (gp.errcode) {
101 retval = gp.errcode;
102 goto cleanup;
103 }
104
105 retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1,
106 buf, &parent_name);
107 if (retval)
108 goto cleanup;
109 if (!ino) {
110 *name = parent_name;
111 return 0;
112 }
113
114 if (gp.name)
115 retval = ext2fs_get_mem(strlen(parent_name)+strlen(gp.name)+2,
116 &ret);
117 else
118 retval = ext2fs_get_mem(strlen(parent_name)+5, &ret);
119 if (retval)
120 goto cleanup;
121
122 ret[0] = 0;
123 if (parent_name[1])
124 strcat(ret, parent_name);
125 strcat(ret, "/");
126 if (gp.name)
127 strcat(ret, gp.name);
128 else
129 strcat(ret, "???");
130 *name = ret;
131 ext2fs_free_mem(&parent_name);
132 retval = 0;
133
134cleanup:
135 if (gp.name)
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/ext2fs/getsectsize.c b/e2fsprogs/ext2fs/getsectsize.c
new file mode 100644
index 000000000..77a9e3da7
--- /dev/null
+++ b/e2fsprogs/ext2fs/getsectsize.c
@@ -0,0 +1,57 @@
1/*
2 * getsectsize.c --- get the sector size of a device.
3 *
4 * Copyright (C) 1995, 1995 Theodore Ts'o.
5 * Copyright (C) 2003 VMware, Inc.
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 <sys/ioctl.h>
23#include <linux/fd.h>
24#endif
25
26#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
27#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
28#endif
29
30#include "ext2_fs.h"
31#include "ext2fs.h"
32
33/*
34 * Returns the number of blocks in a partition
35 */
36errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize)
37{
38 int fd;
39
40#ifdef CONFIG_LFS
41 fd = open64(file, O_RDONLY);
42#else
43 fd = open(file, O_RDONLY);
44#endif
45 if (fd < 0)
46 return errno;
47
48#ifdef BLKSSZGET
49 if (ioctl(fd, BLKSSZGET, sectsize) >= 0) {
50 close(fd);
51 return 0;
52 }
53#endif
54 *sectsize = 0;
55 close(fd);
56 return 0;
57}
diff --git a/e2fsprogs/ext2fs/getsize.c b/e2fsprogs/ext2fs/getsize.c
new file mode 100644
index 000000000..036d9260c
--- /dev/null
+++ b/e2fsprogs/ext2fs/getsize.c
@@ -0,0 +1,290 @@
1/*
2 * getsize.c --- get the size of a partition.
3 *
4 * Copyright (C) 1995, 1995 Theodore Ts'o.
5 * Copyright (C) 2003 VMware, Inc.
6 *
7 * Windows version of ext2fs_get_device_size by Chris Li, VMware.
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#if HAVE_UNISTD_H
17#include <unistd.h>
18#endif
19#if HAVE_ERRNO_H
20#include <errno.h>
21#endif
22#include <fcntl.h>
23#ifdef HAVE_SYS_IOCTL_H
24#include <sys/ioctl.h>
25#endif
26#ifdef HAVE_LINUX_FD_H
27#include <linux/fd.h>
28#endif
29#ifdef HAVE_SYS_DISKLABEL_H
30#include <sys/disklabel.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
54#include "ext2_fs.h"
55#include "ext2fs.h"
56
57#if defined(__CYGWIN__) || defined (WIN32)
58#include "windows.h"
59#include "winioctl.h"
60
61#if (_WIN32_WINNT >= 0x0500)
62#define HAVE_GET_FILE_SIZE_EX 1
63#endif
64
65errcode_t ext2fs_get_device_size(const char *file, int blocksize,
66 blk_t *retblocks)
67{
68 HANDLE dev;
69 PARTITION_INFORMATION pi;
70 DISK_GEOMETRY gi;
71 DWORD retbytes;
72#ifdef HAVE_GET_FILE_SIZE_EX
73 LARGE_INTEGER filesize;
74#else
75 DWORD filesize;
76#endif /* HAVE_GET_FILE_SIZE_EX */
77
78 dev = CreateFile(file, GENERIC_READ,
79 FILE_SHARE_READ | FILE_SHARE_WRITE ,
80 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
81
82 if (dev == INVALID_HANDLE_VALUE)
83 return EBADF;
84 if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO,
85 &pi, sizeof(PARTITION_INFORMATION),
86 &pi, sizeof(PARTITION_INFORMATION),
87 &retbytes, NULL)) {
88
89 *retblocks = pi.PartitionLength.QuadPart / blocksize;
90
91 } else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY,
92 &gi, sizeof(DISK_GEOMETRY),
93 &gi, sizeof(DISK_GEOMETRY),
94 &retbytes, NULL)) {
95
96 *retblocks = gi.BytesPerSector *
97 gi.SectorsPerTrack *
98 gi.TracksPerCylinder *
99 gi.Cylinders.QuadPart / blocksize;
100
101#ifdef HAVE_GET_FILE_SIZE_EX
102 } else if (GetFileSizeEx(dev, &filesize)) {
103 *retblocks = filesize.QuadPart / blocksize;
104 }
105#else
106 } else {
107 filesize = GetFileSize(dev, NULL);
108 if (INVALID_FILE_SIZE != filesize) {
109 *retblocks = filesize / blocksize;
110 }
111 }
112#endif /* HAVE_GET_FILE_SIZE_EX */
113
114 CloseHandle(dev);
115 return 0;
116}
117
118#else
119
120static int valid_offset (int fd, ext2_loff_t offset)
121{
122 char ch;
123
124 if (ext2fs_llseek (fd, offset, 0) < 0)
125 return 0;
126 if (read (fd, &ch, 1) < 1)
127 return 0;
128 return 1;
129}
130
131/*
132 * Returns the number of blocks in a partition
133 */
134errcode_t ext2fs_get_device_size(const char *file, int blocksize,
135 blk_t *retblocks)
136{
137 int fd;
138 int valid_blkgetsize64 = 1;
139#ifdef __linux__
140 struct utsname ut;
141#endif
142 unsigned long long size64;
143 unsigned long size;
144 ext2_loff_t high, low;
145#ifdef FDGETPRM
146 struct floppy_struct this_floppy;
147#endif
148#ifdef HAVE_SYS_DISKLABEL_H
149 int part;
150 struct disklabel lab;
151 struct partition *pp;
152 char ch;
153#endif /* HAVE_SYS_DISKLABEL_H */
154
155#ifdef CONFIG_LFS
156 fd = open64(file, O_RDONLY);
157#else
158 fd = open(file, O_RDONLY);
159#endif
160 if (fd < 0)
161 return errno;
162
163#ifdef DKIOCGETBLOCKCOUNT /* For Apple Darwin */
164 if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
165 if ((sizeof(*retblocks) < sizeof(unsigned long long))
166 && ((size64 / (blocksize / 512)) > 0xFFFFFFFF))
167 return EFBIG;
168 close(fd);
169 *retblocks = size64 / (blocksize / 512);
170 return 0;
171 }
172#endif
173
174#ifdef BLKGETSIZE64
175#ifdef __linux__
176 if ((uname(&ut) == 0) &&
177 ((ut.release[0] == '2') && (ut.release[1] == '.') &&
178 (ut.release[2] < '6') && (ut.release[3] == '.')))
179 valid_blkgetsize64 = 0;
180#endif
181 if (valid_blkgetsize64 &&
182 ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
183 if ((sizeof(*retblocks) < sizeof(unsigned long long))
184 && ((size64 / blocksize) > 0xFFFFFFFF))
185 return EFBIG;
186 close(fd);
187 *retblocks = size64 / blocksize;
188 return 0;
189 }
190#endif
191
192#ifdef BLKGETSIZE
193 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
194 close(fd);
195 *retblocks = size / (blocksize / 512);
196 return 0;
197 }
198#endif
199
200#ifdef FDGETPRM
201 if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
202 close(fd);
203 *retblocks = this_floppy.size / (blocksize / 512);
204 return 0;
205 }
206#endif
207
208#ifdef HAVE_SYS_DISKLABEL_H
209#if defined(DIOCGMEDIASIZE)
210 {
211 off_t ms;
212 u_int bs;
213 if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
214 *retblocks = ms / blocksize;
215 return 0;
216 }
217 }
218#elif defined(DIOCGDINFO)
219 /* old disklabel interface */
220 part = strlen(file) - 1;
221 if (part >= 0) {
222 ch = file[part];
223 if (isdigit(ch))
224 part = 0;
225 else if (ch >= 'a' && ch <= 'h')
226 part = ch - 'a';
227 else
228 part = -1;
229 }
230 if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
231 pp = &lab.d_partitions[part];
232 if (pp->p_size) {
233 close(fd);
234 *retblocks = pp->p_size / (blocksize / 512);
235 return 0;
236 }
237 }
238#endif /* defined(DIOCG*) */
239#endif /* HAVE_SYS_DISKLABEL_H */
240
241 /*
242 * OK, we couldn't figure it out by using a specialized ioctl,
243 * which is generally the best way. So do binary search to
244 * find the size of the partition.
245 */
246 low = 0;
247 for (high = 1024; valid_offset (fd, high); high *= 2)
248 low = high;
249 while (low < high - 1)
250 {
251 const ext2_loff_t mid = (low + high) / 2;
252
253 if (valid_offset (fd, mid))
254 low = mid;
255 else
256 high = mid;
257 }
258 valid_offset (fd, 0);
259 close(fd);
260 size64 = low + 1;
261 if ((sizeof(*retblocks) < sizeof(unsigned long long))
262 && ((size64 / blocksize) > 0xFFFFFFFF))
263 return EFBIG;
264 *retblocks = size64 / blocksize;
265 return 0;
266}
267
268#endif /* WIN32 */
269
270#ifdef DEBUG
271int main(int argc, char **argv)
272{
273 blk_t blocks;
274 int retval;
275
276 if (argc < 2) {
277 fprintf(stderr, "Usage: %s device\n", argv[0]);
278 exit(1);
279 }
280
281 retval = ext2fs_get_device_size(argv[1], 1024, &blocks);
282 if (retval) {
283 com_err(argv[0], retval,
284 "while calling ext2fs_get_device_size");
285 exit(1);
286 }
287 printf("Device %s has %d 1k blocks.\n", argv[1], blocks);
288 exit(0);
289}
290#endif
diff --git a/e2fsprogs/ext2fs/icount.c b/e2fsprogs/ext2fs/icount.c
new file mode 100644
index 000000000..59977928b
--- /dev/null
+++ b/e2fsprogs/ext2fs/icount.c
@@ -0,0 +1,483 @@
1/*
2 * icount.c --- an efficient inode count abstraction
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#if HAVE_UNISTD_H
13#include <unistd.h>
14#endif
15#include <string.h>
16#include <stdio.h>
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21/*
22 * The data storage strategy used by icount relies on the observation
23 * that most inode counts are either zero (for non-allocated inodes),
24 * one (for most files), and only a few that are two or more
25 * (directories and files that are linked to more than one directory).
26 *
27 * Also, e2fsck tends to load the icount data sequentially.
28 *
29 * So, we use an inode bitmap to indicate which inodes have a count of
30 * one, and then use a sorted list to store the counts for inodes
31 * which are greater than one.
32 *
33 * We also use an optional bitmap to indicate which inodes are already
34 * in the sorted list, to speed up the use of this abstraction by
35 * e2fsck's pass 2. Pass 2 increments inode counts as it finds them,
36 * so this extra bitmap avoids searching the sorted list to see if a
37 * particular inode is on the sorted list already.
38 */
39
40struct ext2_icount_el {
41 ext2_ino_t ino;
42 __u16 count;
43};
44
45struct ext2_icount {
46 errcode_t magic;
47 ext2fs_inode_bitmap single;
48 ext2fs_inode_bitmap multiple;
49 ext2_ino_t count;
50 ext2_ino_t size;
51 ext2_ino_t num_inodes;
52 ext2_ino_t cursor;
53 struct ext2_icount_el *list;
54};
55
56void ext2fs_free_icount(ext2_icount_t icount)
57{
58 if (!icount)
59 return;
60
61 icount->magic = 0;
62 if (icount->list)
63 ext2fs_free_mem(&icount->list);
64 if (icount->single)
65 ext2fs_free_inode_bitmap(icount->single);
66 if (icount->multiple)
67 ext2fs_free_inode_bitmap(icount->multiple);
68 ext2fs_free_mem(&icount);
69}
70
71errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
72 ext2_icount_t hint, ext2_icount_t *ret)
73{
74 ext2_icount_t icount;
75 errcode_t retval;
76 size_t bytes;
77 ext2_ino_t i;
78
79 if (hint) {
80 EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT);
81 if (hint->size > size)
82 size = (size_t) hint->size;
83 }
84
85 retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount);
86 if (retval)
87 return retval;
88 memset(icount, 0, sizeof(struct ext2_icount));
89
90 retval = ext2fs_allocate_inode_bitmap(fs, 0,
91 &icount->single);
92 if (retval)
93 goto errout;
94
95 if (flags & EXT2_ICOUNT_OPT_INCREMENT) {
96 retval = ext2fs_allocate_inode_bitmap(fs, 0,
97 &icount->multiple);
98 if (retval)
99 goto errout;
100 } else
101 icount->multiple = 0;
102
103 if (size) {
104 icount->size = size;
105 } else {
106 /*
107 * Figure out how many special case inode counts we will
108 * have. We know we will need one for each directory;
109 * we also need to reserve some extra room for file links
110 */
111 retval = ext2fs_get_num_dirs(fs, &icount->size);
112 if (retval)
113 goto errout;
114 icount->size += fs->super->s_inodes_count / 50;
115 }
116
117 bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
118#if 0
119 printf("Icount allocated %d entries, %d bytes.\n",
120 icount->size, bytes);
121#endif
122 retval = ext2fs_get_mem(bytes, &icount->list);
123 if (retval)
124 goto errout;
125 memset(icount->list, 0, bytes);
126
127 icount->magic = EXT2_ET_MAGIC_ICOUNT;
128 icount->count = 0;
129 icount->cursor = 0;
130 icount->num_inodes = fs->super->s_inodes_count;
131
132 /*
133 * Populate the sorted list with those entries which were
134 * found in the hint icount (since those are ones which will
135 * likely need to be in the sorted list this time around).
136 */
137 if (hint) {
138 for (i=0; i < hint->count; i++)
139 icount->list[i].ino = hint->list[i].ino;
140 icount->count = hint->count;
141 }
142
143 *ret = icount;
144 return 0;
145
146errout:
147 ext2fs_free_icount(icount);
148 return(retval);
149}
150
151errcode_t ext2fs_create_icount(ext2_filsys fs, int flags,
152 unsigned int size,
153 ext2_icount_t *ret)
154{
155 return ext2fs_create_icount2(fs, flags, size, 0, ret);
156}
157
158/*
159 * insert_icount_el() --- Insert a new entry into the sorted list at a
160 * specified position.
161 */
162static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
163 ext2_ino_t ino, int pos)
164{
165 struct ext2_icount_el *el;
166 errcode_t retval;
167 ext2_ino_t new_size = 0;
168 int num;
169
170 if (icount->count >= icount->size) {
171 if (icount->count) {
172 new_size = icount->list[(unsigned)icount->count-1].ino;
173 new_size = (ext2_ino_t) (icount->count *
174 ((float) icount->num_inodes / new_size));
175 }
176 if (new_size < (icount->size + 100))
177 new_size = icount->size + 100;
178#if 0
179 printf("Reallocating icount %d entries...\n", new_size);
180#endif
181 retval = ext2fs_resize_mem((size_t) icount->size *
182 sizeof(struct ext2_icount_el),
183 (size_t) new_size *
184 sizeof(struct ext2_icount_el),
185 &icount->list);
186 if (retval)
187 return 0;
188 icount->size = new_size;
189 }
190 num = (int) icount->count - pos;
191 if (num < 0)
192 return 0; /* should never happen */
193 if (num) {
194 memmove(&icount->list[pos+1], &icount->list[pos],
195 sizeof(struct ext2_icount_el) * num);
196 }
197 icount->count++;
198 el = &icount->list[pos];
199 el->count = 0;
200 el->ino = ino;
201 return el;
202}
203
204/*
205 * get_icount_el() --- given an inode number, try to find icount
206 * information in the sorted list. If the create flag is set,
207 * and we can't find an entry, create one in the sorted list.
208 */
209static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
210 ext2_ino_t ino, int create)
211{
212 float range;
213 int low, high, mid;
214 ext2_ino_t lowval, highval;
215
216 if (!icount || !icount->list)
217 return 0;
218
219 if (create && ((icount->count == 0) ||
220 (ino > icount->list[(unsigned)icount->count-1].ino))) {
221 return insert_icount_el(icount, ino, (unsigned) icount->count);
222 }
223 if (icount->count == 0)
224 return 0;
225
226 if (icount->cursor >= icount->count)
227 icount->cursor = 0;
228 if (ino == icount->list[icount->cursor].ino)
229 return &icount->list[icount->cursor++];
230#if 0
231 printf("Non-cursor get_icount_el: %u\n", ino);
232#endif
233 low = 0;
234 high = (int) icount->count-1;
235 while (low <= high) {
236#if 0
237 mid = (low+high)/2;
238#else
239 if (low == high)
240 mid = low;
241 else {
242 /* Interpolate for efficiency */
243 lowval = icount->list[low].ino;
244 highval = icount->list[high].ino;
245
246 if (ino < lowval)
247 range = 0;
248 else if (ino > highval)
249 range = 1;
250 else
251 range = ((float) (ino - lowval)) /
252 (highval - lowval);
253 mid = low + ((int) (range * (high-low)));
254 }
255#endif
256 if (ino == icount->list[mid].ino) {
257 icount->cursor = mid+1;
258 return &icount->list[mid];
259 }
260 if (ino < icount->list[mid].ino)
261 high = mid-1;
262 else
263 low = mid+1;
264 }
265 /*
266 * If we need to create a new entry, it should be right at
267 * low (where high will be left at low-1).
268 */
269 if (create)
270 return insert_icount_el(icount, ino, low);
271 return 0;
272}
273
274errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
275{
276 errcode_t ret = 0;
277 unsigned int i;
278 const char *bad = "bad icount";
279
280 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
281
282 if (icount->count > icount->size) {
283 fprintf(out, "%s: count > size\n", bad);
284 return EXT2_ET_INVALID_ARGUMENT;
285 }
286 for (i=1; i < icount->count; i++) {
287 if (icount->list[i-1].ino >= icount->list[i].ino) {
288 fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n",
289 bad, i-1, icount->list[i-1].ino,
290 i, icount->list[i].ino);
291 ret = EXT2_ET_INVALID_ARGUMENT;
292 }
293 }
294 return ret;
295}
296
297errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
298{
299 struct ext2_icount_el *el;
300
301 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
302
303 if (!ino || (ino > icount->num_inodes))
304 return EXT2_ET_INVALID_ARGUMENT;
305
306 if (ext2fs_test_inode_bitmap(icount->single, ino)) {
307 *ret = 1;
308 return 0;
309 }
310 if (icount->multiple &&
311 !ext2fs_test_inode_bitmap(icount->multiple, ino)) {
312 *ret = 0;
313 return 0;
314 }
315 el = get_icount_el(icount, ino, 0);
316 if (!el) {
317 *ret = 0;
318 return 0;
319 }
320 *ret = el->count;
321 return 0;
322}
323
324errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
325 __u16 *ret)
326{
327 struct ext2_icount_el *el;
328
329 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
330
331 if (!ino || (ino > icount->num_inodes))
332 return EXT2_ET_INVALID_ARGUMENT;
333
334 if (ext2fs_test_inode_bitmap(icount->single, ino)) {
335 /*
336 * If the existing count is 1, then we know there is
337 * no entry in the list.
338 */
339 el = get_icount_el(icount, ino, 1);
340 if (!el)
341 return EXT2_ET_NO_MEMORY;
342 ext2fs_unmark_inode_bitmap(icount->single, ino);
343 el->count = 2;
344 } else if (icount->multiple) {
345 /*
346 * The count is either zero or greater than 1; if the
347 * inode is set in icount->multiple, then there should
348 * be an entry in the list, so find it using
349 * get_icount_el().
350 */
351 if (ext2fs_test_inode_bitmap(icount->multiple, ino)) {
352 el = get_icount_el(icount, ino, 1);
353 if (!el)
354 return EXT2_ET_NO_MEMORY;
355 el->count++;
356 } else {
357 /*
358 * The count was zero; mark the single bitmap
359 * and return.
360 */
361 zero_count:
362 ext2fs_mark_inode_bitmap(icount->single, ino);
363 if (ret)
364 *ret = 1;
365 return 0;
366 }
367 } else {
368 /*
369 * The count is either zero or greater than 1; try to
370 * find an entry in the list to determine which.
371 */
372 el = get_icount_el(icount, ino, 0);
373 if (!el) {
374 /* No entry means the count was zero */
375 goto zero_count;
376 }
377 el = get_icount_el(icount, ino, 1);
378 if (!el)
379 return EXT2_ET_NO_MEMORY;
380 el->count++;
381 }
382 if (icount->multiple)
383 ext2fs_mark_inode_bitmap(icount->multiple, ino);
384 if (ret)
385 *ret = el->count;
386 return 0;
387}
388
389errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
390 __u16 *ret)
391{
392 struct ext2_icount_el *el;
393
394 if (!ino || (ino > icount->num_inodes))
395 return EXT2_ET_INVALID_ARGUMENT;
396
397 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
398
399 if (ext2fs_test_inode_bitmap(icount->single, ino)) {
400 ext2fs_unmark_inode_bitmap(icount->single, ino);
401 if (icount->multiple)
402 ext2fs_unmark_inode_bitmap(icount->multiple, ino);
403 else {
404 el = get_icount_el(icount, ino, 0);
405 if (el)
406 el->count = 0;
407 }
408 if (ret)
409 *ret = 0;
410 return 0;
411 }
412
413 if (icount->multiple &&
414 !ext2fs_test_inode_bitmap(icount->multiple, ino))
415 return EXT2_ET_INVALID_ARGUMENT;
416
417 el = get_icount_el(icount, ino, 0);
418 if (!el || el->count == 0)
419 return EXT2_ET_INVALID_ARGUMENT;
420
421 el->count--;
422 if (el->count == 1)
423 ext2fs_mark_inode_bitmap(icount->single, ino);
424 if ((el->count == 0) && icount->multiple)
425 ext2fs_unmark_inode_bitmap(icount->multiple, ino);
426
427 if (ret)
428 *ret = el->count;
429 return 0;
430}
431
432errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
433 __u16 count)
434{
435 struct ext2_icount_el *el;
436
437 if (!ino || (ino > icount->num_inodes))
438 return EXT2_ET_INVALID_ARGUMENT;
439
440 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
441
442 if (count == 1) {
443 ext2fs_mark_inode_bitmap(icount->single, ino);
444 if (icount->multiple)
445 ext2fs_unmark_inode_bitmap(icount->multiple, ino);
446 return 0;
447 }
448 if (count == 0) {
449 ext2fs_unmark_inode_bitmap(icount->single, ino);
450 if (icount->multiple) {
451 /*
452 * If the icount->multiple bitmap is enabled,
453 * we can just clear both bitmaps and we're done
454 */
455 ext2fs_unmark_inode_bitmap(icount->multiple, ino);
456 } else {
457 el = get_icount_el(icount, ino, 0);
458 if (el)
459 el->count = 0;
460 }
461 return 0;
462 }
463
464 /*
465 * Get the icount element
466 */
467 el = get_icount_el(icount, ino, 1);
468 if (!el)
469 return EXT2_ET_NO_MEMORY;
470 el->count = count;
471 ext2fs_unmark_inode_bitmap(icount->single, ino);
472 if (icount->multiple)
473 ext2fs_mark_inode_bitmap(icount->multiple, ino);
474 return 0;
475}
476
477ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount)
478{
479 if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT)
480 return 0;
481
482 return icount->size;
483}
diff --git a/e2fsprogs/ext2fs/imager.c b/e2fsprogs/ext2fs/imager.c
new file mode 100644
index 000000000..596fbbebe
--- /dev/null
+++ b/e2fsprogs/ext2fs/imager.c
@@ -0,0 +1,387 @@
1/*
2 * image.c --- writes out the critical parts of the filesystem as a
3 * flat file.
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#include <stdio.h>
17#include <string.h>
18#if HAVE_UNISTD_H
19#include <unistd.h>
20#endif
21#if HAVE_ERRNO_H
22#include <errno.h>
23#endif
24#include <fcntl.h>
25#include <time.h>
26#if HAVE_SYS_STAT_H
27#include <sys/stat.h>
28#endif
29#if HAVE_SYS_TYPES_H
30#include <sys/types.h>
31#endif
32
33#include "ext2_fs.h"
34#include "ext2fs.h"
35
36#ifndef HAVE_TYPE_SSIZE_T
37typedef int ssize_t;
38#endif
39
40/*
41 * This function returns 1 if the specified block is all zeros
42 */
43static int check_zero_block(char *buf, int blocksize)
44{
45 char *cp = buf;
46 int left = blocksize;
47
48 while (left > 0) {
49 if (*cp++)
50 return 0;
51 left--;
52 }
53 return 1;
54}
55
56/*
57 * Write the inode table out as a single block.
58 */
59#define BUF_BLOCKS 32
60
61errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
62{
63 unsigned int group, left, c, d;
64 char *buf, *cp;
65 blk_t blk;
66 ssize_t actual;
67 errcode_t retval;
68
69 buf = malloc(fs->blocksize * BUF_BLOCKS);
70 if (!buf)
71 return ENOMEM;
72
73 for (group = 0; group < fs->group_desc_count; group++) {
74 blk = fs->group_desc[(unsigned)group].bg_inode_table;
75 if (!blk)
76 return EXT2_ET_MISSING_INODE_TABLE;
77 left = fs->inode_blocks_per_group;
78 while (left) {
79 c = BUF_BLOCKS;
80 if (c > left)
81 c = left;
82 retval = io_channel_read_blk(fs->io, blk, c, buf);
83 if (retval)
84 goto errout;
85 cp = buf;
86 while (c) {
87 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
88 d = c;
89 goto skip_sparse;
90 }
91 /* Skip zero blocks */
92 if (check_zero_block(cp, fs->blocksize)) {
93 c--;
94 blk++;
95 left--;
96 cp += fs->blocksize;
97 lseek(fd, fs->blocksize, SEEK_CUR);
98 continue;
99 }
100 /* Find non-zero blocks */
101 for (d=1; d < c; d++) {
102 if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
103 break;
104 }
105 skip_sparse:
106 actual = write(fd, cp, fs->blocksize * d);
107 if (actual == -1) {
108 retval = errno;
109 goto errout;
110 }
111 if (actual != (ssize_t) (fs->blocksize * d)) {
112 retval = EXT2_ET_SHORT_WRITE;
113 goto errout;
114 }
115 blk += d;
116 left -= d;
117 cp += fs->blocksize * d;
118 c -= d;
119 }
120 }
121 }
122 retval = 0;
123
124errout:
125 free(buf);
126 return retval;
127}
128
129/*
130 * Read in the inode table and stuff it into place
131 */
132errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
133 int flags EXT2FS_ATTR((unused)))
134{
135 unsigned int group, c, left;
136 char *buf;
137 blk_t blk;
138 ssize_t actual;
139 errcode_t retval;
140
141 buf = malloc(fs->blocksize * BUF_BLOCKS);
142 if (!buf)
143 return ENOMEM;
144
145 for (group = 0; group < fs->group_desc_count; group++) {
146 blk = fs->group_desc[(unsigned)group].bg_inode_table;
147 if (!blk) {
148 retval = EXT2_ET_MISSING_INODE_TABLE;
149 goto errout;
150 }
151 left = fs->inode_blocks_per_group;
152 while (left) {
153 c = BUF_BLOCKS;
154 if (c > left)
155 c = left;
156 actual = read(fd, buf, fs->blocksize * c);
157 if (actual == -1) {
158 retval = errno;
159 goto errout;
160 }
161 if (actual != (ssize_t) (fs->blocksize * c)) {
162 retval = EXT2_ET_SHORT_READ;
163 goto errout;
164 }
165 retval = io_channel_write_blk(fs->io, blk, c, buf);
166 if (retval)
167 goto errout;
168
169 blk += c;
170 left -= c;
171 }
172 }
173 retval = ext2fs_flush_icache(fs);
174
175errout:
176 free(buf);
177 return retval;
178}
179
180/*
181 * Write out superblock and group descriptors
182 */
183errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
184 int flags EXT2FS_ATTR((unused)))
185{
186 char *buf, *cp;
187 ssize_t actual;
188 errcode_t retval;
189
190 buf = malloc(fs->blocksize);
191 if (!buf)
192 return ENOMEM;
193
194 /*
195 * Write out the superblock
196 */
197 memset(buf, 0, fs->blocksize);
198 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
199 actual = write(fd, buf, fs->blocksize);
200 if (actual == -1) {
201 retval = errno;
202 goto errout;
203 }
204 if (actual != (ssize_t) fs->blocksize) {
205 retval = EXT2_ET_SHORT_WRITE;
206 goto errout;
207 }
208
209 /*
210 * Now write out the block group descriptors
211 */
212 cp = (char *) fs->group_desc;
213 actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
214 if (actual == -1) {
215 retval = errno;
216 goto errout;
217 }
218 if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
219 retval = EXT2_ET_SHORT_WRITE;
220 goto errout;
221 }
222
223 retval = 0;
224
225errout:
226 free(buf);
227 return retval;
228}
229
230/*
231 * Read the superblock and group descriptors and overwrite them.
232 */
233errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
234 int flags EXT2FS_ATTR((unused)))
235{
236 char *buf;
237 ssize_t actual, size;
238 errcode_t retval;
239
240 size = fs->blocksize * (fs->group_desc_count + 1);
241 buf = malloc(size);
242 if (!buf)
243 return ENOMEM;
244
245 /*
246 * Read it all in.
247 */
248 actual = read(fd, buf, size);
249 if (actual == -1) {
250 retval = errno;
251 goto errout;
252 }
253 if (actual != size) {
254 retval = EXT2_ET_SHORT_READ;
255 goto errout;
256 }
257
258 /*
259 * Now copy in the superblock and group descriptors
260 */
261 memcpy(fs->super, buf, SUPERBLOCK_SIZE);
262
263 memcpy(fs->group_desc, buf + fs->blocksize,
264 fs->blocksize * fs->group_desc_count);
265
266 retval = 0;
267
268errout:
269 free(buf);
270 return retval;
271}
272
273/*
274 * Write the block/inode bitmaps.
275 */
276errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
277{
278 char *ptr;
279 int c, size;
280 char zero_buf[1024];
281 ssize_t actual;
282 errcode_t retval;
283
284 if (flags & IMAGER_FLAG_INODEMAP) {
285 if (!fs->inode_map) {
286 retval = ext2fs_read_inode_bitmap(fs);
287 if (retval)
288 return retval;
289 }
290 ptr = fs->inode_map->bitmap;
291 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
292 } else {
293 if (!fs->block_map) {
294 retval = ext2fs_read_block_bitmap(fs);
295 if (retval)
296 return retval;
297 }
298 ptr = fs->block_map->bitmap;
299 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
300 }
301 size = size * fs->group_desc_count;
302
303 actual = write(fd, ptr, size);
304 if (actual == -1) {
305 retval = errno;
306 goto errout;
307 }
308 if (actual != size) {
309 retval = EXT2_ET_SHORT_WRITE;
310 goto errout;
311 }
312 size = size % fs->blocksize;
313 memset(zero_buf, 0, sizeof(zero_buf));
314 if (size) {
315 size = fs->blocksize - size;
316 while (size) {
317 c = size;
318 if (c > (int) sizeof(zero_buf))
319 c = sizeof(zero_buf);
320 actual = write(fd, zero_buf, c);
321 if (actual == -1) {
322 retval = errno;
323 goto errout;
324 }
325 if (actual != c) {
326 retval = EXT2_ET_SHORT_WRITE;
327 goto errout;
328 }
329 size -= c;
330 }
331 }
332 retval = 0;
333errout:
334 return (retval);
335}
336
337
338/*
339 * Read the block/inode bitmaps.
340 */
341errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
342{
343 char *ptr, *buf = 0;
344 int size;
345 ssize_t actual;
346 errcode_t retval;
347
348 if (flags & IMAGER_FLAG_INODEMAP) {
349 if (!fs->inode_map) {
350 retval = ext2fs_read_inode_bitmap(fs);
351 if (retval)
352 return retval;
353 }
354 ptr = fs->inode_map->bitmap;
355 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
356 } else {
357 if (!fs->block_map) {
358 retval = ext2fs_read_block_bitmap(fs);
359 if (retval)
360 return retval;
361 }
362 ptr = fs->block_map->bitmap;
363 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
364 }
365 size = size * fs->group_desc_count;
366
367 buf = malloc(size);
368 if (!buf)
369 return ENOMEM;
370
371 actual = read(fd, buf, size);
372 if (actual == -1) {
373 retval = errno;
374 goto errout;
375 }
376 if (actual != size) {
377 retval = EXT2_ET_SHORT_WRITE;
378 goto errout;
379 }
380 memcpy(ptr, buf, size);
381
382 retval = 0;
383errout:
384 if (buf)
385 free(buf);
386 return (retval);
387}
diff --git a/e2fsprogs/ext2fs/ind_block.c b/e2fsprogs/ext2fs/ind_block.c
new file mode 100644
index 000000000..351904831
--- /dev/null
+++ b/e2fsprogs/ext2fs/ind_block.c
@@ -0,0 +1,66 @@
1/*
2 * ind_block.c --- indirect block I/O routines
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
5 * 2001, 2002, 2003, 2004, 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#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
22errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf)
23{
24 errcode_t retval;
25 blk_t *block_nr;
26 int i;
27 int limit = fs->blocksize >> 2;
28
29 if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
30 (fs->io != fs->image_io))
31 memset(buf, 0, fs->blocksize);
32 else {
33 retval = io_channel_read_blk(fs->io, blk, 1, buf);
34 if (retval)
35 return retval;
36 }
37#ifdef EXT2FS_ENABLE_SWAPFS
38 if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_READ)) {
39 block_nr = (blk_t *) buf;
40 for (i = 0; i < limit; i++, block_nr++)
41 *block_nr = ext2fs_swab32(*block_nr);
42 }
43#endif
44 return 0;
45}
46
47errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf)
48{
49 blk_t *block_nr;
50 int i;
51 int limit = fs->blocksize >> 2;
52
53 if (fs->flags & EXT2_FLAG_IMAGE_FILE)
54 return 0;
55
56#ifdef EXT2FS_ENABLE_SWAPFS
57 if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_WRITE)) {
58 block_nr = (blk_t *) buf;
59 for (i = 0; i < limit; i++, block_nr++)
60 *block_nr = ext2fs_swab32(*block_nr);
61 }
62#endif
63 return io_channel_write_blk(fs->io, blk, 1, buf);
64}
65
66
diff --git a/e2fsprogs/ext2fs/initialize.c b/e2fsprogs/ext2fs/initialize.c
new file mode 100644
index 000000000..82cd9f1da
--- /dev/null
+++ b/e2fsprogs/ext2fs/initialize.c
@@ -0,0 +1,387 @@
1/*
2 * initialize.c --- initialize a filesystem handle given superblock
3 * parameters. Used by mke2fs when initializing a filesystem.
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 "ext2fs.h"
29
30#if defined(__linux__) && defined(EXT2_OS_LINUX)
31#define CREATOR_OS EXT2_OS_LINUX
32#else
33#if defined(__GNU__) && defined(EXT2_OS_HURD)
34#define CREATOR_OS EXT2_OS_HURD
35#else
36#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD)
37#define CREATOR_OS EXT2_OS_FREEBSD
38#else
39#if defined(LITES) && defined(EXT2_OS_LITES)
40#define CREATOR_OS EXT2_OS_LITES
41#else
42#define CREATOR_OS EXT2_OS_LINUX /* by default */
43#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
44#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
45#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */
46#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */
47
48/*
49 * Note we override the kernel include file's idea of what the default
50 * check interval (never) should be. It's a good idea to check at
51 * least *occasionally*, specially since servers will never rarely get
52 * to reboot, since Linux is so robust these days. :-)
53 *
54 * 180 days (six months) seems like a good value.
55 */
56#ifdef EXT2_DFL_CHECKINTERVAL
57#undef EXT2_DFL_CHECKINTERVAL
58#endif
59#define EXT2_DFL_CHECKINTERVAL (86400L * 180L)
60
61/*
62 * Calculate the number of GDT blocks to reserve for online filesystem growth.
63 * The absolute maximum number of GDT blocks we can reserve is determined by
64 * the number of block pointers that can fit into a single block.
65 */
66static int calc_reserved_gdt_blocks(ext2_filsys fs)
67{
68 struct ext2_super_block *sb = fs->super;
69 unsigned long bpg = sb->s_blocks_per_group;
70 unsigned int gdpb = fs->blocksize / sizeof(struct ext2_group_desc);
71 unsigned long max_blocks = 0xffffffff;
72 unsigned long rsv_groups;
73 int rsv_gdb;
74
75 /* We set it at 1024x the current filesystem size, or
76 * the upper block count limit (2^32), whichever is lower.
77 */
78 if (sb->s_blocks_count < max_blocks / 1024)
79 max_blocks = sb->s_blocks_count * 1024;
80 rsv_groups = (max_blocks - sb->s_first_data_block + bpg - 1) / bpg;
81 rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - fs->desc_blocks;
82 if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
83 rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
84#ifdef RES_GDT_DEBUG
85 printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %lu\n",
86 max_blocks, rsv_groups, rsv_gdb);
87#endif
88
89 return rsv_gdb;
90}
91
92errcode_t ext2fs_initialize(const char *name, int flags,
93 struct ext2_super_block *param,
94 io_manager manager, ext2_filsys *ret_fs)
95{
96 ext2_filsys fs;
97 errcode_t retval;
98 struct ext2_super_block *super;
99 int frags_per_block;
100 unsigned int rem;
101 unsigned int overhead = 0;
102 blk_t group_block;
103 unsigned int ipg;
104 dgrp_t i;
105 blk_t numblocks;
106 int rsv_gdt;
107 char *buf;
108
109 if (!param || !param->s_blocks_count)
110 return EXT2_ET_INVALID_ARGUMENT;
111
112 retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
113 if (retval)
114 return retval;
115
116 memset(fs, 0, sizeof(struct struct_ext2_filsys));
117 fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
118 fs->flags = flags | EXT2_FLAG_RW;
119 fs->umask = 022;
120#ifdef WORDS_BIGENDIAN
121 fs->flags |= EXT2_FLAG_SWAP_BYTES;
122#endif
123 retval = manager->open(name, IO_FLAG_RW, &fs->io);
124 if (retval)
125 goto cleanup;
126 fs->image_io = fs->io;
127 fs->io->app_data = fs;
128 retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
129 if (retval)
130 goto cleanup;
131
132 strcpy(fs->device_name, name);
133 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
134 if (retval)
135 goto cleanup;
136 fs->super = super;
137
138 memset(super, 0, SUPERBLOCK_SIZE);
139
140#define set_field(field, default) (super->field = param->field ? \
141 param->field : (default))
142
143 super->s_magic = EXT2_SUPER_MAGIC;
144 super->s_state = EXT2_VALID_FS;
145
146 set_field(s_log_block_size, 0); /* default blocksize: 1024 bytes */
147 set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
148 set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
149 set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
150 set_field(s_errors, EXT2_ERRORS_DEFAULT);
151 set_field(s_feature_compat, 0);
152 set_field(s_feature_incompat, 0);
153 set_field(s_feature_ro_compat, 0);
154 set_field(s_first_meta_bg, 0);
155 if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
156 retval = EXT2_ET_UNSUPP_FEATURE;
157 goto cleanup;
158 }
159 if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
160 retval = EXT2_ET_RO_UNSUPP_FEATURE;
161 goto cleanup;
162 }
163
164 set_field(s_rev_level, EXT2_GOOD_OLD_REV);
165 if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
166 set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
167 set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
168 }
169
170 set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
171 super->s_mkfs_time = super->s_lastcheck = time(NULL);
172
173 super->s_creator_os = CREATOR_OS;
174
175 fs->blocksize = EXT2_BLOCK_SIZE(super);
176 fs->fragsize = EXT2_FRAG_SIZE(super);
177 frags_per_block = fs->blocksize / fs->fragsize;
178
179 /* default: (fs->blocksize*8) blocks/group, up to 2^16 (GDT limit) */
180 set_field(s_blocks_per_group, fs->blocksize * 8);
181 if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
182 super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
183 super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
184
185 super->s_blocks_count = param->s_blocks_count;
186 super->s_r_blocks_count = param->s_r_blocks_count;
187 if (super->s_r_blocks_count >= param->s_blocks_count) {
188 retval = EXT2_ET_INVALID_ARGUMENT;
189 goto cleanup;
190 }
191
192 /*
193 * If we're creating an external journal device, we don't need
194 * to bother with the rest.
195 */
196 if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
197 fs->group_desc_count = 0;
198 ext2fs_mark_super_dirty(fs);
199 *ret_fs = fs;
200 return 0;
201 }
202
203retry:
204 fs->group_desc_count = (super->s_blocks_count -
205 super->s_first_data_block +
206 EXT2_BLOCKS_PER_GROUP(super) - 1)
207 / EXT2_BLOCKS_PER_GROUP(super);
208 if (fs->group_desc_count == 0) {
209 retval = EXT2_ET_TOOSMALL;
210 goto cleanup;
211 }
212 fs->desc_blocks = (fs->group_desc_count +
213 EXT2_DESC_PER_BLOCK(super) - 1)
214 / EXT2_DESC_PER_BLOCK(super);
215
216 i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
217 set_field(s_inodes_count, super->s_blocks_count / i);
218
219 /*
220 * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
221 * that we have enough inodes for the filesystem(!)
222 */
223 if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
224 super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
225
226 /*
227 * There should be at least as many inodes as the user
228 * requested. Figure out how many inodes per group that
229 * should be. But make sure that we don't allocate more than
230 * one bitmap's worth of inodes each group.
231 */
232 ipg = (super->s_inodes_count + fs->group_desc_count - 1) /
233 fs->group_desc_count;
234 if (ipg > fs->blocksize * 8) {
235 if (super->s_blocks_per_group >= 256) {
236 /* Try again with slightly different parameters */
237 super->s_blocks_per_group -= 8;
238 super->s_blocks_count = param->s_blocks_count;
239 super->s_frags_per_group = super->s_blocks_per_group *
240 frags_per_block;
241 goto retry;
242 } else
243 return EXT2_ET_TOO_MANY_INODES;
244 }
245
246 if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
247 ipg = EXT2_MAX_INODES_PER_GROUP(super);
248
249 super->s_inodes_per_group = ipg;
250 if (super->s_inodes_count > ipg * fs->group_desc_count)
251 super->s_inodes_count = ipg * fs->group_desc_count;
252
253 /*
254 * Make sure the number of inodes per group completely fills
255 * the inode table blocks in the descriptor. If not, add some
256 * additional inodes/group. Waste not, want not...
257 */
258 fs->inode_blocks_per_group = (((super->s_inodes_per_group *
259 EXT2_INODE_SIZE(super)) +
260 EXT2_BLOCK_SIZE(super) - 1) /
261 EXT2_BLOCK_SIZE(super));
262 super->s_inodes_per_group = ((fs->inode_blocks_per_group *
263 EXT2_BLOCK_SIZE(super)) /
264 EXT2_INODE_SIZE(super));
265 /*
266 * Finally, make sure the number of inodes per group is a
267 * multiple of 8. This is needed to simplify the bitmap
268 * splicing code.
269 */
270 super->s_inodes_per_group &= ~7;
271 fs->inode_blocks_per_group = (((super->s_inodes_per_group *
272 EXT2_INODE_SIZE(super)) +
273 EXT2_BLOCK_SIZE(super) - 1) /
274 EXT2_BLOCK_SIZE(super));
275
276 /*
277 * adjust inode count to reflect the adjusted inodes_per_group
278 */
279 super->s_inodes_count = super->s_inodes_per_group *
280 fs->group_desc_count;
281 super->s_free_inodes_count = super->s_inodes_count;
282
283 /*
284 * check the number of reserved group descriptor table blocks
285 */
286 if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)
287 rsv_gdt = calc_reserved_gdt_blocks(fs);
288 else
289 rsv_gdt = 0;
290 set_field(s_reserved_gdt_blocks, rsv_gdt);
291 if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
292 retval = EXT2_ET_RES_GDT_BLOCKS;
293 goto cleanup;
294 }
295
296 /*
297 * Overhead is the number of bookkeeping blocks per group. It
298 * includes the superblock backup, the group descriptor
299 * backups, the inode bitmap, the block bitmap, and the inode
300 * table.
301 */
302
303 overhead = (int) (2 + fs->inode_blocks_per_group);
304
305 if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
306 overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
307
308 /* This can only happen if the user requested too many inodes */
309 if (overhead > super->s_blocks_per_group)
310 return EXT2_ET_TOO_MANY_INODES;
311
312 /*
313 * See if the last group is big enough to support the
314 * necessary data structures. If not, we need to get rid of
315 * it.
316 */
317 rem = ((super->s_blocks_count - super->s_first_data_block) %
318 super->s_blocks_per_group);
319 if ((fs->group_desc_count == 1) && rem && (rem < overhead))
320 return EXT2_ET_TOOSMALL;
321 if (rem && (rem < overhead+50)) {
322 super->s_blocks_count -= rem;
323 goto retry;
324 }
325
326 /*
327 * At this point we know how big the filesystem will be. So
328 * we can do any and all allocations that depend on the block
329 * count.
330 */
331
332 retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
333 if (retval)
334 goto cleanup;
335
336 sprintf(buf, "block bitmap for %s", fs->device_name);
337 retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
338 if (retval)
339 goto cleanup;
340
341 sprintf(buf, "inode bitmap for %s", fs->device_name);
342 retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
343 if (retval)
344 goto cleanup;
345
346 ext2fs_free_mem(&buf);
347
348 retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
349 &fs->group_desc);
350 if (retval)
351 goto cleanup;
352
353 memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);
354
355 /*
356 * Reserve the superblock and group descriptors for each
357 * group, and fill in the correct group statistics for group.
358 * Note that although the block bitmap, inode bitmap, and
359 * inode table have not been allocated (and in fact won't be
360 * by this routine), they are accounted for nevertheless.
361 */
362 group_block = super->s_first_data_block;
363 super->s_free_blocks_count = 0;
364 for (i = 0; i < fs->group_desc_count; i++) {
365 numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
366
367 super->s_free_blocks_count += numblocks;
368 fs->group_desc[i].bg_free_blocks_count = numblocks;
369 fs->group_desc[i].bg_free_inodes_count =
370 fs->super->s_inodes_per_group;
371 fs->group_desc[i].bg_used_dirs_count = 0;
372
373 group_block += super->s_blocks_per_group;
374 }
375
376 ext2fs_mark_super_dirty(fs);
377 ext2fs_mark_bb_dirty(fs);
378 ext2fs_mark_ib_dirty(fs);
379
380 io_channel_set_blksize(fs->io, fs->blocksize);
381
382 *ret_fs = fs;
383 return 0;
384cleanup:
385 ext2fs_free(fs);
386 return retval;
387}
diff --git a/e2fsprogs/ext2fs/inline.c b/e2fsprogs/ext2fs/inline.c
new file mode 100644
index 000000000..5833b1d9d
--- /dev/null
+++ b/e2fsprogs/ext2fs/inline.c
@@ -0,0 +1,32 @@
1/*
2 * inline.c --- Includes the inlined functions defined in the header
3 * files as standalone functions, in case the application program
4 * is compiled with inlining turned off.
5 *
6 * Copyright (C) 1993, 1994 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
15#include <stdio.h>
16#include <string.h>
17#if HAVE_UNISTD_H
18#include <unistd.h>
19#endif
20#include <fcntl.h>
21#include <time.h>
22#if HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#if HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28
29#include "ext2_fs.h"
30#define INCLUDE_INLINE_FUNCS
31#include "ext2fs.h"
32
diff --git a/e2fsprogs/ext2fs/inode.c b/e2fsprogs/ext2fs/inode.c
new file mode 100644
index 000000000..222568ebe
--- /dev/null
+++ b/e2fsprogs/ext2fs/inode.c
@@ -0,0 +1,794 @@
1/*
2 * inode.c --- utility routines to read and write inodes
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#if HAVE_ERRNO_H
18#include <errno.h>
19#endif
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#include "e2image.h"
30
31struct ext2_struct_inode_scan {
32 errcode_t magic;
33 ext2_filsys fs;
34 ext2_ino_t current_inode;
35 blk_t current_block;
36 dgrp_t current_group;
37 ext2_ino_t inodes_left;
38 blk_t blocks_left;
39 dgrp_t groups_left;
40 blk_t inode_buffer_blocks;
41 char * inode_buffer;
42 int inode_size;
43 char * ptr;
44 int bytes_left;
45 char *temp_buffer;
46 errcode_t (*done_group)(ext2_filsys fs,
47 ext2_inode_scan scan,
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 && fs->badblocks) {
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 ext2_inode_scan scan,
187 dgrp_t group,
188 void * priv_data),
189 void *done_group_data)
190{
191 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
192 return;
193
194 scan->done_group = done_group;
195 scan->done_group_data = done_group_data;
196}
197
198int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
199 int clear_flags)
200{
201 int old_flags;
202
203 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
204 return 0;
205
206 old_flags = scan->scan_flags;
207 scan->scan_flags &= ~clear_flags;
208 scan->scan_flags |= set_flags;
209 return old_flags;
210}
211
212/*
213 * This function is called by ext2fs_get_next_inode when it needs to
214 * get ready to read in a new blockgroup.
215 */
216static errcode_t get_next_blockgroup(ext2_inode_scan scan)
217{
218 scan->current_group++;
219 scan->groups_left--;
220
221 scan->current_block = scan->fs->
222 group_desc[scan->current_group].bg_inode_table;
223
224 scan->current_inode = scan->current_group *
225 EXT2_INODES_PER_GROUP(scan->fs->super);
226
227 scan->bytes_left = 0;
228 scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
229 scan->blocks_left = scan->fs->inode_blocks_per_group;
230 return 0;
231}
232
233errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
234 int group)
235{
236 scan->current_group = group - 1;
237 scan->groups_left = scan->fs->group_desc_count - group;
238 return get_next_blockgroup(scan);
239}
240
241/*
242 * This function is called by get_next_blocks() to check for bad
243 * blocks in the inode table.
244 *
245 * This function assumes that badblocks_list->list is sorted in
246 * increasing order.
247 */
248static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
249 blk_t *num_blocks)
250{
251 blk_t blk = scan->current_block;
252 badblocks_list bb = scan->fs->badblocks;
253
254 /*
255 * If the inode table is missing, then obviously there are no
256 * bad blocks. :-)
257 */
258 if (blk == 0)
259 return 0;
260
261 /*
262 * If the current block is greater than the bad block listed
263 * in the bad block list, then advance the pointer until this
264 * is no longer the case. If we run out of bad blocks, then
265 * we don't need to do any more checking!
266 */
267 while (blk > bb->list[scan->bad_block_ptr]) {
268 if (++scan->bad_block_ptr >= bb->num) {
269 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
270 return 0;
271 }
272 }
273
274 /*
275 * If the current block is equal to the bad block listed in
276 * the bad block list, then handle that one block specially.
277 * (We could try to handle runs of bad blocks, but that
278 * only increases CPU efficiency by a small amount, at the
279 * expense of a huge expense of code complexity, and for an
280 * uncommon case at that.)
281 */
282 if (blk == bb->list[scan->bad_block_ptr]) {
283 scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
284 *num_blocks = 1;
285 if (++scan->bad_block_ptr >= bb->num)
286 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
287 return 0;
288 }
289
290 /*
291 * If there is a bad block in the range that we're about to
292 * read in, adjust the number of blocks to read so that we we
293 * don't read in the bad block. (Then the next block to read
294 * will be the bad block, which is handled in the above case.)
295 */
296 if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
297 *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
298
299 return 0;
300}
301
302/*
303 * This function is called by ext2fs_get_next_inode when it needs to
304 * read in more blocks from the current blockgroup's inode table.
305 */
306static errcode_t get_next_blocks(ext2_inode_scan scan)
307{
308 blk_t num_blocks;
309 errcode_t retval;
310
311 /*
312 * Figure out how many blocks to read; we read at most
313 * inode_buffer_blocks, and perhaps less if there aren't that
314 * many blocks left to read.
315 */
316 num_blocks = scan->inode_buffer_blocks;
317 if (num_blocks > scan->blocks_left)
318 num_blocks = scan->blocks_left;
319
320 /*
321 * If the past block "read" was a bad block, then mark the
322 * left-over extra bytes as also being bad.
323 */
324 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
325 if (scan->bytes_left)
326 scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
327 scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
328 }
329
330 /*
331 * Do inode bad block processing, if necessary.
332 */
333 if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
334 retval = check_for_inode_bad_blocks(scan, &num_blocks);
335 if (retval)
336 return retval;
337 }
338
339 if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
340 (scan->current_block == 0)) {
341 memset(scan->inode_buffer, 0,
342 (size_t) num_blocks * scan->fs->blocksize);
343 } else {
344 retval = io_channel_read_blk(scan->fs->io,
345 scan->current_block,
346 (int) num_blocks,
347 scan->inode_buffer);
348 if (retval)
349 return EXT2_ET_NEXT_INODE_READ;
350 }
351 scan->ptr = scan->inode_buffer;
352 scan->bytes_left = num_blocks * scan->fs->blocksize;
353
354 scan->blocks_left -= num_blocks;
355 if (scan->current_block)
356 scan->current_block += num_blocks;
357 return 0;
358}
359
360#if 0
361/*
362 * Returns 1 if the entire inode_buffer has a non-zero size and
363 * contains all zeros. (Not just deleted inodes, since that means
364 * that part of the inode table was used at one point; we want all
365 * zeros, which means that the inode table is pristine.)
366 */
367static inline int is_empty_scan(ext2_inode_scan scan)
368{
369 int i;
370
371 if (scan->bytes_left == 0)
372 return 0;
373
374 for (i=0; i < scan->bytes_left; i++)
375 if (scan->ptr[i])
376 return 0;
377 return 1;
378}
379#endif
380
381errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
382 struct ext2_inode *inode, int bufsize)
383{
384 errcode_t retval;
385 int extra_bytes = 0;
386
387 EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
388
389 /*
390 * Do we need to start reading a new block group?
391 */
392 if (scan->inodes_left <= 0) {
393 force_new_group:
394 if (scan->done_group) {
395 retval = (scan->done_group)
396 (scan->fs, scan, scan->current_group,
397 scan->done_group_data);
398 if (retval)
399 return retval;
400 }
401 if (scan->groups_left <= 0) {
402 *ino = 0;
403 return 0;
404 }
405 retval = get_next_blockgroup(scan);
406 if (retval)
407 return retval;
408 }
409 /*
410 * This is done outside the above if statement so that the
411 * check can be done for block group #0.
412 */
413 if (scan->current_block == 0) {
414 if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
415 goto force_new_group;
416 } else
417 return EXT2_ET_MISSING_INODE_TABLE;
418 }
419
420
421 /*
422 * Have we run out of space in the inode buffer? If so, we
423 * need to read in more blocks.
424 */
425 if (scan->bytes_left < scan->inode_size) {
426 memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
427 extra_bytes = scan->bytes_left;
428
429 retval = get_next_blocks(scan);
430 if (retval)
431 return retval;
432#if 0
433 /*
434 * XXX test Need check for used inode somehow.
435 * (Note: this is hard.)
436 */
437 if (is_empty_scan(scan))
438 goto force_new_group;
439#endif
440 }
441
442 retval = 0;
443 if (extra_bytes) {
444 memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
445 scan->inode_size - extra_bytes);
446 scan->ptr += scan->inode_size - extra_bytes;
447 scan->bytes_left -= scan->inode_size - extra_bytes;
448
449#ifdef EXT2FS_ENABLE_SWAPFS
450 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
451 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
452 ext2fs_swap_inode_full(scan->fs,
453 (struct ext2_inode_large *) inode,
454 (struct ext2_inode_large *) scan->temp_buffer,
455 0, bufsize);
456 else
457#endif
458 *inode = *((struct ext2_inode *) scan->temp_buffer);
459 if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
460 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
461 scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
462 } else {
463#ifdef EXT2FS_ENABLE_SWAPFS
464 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
465 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
466 ext2fs_swap_inode_full(scan->fs,
467 (struct ext2_inode_large *) inode,
468 (struct ext2_inode_large *) scan->ptr,
469 0, bufsize);
470 else
471#endif
472 memcpy(inode, scan->ptr, bufsize);
473 scan->ptr += scan->inode_size;
474 scan->bytes_left -= scan->inode_size;
475 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
476 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
477 }
478
479 scan->inodes_left--;
480 scan->current_inode++;
481 *ino = scan->current_inode;
482 return retval;
483}
484
485errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
486 struct ext2_inode *inode)
487{
488 return ext2fs_get_next_inode_full(scan, ino, inode,
489 sizeof(struct ext2_inode));
490}
491
492/*
493 * Functions to read and write a single inode.
494 */
495errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
496 struct ext2_inode * inode, int bufsize)
497{
498 unsigned long group, block, block_nr, offset;
499 char *ptr;
500 errcode_t retval;
501 int clen, i, inodes_per_block, length;
502 io_channel io;
503
504 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
505
506 /* Check to see if user has an override function */
507 if (fs->read_inode) {
508 retval = (fs->read_inode)(fs, ino, inode);
509 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
510 return retval;
511 }
512 /* Create inode cache if not present */
513 if (!fs->icache) {
514 retval = create_icache(fs);
515 if (retval)
516 return retval;
517 }
518 /* Check to see if it's in the inode cache */
519 if (bufsize == sizeof(struct ext2_inode)) {
520 /* only old good inode can be retrieve from the cache */
521 for (i=0; i < fs->icache->cache_size; i++) {
522 if (fs->icache->cache[i].ino == ino) {
523 *inode = fs->icache->cache[i].inode;
524 return 0;
525 }
526 }
527 }
528 if ((ino == 0) || (ino > fs->super->s_inodes_count))
529 return EXT2_ET_BAD_INODE_NUM;
530 if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
531 inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
532 block_nr = fs->image_header->offset_inode / fs->blocksize;
533 block_nr += (ino - 1) / inodes_per_block;
534 offset = ((ino - 1) % inodes_per_block) *
535 EXT2_INODE_SIZE(fs->super);
536 io = fs->image_io;
537 } else {
538 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
539 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
540 EXT2_INODE_SIZE(fs->super);
541 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
542 if (!fs->group_desc[(unsigned)group].bg_inode_table)
543 return EXT2_ET_MISSING_INODE_TABLE;
544 block_nr = fs->group_desc[(unsigned)group].bg_inode_table +
545 block;
546 io = fs->io;
547 }
548 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
549
550 length = EXT2_INODE_SIZE(fs->super);
551 if (bufsize < length)
552 length = bufsize;
553
554 ptr = (char *) inode;
555 while (length) {
556 clen = length;
557 if ((offset + length) > fs->blocksize)
558 clen = fs->blocksize - offset;
559
560 if (block_nr != fs->icache->buffer_blk) {
561 retval = io_channel_read_blk(io, block_nr, 1,
562 fs->icache->buffer);
563 if (retval)
564 return retval;
565 fs->icache->buffer_blk = block_nr;
566 }
567
568 memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
569 clen);
570
571 offset = 0;
572 length -= clen;
573 ptr += clen;
574 block_nr++;
575 }
576
577#ifdef EXT2FS_ENABLE_SWAPFS
578 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
579 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
580 ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode,
581 (struct ext2_inode_large *) inode,
582 0, length);
583#endif
584
585 /* Update the inode cache */
586 fs->icache->cache_last = (fs->icache->cache_last + 1) %
587 fs->icache->cache_size;
588 fs->icache->cache[fs->icache->cache_last].ino = ino;
589 fs->icache->cache[fs->icache->cache_last].inode = *inode;
590
591 return 0;
592}
593
594errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
595 struct ext2_inode * inode)
596{
597 return ext2fs_read_inode_full(fs, ino, inode,
598 sizeof(struct ext2_inode));
599}
600
601errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
602 struct ext2_inode * inode, int bufsize)
603{
604 unsigned long group, block, block_nr, offset;
605 errcode_t retval = 0;
606 struct ext2_inode_large temp_inode, *w_inode;
607 char *ptr;
608 int clen, i, length;
609
610 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
611
612 /* Check to see if user provided an override function */
613 if (fs->write_inode) {
614 retval = (fs->write_inode)(fs, ino, inode);
615 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
616 return retval;
617 }
618
619 /* Check to see if the inode cache needs to be updated */
620 if (fs->icache) {
621 for (i=0; i < fs->icache->cache_size; i++) {
622 if (fs->icache->cache[i].ino == ino) {
623 fs->icache->cache[i].inode = *inode;
624 break;
625 }
626 }
627 } else {
628 retval = create_icache(fs);
629 if (retval)
630 return retval;
631 }
632
633 if (!(fs->flags & EXT2_FLAG_RW))
634 return EXT2_ET_RO_FILSYS;
635
636 if ((ino == 0) || (ino > fs->super->s_inodes_count))
637 return EXT2_ET_BAD_INODE_NUM;
638
639 length = bufsize;
640 if (length < EXT2_INODE_SIZE(fs->super))
641 length = EXT2_INODE_SIZE(fs->super);
642
643 if (length > (int) sizeof(struct ext2_inode_large)) {
644 w_inode = malloc(length);
645 if (!w_inode)
646 return ENOMEM;
647 } else
648 w_inode = &temp_inode;
649 memset(w_inode, 0, length);
650
651#ifdef EXT2FS_ENABLE_SWAPFS
652 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
653 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
654 ext2fs_swap_inode_full(fs, w_inode,
655 (struct ext2_inode_large *) inode,
656 1, bufsize);
657 else
658#endif
659 memcpy(w_inode, inode, bufsize);
660
661 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
662 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
663 EXT2_INODE_SIZE(fs->super);
664 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
665 if (!fs->group_desc[(unsigned) group].bg_inode_table)
666 return EXT2_ET_MISSING_INODE_TABLE;
667 block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
668
669 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
670
671 length = EXT2_INODE_SIZE(fs->super);
672 if (length > bufsize)
673 length = bufsize;
674
675 ptr = (char *) w_inode;
676
677 while (length) {
678 clen = length;
679 if ((offset + length) > fs->blocksize)
680 clen = fs->blocksize - offset;
681
682 if (fs->icache->buffer_blk != block_nr) {
683 retval = io_channel_read_blk(fs->io, block_nr, 1,
684 fs->icache->buffer);
685 if (retval)
686 goto errout;
687 fs->icache->buffer_blk = block_nr;
688 }
689
690
691 memcpy((char *) fs->icache->buffer + (unsigned) offset,
692 ptr, clen);
693
694 retval = io_channel_write_blk(fs->io, block_nr, 1,
695 fs->icache->buffer);
696 if (retval)
697 goto errout;
698
699 offset = 0;
700 ptr += clen;
701 length -= clen;
702 block_nr++;
703 }
704
705 fs->flags |= EXT2_FLAG_CHANGED;
706errout:
707 if (w_inode && w_inode != &temp_inode)
708 free(w_inode);
709 return retval;
710}
711
712errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
713 struct ext2_inode *inode)
714{
715 return ext2fs_write_inode_full(fs, ino, inode,
716 sizeof(struct ext2_inode));
717}
718
719/*
720 * This function should be called when writing a new inode. It makes
721 * sure that extra part of large inodes is initialized properly.
722 */
723errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
724 struct ext2_inode *inode)
725{
726 struct ext2_inode *buf;
727 int size = EXT2_INODE_SIZE(fs->super);
728 struct ext2_inode_large *large_inode;
729
730 if (size == sizeof(struct ext2_inode))
731 return ext2fs_write_inode_full(fs, ino, inode,
732 sizeof(struct ext2_inode));
733
734 buf = malloc(size);
735 if (!buf)
736 return ENOMEM;
737
738 memset(buf, 0, size);
739 *buf = *inode;
740
741 large_inode = (struct ext2_inode_large *) buf;
742 large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
743 EXT2_GOOD_OLD_INODE_SIZE;
744
745 return ext2fs_write_inode_full(fs, ino, buf, size);
746}
747
748
749errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
750{
751 struct ext2_inode inode;
752 int i;
753 errcode_t retval;
754
755 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
756
757 if (ino > fs->super->s_inodes_count)
758 return EXT2_ET_BAD_INODE_NUM;
759
760 if (fs->get_blocks) {
761 if (!(*fs->get_blocks)(fs, ino, blocks))
762 return 0;
763 }
764 retval = ext2fs_read_inode(fs, ino, &inode);
765 if (retval)
766 return retval;
767 for (i=0; i < EXT2_N_BLOCKS; i++)
768 blocks[i] = inode.i_block[i];
769 return 0;
770}
771
772errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
773{
774 struct ext2_inode inode;
775 errcode_t retval;
776
777 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
778
779 if (ino > fs->super->s_inodes_count)
780 return EXT2_ET_BAD_INODE_NUM;
781
782 if (fs->check_directory) {
783 retval = (fs->check_directory)(fs, ino);
784 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
785 return retval;
786 }
787 retval = ext2fs_read_inode(fs, ino, &inode);
788 if (retval)
789 return retval;
790 if (!LINUX_S_ISDIR(inode.i_mode))
791 return EXT2_ET_NO_DIRECTORY;
792 return 0;
793}
794
diff --git a/e2fsprogs/ext2fs/inode_io.c b/e2fsprogs/ext2fs/inode_io.c
new file mode 100644
index 000000000..b5c08b90a
--- /dev/null
+++ b/e2fsprogs/ext2fs/inode_io.c
@@ -0,0 +1,270 @@
1/*
2 * inode_io.c --- This is allows an inode in an ext2 filesystem image
3 * to be accessed via the I/O manager interface.
4 *
5 * Copyright (C) 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 <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 <time.h>
22
23#include "ext2_fs.h"
24#include "ext2fs.h"
25
26/*
27 * For checking structure magic numbers...
28 */
29
30#define EXT2_CHECK_MAGIC(struct, code) \
31 if ((struct)->magic != (code)) return (code)
32
33struct inode_private_data {
34 int magic;
35 char name[32];
36 ext2_file_t file;
37 ext2_filsys fs;
38 ext2_ino_t ino;
39 struct ext2_inode inode;
40 int flags;
41 struct inode_private_data *next;
42};
43
44#define CHANNEL_HAS_INODE 0x8000
45
46static struct inode_private_data *top_intern;
47static int ino_unique = 0;
48
49static errcode_t inode_open(const char *name, int flags, io_channel *channel);
50static errcode_t inode_close(io_channel channel);
51static errcode_t inode_set_blksize(io_channel channel, int blksize);
52static errcode_t inode_read_blk(io_channel channel, unsigned long block,
53 int count, void *data);
54static errcode_t inode_write_blk(io_channel channel, unsigned long block,
55 int count, const void *data);
56static errcode_t inode_flush(io_channel channel);
57static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
58 int size, const void *data);
59
60static struct struct_io_manager struct_inode_manager = {
61 EXT2_ET_MAGIC_IO_MANAGER,
62 "Inode I/O Manager",
63 inode_open,
64 inode_close,
65 inode_set_blksize,
66 inode_read_blk,
67 inode_write_blk,
68 inode_flush,
69 inode_write_byte
70};
71
72io_manager inode_io_manager = &struct_inode_manager;
73
74errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
75 struct ext2_inode *inode,
76 char **name)
77{
78 struct inode_private_data *data;
79 errcode_t retval;
80
81 if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
82 &data)))
83 return retval;
84 data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
85 sprintf(data->name, "%u:%d", ino, ino_unique++);
86 data->file = 0;
87 data->fs = fs;
88 data->ino = ino;
89 data->flags = 0;
90 if (inode) {
91 memcpy(&data->inode, inode, sizeof(struct ext2_inode));
92 data->flags |= CHANNEL_HAS_INODE;
93 }
94 data->next = top_intern;
95 top_intern = data;
96 *name = data->name;
97 return 0;
98}
99
100errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
101 char **name)
102{
103 return ext2fs_inode_io_intern2(fs, ino, NULL, name);
104}
105
106
107static errcode_t inode_open(const char *name, int flags, io_channel *channel)
108{
109 io_channel io = NULL;
110 struct inode_private_data *prev, *data = NULL;
111 errcode_t retval;
112 int open_flags;
113
114 if (name == 0)
115 return EXT2_ET_BAD_DEVICE_NAME;
116
117 for (data = top_intern, prev = NULL; data;
118 prev = data, data = data->next)
119 if (strcmp(name, data->name) == 0)
120 break;
121 if (!data)
122 return ENOENT;
123 if (prev)
124 prev->next = data->next;
125 else
126 top_intern = data->next;
127
128 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
129 if (retval)
130 goto cleanup;
131 memset(io, 0, sizeof(struct struct_io_channel));
132
133 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
134 io->manager = inode_io_manager;
135 retval = ext2fs_get_mem(strlen(name)+1, &io->name);
136 if (retval)
137 goto cleanup;
138
139 strcpy(io->name, name);
140 io->private_data = data;
141 io->block_size = 1024;
142 io->read_error = 0;
143 io->write_error = 0;
144 io->refcount = 1;
145
146 open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
147 retval = ext2fs_file_open2(data->fs, data->ino,
148 (data->flags & CHANNEL_HAS_INODE) ?
149 &data->inode : 0, open_flags,
150 &data->file);
151 if (retval)
152 goto cleanup;
153
154 *channel = io;
155 return 0;
156
157cleanup:
158 if (data) {
159 ext2fs_free_mem(&data);
160 }
161 if (io)
162 ext2fs_free_mem(&io);
163 return retval;
164}
165
166static errcode_t inode_close(io_channel channel)
167{
168 struct inode_private_data *data;
169 errcode_t retval = 0;
170
171 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
172 data = (struct inode_private_data *) channel->private_data;
173 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
174
175 if (--channel->refcount > 0)
176 return 0;
177
178 retval = ext2fs_file_close(data->file);
179
180 ext2fs_free_mem(&channel->private_data);
181 if (channel->name)
182 ext2fs_free_mem(&channel->name);
183 ext2fs_free_mem(&channel);
184 return retval;
185}
186
187static errcode_t inode_set_blksize(io_channel channel, int blksize)
188{
189 struct inode_private_data *data;
190
191 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
192 data = (struct inode_private_data *) channel->private_data;
193 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
194
195 channel->block_size = blksize;
196 return 0;
197}
198
199
200static errcode_t inode_read_blk(io_channel channel, unsigned long block,
201 int count, void *buf)
202{
203 struct inode_private_data *data;
204 errcode_t retval;
205
206 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
207 data = (struct inode_private_data *) channel->private_data;
208 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
209
210 if ((retval = ext2fs_file_lseek(data->file,
211 block * channel->block_size,
212 EXT2_SEEK_SET, 0)))
213 return retval;
214
215 count = (count < 0) ? -count : (count * channel->block_size);
216
217 return ext2fs_file_read(data->file, buf, count, 0);
218}
219
220static errcode_t inode_write_blk(io_channel channel, unsigned long block,
221 int count, const void *buf)
222{
223 struct inode_private_data *data;
224 errcode_t retval;
225
226 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
227 data = (struct inode_private_data *) channel->private_data;
228 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
229
230 if ((retval = ext2fs_file_lseek(data->file,
231 block * channel->block_size,
232 EXT2_SEEK_SET, 0)))
233 return retval;
234
235 count = (count < 0) ? -count : (count * channel->block_size);
236
237 return ext2fs_file_write(data->file, buf, count, 0);
238}
239
240static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
241 int size, const void *buf)
242{
243 struct inode_private_data *data;
244 errcode_t retval = 0;
245
246 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
247 data = (struct inode_private_data *) channel->private_data;
248 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
249
250 if ((retval = ext2fs_file_lseek(data->file, offset,
251 EXT2_SEEK_SET, 0)))
252 return retval;
253
254 return ext2fs_file_write(data->file, buf, size, 0);
255}
256
257/*
258 * Flush data buffers to disk.
259 */
260static errcode_t inode_flush(io_channel channel)
261{
262 struct inode_private_data *data;
263
264 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
265 data = (struct inode_private_data *) channel->private_data;
266 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
267
268 return ext2fs_file_flush(data->file);
269}
270
diff --git a/e2fsprogs/ext2fs/io_manager.c b/e2fsprogs/ext2fs/io_manager.c
new file mode 100644
index 000000000..e50d7e414
--- /dev/null
+++ b/e2fsprogs/ext2fs/io_manager.c
@@ -0,0 +1,69 @@
1/*
2 * io_manager.c --- the I/O manager abstraction
3 */
4
5#include <stdio.h>
6#include <string.h>
7#if HAVE_UNISTD_H
8#include <unistd.h>
9#endif
10#include <fcntl.h>
11#include <time.h>
12#if HAVE_SYS_STAT_H
13#include <sys/stat.h>
14#endif
15#if HAVE_SYS_TYPES_H
16#include <sys/types.h>
17#endif
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22errcode_t io_channel_set_options(io_channel channel, const char *opts)
23{
24 errcode_t retval = 0;
25 char *next, *ptr, *options, *arg;
26
27 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
28
29 if (!opts)
30 return 0;
31
32 if (!channel->manager->set_option)
33 return EXT2_ET_INVALID_ARGUMENT;
34
35 options = malloc(strlen(opts)+1);
36 if (!options)
37 return EXT2_ET_NO_MEMORY;
38 strcpy(options, opts);
39 ptr = options;
40
41 while (ptr && *ptr) {
42 next = strchr(ptr, '&');
43 if (next)
44 *next++ = 0;
45
46 arg = strchr(ptr, '=');
47 if (arg)
48 *arg++ = 0;
49
50 retval = (channel->manager->set_option)(channel, ptr, arg);
51 if (retval)
52 break;
53 ptr = next;
54 }
55 free(options);
56 return retval;
57}
58
59errcode_t io_channel_write_byte(io_channel channel, unsigned long offset,
60 int count, const void *data)
61{
62 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
63
64 if (channel->manager->write_byte)
65 return channel->manager->write_byte(channel, offset,
66 count, data);
67
68 return EXT2_ET_UNIMPLEMENTED;
69}
diff --git a/e2fsprogs/ext2fs/irel.h b/e2fsprogs/ext2fs/irel.h
new file mode 100644
index 000000000..9b943ced1
--- /dev/null
+++ b/e2fsprogs/ext2fs/irel.h
@@ -0,0 +1,114 @@
1/*
2 * irel.h
3 *
4 * Copyright (C) 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12struct ext2_inode_reference {
13 blk_t block;
14 __u16 offset;
15};
16
17struct ext2_inode_relocate_entry {
18 ext2_ino_t new;
19 ext2_ino_t orig;
20 __u16 flags;
21 __u16 max_refs;
22};
23
24typedef struct ext2_inode_relocation_table *ext2_irel;
25
26struct ext2_inode_relocation_table {
27 __u32 magic;
28 char *name;
29 ext2_ino_t current;
30 void *priv_data;
31
32 /*
33 * Add an inode relocation entry.
34 */
35 errcode_t (*put)(ext2_irel irel, ext2_ino_t old,
36 struct ext2_inode_relocate_entry *ent);
37 /*
38 * Get an inode relocation entry.
39 */
40 errcode_t (*get)(ext2_irel irel, ext2_ino_t old,
41 struct ext2_inode_relocate_entry *ent);
42
43 /*
44 * Get an inode relocation entry by its original inode number
45 */
46 errcode_t (*get_by_orig)(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
47 struct ext2_inode_relocate_entry *ent);
48
49 /*
50 * Initialize for iterating over the inode relocation entries.
51 */
52 errcode_t (*start_iter)(ext2_irel irel);
53
54 /*
55 * The iterator function for the inode relocation entries.
56 * Returns an inode number of 0 when out of entries.
57 */
58 errcode_t (*next)(ext2_irel irel, ext2_ino_t *old,
59 struct ext2_inode_relocate_entry *ent);
60
61 /*
62 * Add an inode reference (i.e., note the fact that a
63 * particular block/offset contains a reference to an inode)
64 */
65 errcode_t (*add_ref)(ext2_irel irel, ext2_ino_t ino,
66 struct ext2_inode_reference *ref);
67
68 /*
69 * Initialize for iterating over the inode references for a
70 * particular inode.
71 */
72 errcode_t (*start_iter_ref)(ext2_irel irel, ext2_ino_t ino);
73
74 /*
75 * The iterator function for the inode references for an
76 * inode. The references for only one inode can be interator
77 * over at a time, as the iterator state is stored in ext2_irel.
78 */
79 errcode_t (*next_ref)(ext2_irel irel,
80 struct ext2_inode_reference *ref);
81
82 /*
83 * Move the inode relocation table from one inode number to
84 * another. Note that the inode references also must move.
85 */
86 errcode_t (*move)(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
87
88 /*
89 * Remove an inode relocation entry, along with all of the
90 * inode references.
91 */
92 errcode_t (*delete)(ext2_irel irel, ext2_ino_t old);
93
94 /*
95 * Free the inode relocation table.
96 */
97 errcode_t (*free)(ext2_irel irel);
98};
99
100errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
101 ext2_irel *irel);
102
103#define ext2fs_irel_put(irel, old, ent) ((irel)->put((irel), old, ent))
104#define ext2fs_irel_get(irel, old, ent) ((irel)->get((irel), old, ent))
105#define ext2fs_irel_get_by_orig(irel, orig, old, ent) \
106 ((irel)->get_by_orig((irel), orig, old, ent))
107#define ext2fs_irel_start_iter(irel) ((irel)->start_iter((irel)))
108#define ext2fs_irel_next(irel, old, ent) ((irel)->next((irel), old, ent))
109#define ext2fs_irel_add_ref(irel, ino, ref) ((irel)->add_ref((irel), ino, ref))
110#define ext2fs_irel_start_iter_ref(irel, ino) ((irel)->start_iter_ref((irel), ino))
111#define ext2fs_irel_next_ref(irel, ref) ((irel)->next_ref((irel), ref))
112#define ext2fs_irel_move(irel, old, new) ((irel)->move((irel), old, new))
113#define ext2fs_irel_delete(irel, old) ((irel)->delete((irel), old))
114#define ext2fs_irel_free(irel) ((irel)->free((irel)))
diff --git a/e2fsprogs/ext2fs/irel_ma.c b/e2fsprogs/ext2fs/irel_ma.c
new file mode 100644
index 000000000..eedbe55c8
--- /dev/null
+++ b/e2fsprogs/ext2fs/irel_ma.c
@@ -0,0 +1,372 @@
1/*
2 * irel_ma.c
3 *
4 * Copyright (C) 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <fcntl.h>
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 "ext2fs.h"
24#include "irel.h"
25
26static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
27 struct ext2_inode_relocate_entry *ent);
28static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
29 struct ext2_inode_relocate_entry *ent);
30static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
31 struct ext2_inode_relocate_entry *ent);
32static errcode_t ima_start_iter(ext2_irel irel);
33static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
34 struct ext2_inode_relocate_entry *ent);
35static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
36 struct ext2_inode_reference *ref);
37static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino);
38static errcode_t ima_next_ref(ext2_irel irel, struct ext2_inode_reference *ref);
39static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
40static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old);
41static errcode_t ima_free(ext2_irel irel);
42
43/*
44 * This data structure stores the array of inode references; there is
45 * a structure for each inode.
46 */
47struct inode_reference_entry {
48 __u16 num;
49 struct ext2_inode_reference *refs;
50};
51
52struct irel_ma {
53 __u32 magic;
54 ext2_ino_t max_inode;
55 ext2_ino_t ref_current;
56 int ref_iter;
57 ext2_ino_t *orig_map;
58 struct ext2_inode_relocate_entry *entries;
59 struct inode_reference_entry *ref_entries;
60};
61
62errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
63 ext2_irel *new_irel)
64{
65 ext2_irel irel = 0;
66 errcode_t retval;
67 struct irel_ma *ma = 0;
68 size_t size;
69
70 *new_irel = 0;
71
72 /*
73 * Allocate memory structures
74 */
75 retval = ext2fs_get_mem(sizeof(struct ext2_inode_relocation_table),
76 &irel);
77 if (retval)
78 goto errout;
79 memset(irel, 0, sizeof(struct ext2_inode_relocation_table));
80
81 retval = ext2fs_get_mem(strlen(name)+1, &irel->name);
82 if (retval)
83 goto errout;
84 strcpy(irel->name, name);
85
86 retval = ext2fs_get_mem(sizeof(struct irel_ma), &ma);
87 if (retval)
88 goto errout;
89 memset(ma, 0, sizeof(struct irel_ma));
90 irel->priv_data = ma;
91
92 size = (size_t) (sizeof(ext2_ino_t) * (max_inode+1));
93 retval = ext2fs_get_mem(size, &ma->orig_map);
94 if (retval)
95 goto errout;
96 memset(ma->orig_map, 0, size);
97
98 size = (size_t) (sizeof(struct ext2_inode_relocate_entry) *
99 (max_inode+1));
100 retval = ext2fs_get_mem(size, &ma->entries);
101 if (retval)
102 goto errout;
103 memset(ma->entries, 0, size);
104
105 size = (size_t) (sizeof(struct inode_reference_entry) *
106 (max_inode+1));
107 retval = ext2fs_get_mem(size, &ma->ref_entries);
108 if (retval)
109 goto errout;
110 memset(ma->ref_entries, 0, size);
111 ma->max_inode = max_inode;
112
113 /*
114 * Fill in the irel data structure
115 */
116 irel->put = ima_put;
117 irel->get = ima_get;
118 irel->get_by_orig = ima_get_by_orig;
119 irel->start_iter = ima_start_iter;
120 irel->next = ima_next;
121 irel->add_ref = ima_add_ref;
122 irel->start_iter_ref = ima_start_iter_ref;
123 irel->next_ref = ima_next_ref;
124 irel->move = ima_move;
125 irel->delete = ima_delete;
126 irel->free = ima_free;
127
128 *new_irel = irel;
129 return 0;
130
131errout:
132 ima_free(irel);
133 return retval;
134}
135
136static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
137 struct ext2_inode_relocate_entry *ent)
138{
139 struct inode_reference_entry *ref_ent;
140 struct irel_ma *ma;
141 errcode_t retval;
142 size_t size, old_size;
143
144 ma = irel->priv_data;
145 if (old > ma->max_inode)
146 return EXT2_ET_INVALID_ARGUMENT;
147
148 /*
149 * Force the orig field to the correct value; the application
150 * program shouldn't be messing with this field.
151 */
152 if (ma->entries[(unsigned) old].new == 0)
153 ent->orig = old;
154 else
155 ent->orig = ma->entries[(unsigned) old].orig;
156
157 /*
158 * If max_refs has changed, reallocate the refs array
159 */
160 ref_ent = ma->ref_entries + (unsigned) old;
161 if (ref_ent->refs && ent->max_refs !=
162 ma->entries[(unsigned) old].max_refs) {
163 size = (sizeof(struct ext2_inode_reference) * ent->max_refs);
164 old_size = (sizeof(struct ext2_inode_reference) *
165 ma->entries[(unsigned) old].max_refs);
166 retval = ext2fs_resize_mem(old_size, size, &ref_ent->refs);
167 if (retval)
168 return retval;
169 }
170
171 ma->entries[(unsigned) old] = *ent;
172 ma->orig_map[(unsigned) ent->orig] = old;
173 return 0;
174}
175
176static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
177 struct ext2_inode_relocate_entry *ent)
178{
179 struct irel_ma *ma;
180
181 ma = irel->priv_data;
182 if (old > ma->max_inode)
183 return EXT2_ET_INVALID_ARGUMENT;
184 if (ma->entries[(unsigned) old].new == 0)
185 return ENOENT;
186 *ent = ma->entries[(unsigned) old];
187 return 0;
188}
189
190static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
191 struct ext2_inode_relocate_entry *ent)
192{
193 struct irel_ma *ma;
194 ext2_ino_t ino;
195
196 ma = irel->priv_data;
197 if (orig > ma->max_inode)
198 return EXT2_ET_INVALID_ARGUMENT;
199 ino = ma->orig_map[(unsigned) orig];
200 if (ino == 0)
201 return ENOENT;
202 *old = ino;
203 *ent = ma->entries[(unsigned) ino];
204 return 0;
205}
206
207static errcode_t ima_start_iter(ext2_irel irel)
208{
209 irel->current = 0;
210 return 0;
211}
212
213static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
214 struct ext2_inode_relocate_entry *ent)
215{
216 struct irel_ma *ma;
217
218 ma = irel->priv_data;
219 while (++irel->current < ma->max_inode) {
220 if (ma->entries[(unsigned) irel->current].new == 0)
221 continue;
222 *old = irel->current;
223 *ent = ma->entries[(unsigned) irel->current];
224 return 0;
225 }
226 *old = 0;
227 return 0;
228}
229
230static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
231 struct ext2_inode_reference *ref)
232{
233 struct irel_ma *ma;
234 size_t size;
235 struct inode_reference_entry *ref_ent;
236 struct ext2_inode_relocate_entry *ent;
237 errcode_t retval;
238
239 ma = irel->priv_data;
240 if (ino > ma->max_inode)
241 return EXT2_ET_INVALID_ARGUMENT;
242
243 ref_ent = ma->ref_entries + (unsigned) ino;
244 ent = ma->entries + (unsigned) ino;
245
246 /*
247 * If the inode reference array doesn't exist, create it.
248 */
249 if (ref_ent->refs == 0) {
250 size = (size_t) ((sizeof(struct ext2_inode_reference) *
251 ent->max_refs));
252 retval = ext2fs_get_mem(size, &ref_ent->refs);
253 if (retval)
254 return retval;
255 memset(ref_ent->refs, 0, size);
256 ref_ent->num = 0;
257 }
258
259 if (ref_ent->num >= ent->max_refs)
260 return EXT2_ET_TOO_MANY_REFS;
261
262 ref_ent->refs[(unsigned) ref_ent->num++] = *ref;
263 return 0;
264}
265
266static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino)
267{
268 struct irel_ma *ma;
269
270 ma = irel->priv_data;
271 if (ino > ma->max_inode)
272 return EXT2_ET_INVALID_ARGUMENT;
273 if (ma->entries[(unsigned) ino].new == 0)
274 return ENOENT;
275 ma->ref_current = ino;
276 ma->ref_iter = 0;
277 return 0;
278}
279
280static errcode_t ima_next_ref(ext2_irel irel,
281 struct ext2_inode_reference *ref)
282{
283 struct irel_ma *ma;
284 struct inode_reference_entry *ref_ent;
285
286 ma = irel->priv_data;
287
288 ref_ent = ma->ref_entries + ma->ref_current;
289
290 if ((ref_ent->refs == NULL) ||
291 (ma->ref_iter >= ref_ent->num)) {
292 ref->block = 0;
293 ref->offset = 0;
294 return 0;
295 }
296 *ref = ref_ent->refs[ma->ref_iter++];
297 return 0;
298}
299
300
301static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new)
302{
303 struct irel_ma *ma;
304
305 ma = irel->priv_data;
306 if ((old > ma->max_inode) || (new > ma->max_inode))
307 return EXT2_ET_INVALID_ARGUMENT;
308 if (ma->entries[(unsigned) old].new == 0)
309 return ENOENT;
310
311 ma->entries[(unsigned) new] = ma->entries[(unsigned) old];
312 if (ma->ref_entries[(unsigned) new].refs)
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 if (ma->ref_entries[(unsigned) old].refs)
336 ext2fs_free_mem(&ma->ref_entries[(unsigned) old].refs);
337 ma->orig_map[ma->entries[(unsigned) old].orig] = 0;
338
339 ma->ref_entries[(unsigned) old].num = 0;
340 ma->ref_entries[(unsigned) old].refs = 0;
341 return 0;
342}
343
344static errcode_t ima_free(ext2_irel irel)
345{
346 struct irel_ma *ma;
347 ext2_ino_t ino;
348
349 if (!irel)
350 return 0;
351
352 ma = irel->priv_data;
353
354 if (ma) {
355 if (ma->orig_map)
356 ext2fs_free_mem(&ma->orig_map);
357 if (ma->entries)
358 ext2fs_free_mem(&ma->entries);
359 if (ma->ref_entries) {
360 for (ino = 0; ino <= ma->max_inode; ino++) {
361 if (ma->ref_entries[(unsigned) ino].refs)
362 ext2fs_free_mem(&ma->ref_entries[(unsigned) ino].refs);
363 }
364 ext2fs_free_mem(&ma->ref_entries);
365 }
366 ext2fs_free_mem(&ma);
367 }
368 if (irel->name)
369 ext2fs_free_mem(&irel->name);
370 ext2fs_free_mem(&irel);
371 return 0;
372}
diff --git a/e2fsprogs/ext2fs/ismounted.c b/e2fsprogs/ext2fs/ismounted.c
new file mode 100644
index 000000000..3f2241d23
--- /dev/null
+++ b/e2fsprogs/ext2fs/ismounted.c
@@ -0,0 +1,358 @@
1/*
2 * ismounted.c --- Check to see if the filesystem was mounted
3 *
4 * Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#if HAVE_UNISTD_H
14#include <unistd.h>
15#endif
16#if HAVE_ERRNO_H
17#include <errno.h>
18#endif
19#include <fcntl.h>
20#ifdef HAVE_LINUX_FD_H
21#include <linux/fd.h>
22#endif
23#ifdef HAVE_MNTENT_H
24#include <mntent.h>
25#endif
26#ifdef HAVE_GETMNTINFO
27#include <paths.h>
28#include <sys/param.h>
29#include <sys/mount.h>
30#endif /* HAVE_GETMNTINFO */
31#include <string.h>
32#include <sys/stat.h>
33
34#include "ext2_fs.h"
35#include "ext2fs.h"
36
37#ifdef HAVE_MNTENT_H
38/*
39 * Helper function which checks a file in /etc/mtab format to see if a
40 * filesystem is mounted. Returns an error if the file doesn't exist
41 * or can't be opened.
42 */
43static errcode_t check_mntent_file(const char *mtab_file, const char *file,
44 int *mount_flags, char *mtpt, int mtlen)
45{
46 struct mntent *mnt;
47 struct stat st_buf;
48 errcode_t retval = 0;
49 dev_t file_dev=0, file_rdev=0;
50 ino_t file_ino=0;
51 FILE *f;
52 int fd;
53
54 *mount_flags = 0;
55 if ((f = setmntent (mtab_file, "r")) == NULL)
56 return errno;
57 if (stat(file, &st_buf) == 0) {
58 if (S_ISBLK(st_buf.st_mode)) {
59#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
60 file_rdev = st_buf.st_rdev;
61#endif /* __GNU__ */
62 } else {
63 file_dev = st_buf.st_dev;
64 file_ino = st_buf.st_ino;
65 }
66 }
67 while ((mnt = getmntent (f)) != NULL) {
68 if (strcmp(file, mnt->mnt_fsname) == 0)
69 break;
70 if (stat(mnt->mnt_fsname, &st_buf) == 0) {
71 if (S_ISBLK(st_buf.st_mode)) {
72#ifndef __GNU__
73 if (file_rdev && (file_rdev == st_buf.st_rdev))
74 break;
75#endif /* __GNU__ */
76 } else {
77 if (file_dev && ((file_dev == st_buf.st_dev) &&
78 (file_ino == st_buf.st_ino)))
79 break;
80 }
81 }
82 }
83
84 if (mnt == 0) {
85#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
86 /*
87 * Do an extra check to see if this is the root device. We
88 * can't trust /etc/mtab, and /proc/mounts will only list
89 * /dev/root for the root filesystem. Argh. Instead we
90 * check if the given device has the same major/minor number
91 * as the device that the root directory is on.
92 */
93 if (file_rdev && stat("/", &st_buf) == 0) {
94 if (st_buf.st_dev == file_rdev) {
95 *mount_flags = EXT2_MF_MOUNTED;
96 if (mtpt)
97 strncpy(mtpt, "/", mtlen);
98 goto is_root;
99 }
100 }
101#endif /* __GNU__ */
102 goto errout;
103 }
104#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
105 /* Validate the entry in case /etc/mtab is out of date */
106 /*
107 * We need to be paranoid, because some broken distributions
108 * (read: Slackware) don't initialize /etc/mtab before checking
109 * all of the non-root filesystems on the disk.
110 */
111 if (stat(mnt->mnt_dir, &st_buf) < 0) {
112 retval = errno;
113 if (retval == ENOENT) {
114#ifdef DEBUG
115 printf("Bogus entry in %s! (%s does not exist)\n",
116 mtab_file, mnt->mnt_dir);
117#endif /* DEBUG */
118 retval = 0;
119 }
120 goto errout;
121 }
122 if (file_rdev && (st_buf.st_dev != file_rdev)) {
123#ifdef DEBUG
124 printf("Bogus entry in %s! (%s not mounted on %s)\n",
125 mtab_file, file, mnt->mnt_dir);
126#endif /* DEBUG */
127 goto errout;
128 }
129#endif /* __GNU__ */
130 *mount_flags = EXT2_MF_MOUNTED;
131
132#ifdef MNTOPT_RO
133 /* Check to see if the ro option is set */
134 if (hasmntopt(mnt, MNTOPT_RO))
135 *mount_flags |= EXT2_MF_READONLY;
136#endif
137
138 if (mtpt)
139 strncpy(mtpt, mnt->mnt_dir, mtlen);
140 /*
141 * Check to see if we're referring to the root filesystem.
142 * If so, do a manual check to see if we can open /etc/mtab
143 * read/write, since if the root is mounted read/only, the
144 * contents of /etc/mtab may not be accurate.
145 */
146 if (!strcmp(mnt->mnt_dir, "/")) {
147is_root:
148#define TEST_FILE "/.ismount-test-file"
149 *mount_flags |= EXT2_MF_ISROOT;
150 fd = open(TEST_FILE, O_RDWR|O_CREAT);
151 if (fd < 0) {
152 if (errno == EROFS)
153 *mount_flags |= EXT2_MF_READONLY;
154 } else
155 close(fd);
156 (void) unlink(TEST_FILE);
157 }
158 retval = 0;
159errout:
160 endmntent (f);
161 return retval;
162}
163
164static errcode_t check_mntent(const char *file, int *mount_flags,
165 char *mtpt, int mtlen)
166{
167 errcode_t retval;
168
169#ifdef DEBUG
170 retval = check_mntent_file("/tmp/mtab", file, mount_flags,
171 mtpt, mtlen);
172 if (retval == 0)
173 return 0;
174#endif /* DEBUG */
175#ifdef __linux__
176 retval = check_mntent_file("/proc/mounts", file, mount_flags,
177 mtpt, mtlen);
178 if (retval == 0 && (*mount_flags != 0))
179 return 0;
180#endif /* __linux__ */
181#if defined(MOUNTED) || defined(_PATH_MOUNTED)
182#ifndef MOUNTED
183#define MOUNTED _PATH_MOUNTED
184#endif /* MOUNTED */
185 retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen);
186 return retval;
187#else
188 *mount_flags = 0;
189 return 0;
190#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
191}
192
193#else
194#if defined(HAVE_GETMNTINFO)
195
196static errcode_t check_getmntinfo(const char *file, int *mount_flags,
197 char *mtpt, int mtlen)
198{
199 struct statfs *mp;
200 int len, n;
201 const char *s1;
202 char *s2;
203
204 n = getmntinfo(&mp, MNT_NOWAIT);
205 if (n == 0)
206 return errno;
207
208 len = sizeof(_PATH_DEV) - 1;
209 s1 = file;
210 if (strncmp(_PATH_DEV, s1, len) == 0)
211 s1 += len;
212
213 *mount_flags = 0;
214 while (--n >= 0) {
215 s2 = mp->f_mntfromname;
216 if (strncmp(_PATH_DEV, s2, len) == 0) {
217 s2 += len - 1;
218 *s2 = 'r';
219 }
220 if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
221 *mount_flags = EXT2_MF_MOUNTED;
222 break;
223 }
224 ++mp;
225 }
226 if (mtpt)
227 strncpy(mtpt, mp->f_mntonname, mtlen);
228 return 0;
229}
230#endif /* HAVE_GETMNTINFO */
231#endif /* HAVE_MNTENT_H */
232
233/*
234 * Check to see if we're dealing with the swap device.
235 */
236static int is_swap_device(const char *file)
237{
238 FILE *f;
239 char buf[1024], *cp;
240 dev_t file_dev;
241 struct stat st_buf;
242 int ret = 0;
243
244 file_dev = 0;
245#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
246 if ((stat(file, &st_buf) == 0) &&
247 S_ISBLK(st_buf.st_mode))
248 file_dev = st_buf.st_rdev;
249#endif /* __GNU__ */
250
251 if (!(f = fopen("/proc/swaps", "r")))
252 return 0;
253 /* Skip the first line */
254 fgets(buf, sizeof(buf), f);
255 while (!feof(f)) {
256 if (!fgets(buf, sizeof(buf), f))
257 break;
258 if ((cp = strchr(buf, ' ')) != NULL)
259 *cp = 0;
260 if ((cp = strchr(buf, '\t')) != NULL)
261 *cp = 0;
262 if (strcmp(buf, file) == 0) {
263 ret++;
264 break;
265 }
266#ifndef __GNU__
267 if (file_dev && (stat(buf, &st_buf) == 0) &&
268 S_ISBLK(st_buf.st_mode) &&
269 file_dev == st_buf.st_rdev) {
270 ret++;
271 break;
272 }
273#endif /* __GNU__ */
274 }
275 fclose(f);
276 return ret;
277}
278
279
280/*
281 * ext2fs_check_mount_point() returns 1 if the device is mounted, 0
282 * otherwise. If mtpt is non-NULL, the directory where the device is
283 * mounted is copied to where mtpt is pointing, up to mtlen
284 * characters.
285 */
286#ifdef __TURBOC__
287 #pragma argsused
288#endif
289errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
290 char *mtpt, int mtlen)
291{
292 if (is_swap_device(device)) {
293 *mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP;
294 strncpy(mtpt, "<swap>", mtlen);
295 return 0;
296 }
297#ifdef HAVE_MNTENT_H
298 return check_mntent(device, mount_flags, mtpt, mtlen);
299#else
300#ifdef HAVE_GETMNTINFO
301 return check_getmntinfo(device, mount_flags, mtpt, mtlen);
302#else
303#ifdef __GNUC__
304 #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
305#endif
306 *mount_flags = 0;
307 return 0;
308#endif /* HAVE_GETMNTINFO */
309#endif /* HAVE_MNTENT_H */
310}
311
312/*
313 * ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED,
314 * EXT2_MF_READONLY, and EXT2_MF_ROOT
315 *
316 */
317errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags)
318{
319 return ext2fs_check_mount_point(file, mount_flags, NULL, 0);
320}
321
322#ifdef DEBUG
323int main(int argc, char **argv)
324{
325 int retval, mount_flags;
326 char mntpt[80];
327
328 if (argc < 2) {
329 fprintf(stderr, "Usage: %s device\n", argv[0]);
330 exit(1);
331 }
332
333 mntpt[0] = 0;
334 retval = ext2fs_check_mount_point(argv[1], &mount_flags,
335 mntpt, sizeof(mntpt));
336 if (retval) {
337 com_err(argv[0], retval,
338 "while calling ext2fs_check_if_mounted");
339 exit(1);
340 }
341 printf("Device %s reports flags %02x\n", argv[1], mount_flags);
342 if (mount_flags & EXT2_MF_MOUNTED)
343 printf("\t%s is mounted.\n", argv[1]);
344
345 if (mount_flags & EXT2_MF_SWAP)
346 printf("\t%s is a swap device.\n", argv[1]);
347
348 if (mount_flags & EXT2_MF_READONLY)
349 printf("\t%s is read-only.\n", argv[1]);
350
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
356 exit(0);
357}
358#endif /* DEBUG */
diff --git a/e2fsprogs/ext2fs/jfs_compat.h b/e2fsprogs/ext2fs/jfs_compat.h
new file mode 100644
index 000000000..30ad1ef5e
--- /dev/null
+++ b/e2fsprogs/ext2fs/jfs_compat.h
@@ -0,0 +1,67 @@
1
2#ifndef _JFS_COMPAT_H
3#define _JFS_COMPAT_H
4
5#include "kernel-list.h"
6#include <errno.h>
7#ifdef HAVE_NETINET_IN_H
8#include <netinet/in.h>
9#endif
10
11#define printk printf
12#define KERN_ERR ""
13#define KERN_DEBUG ""
14
15#define READ 0
16#define WRITE 1
17
18#define cpu_to_be32(n) htonl(n)
19#define be32_to_cpu(n) ntohl(n)
20
21typedef unsigned int tid_t;
22typedef struct journal_s journal_t;
23
24struct buffer_head;
25struct inode;
26
27struct journal_s
28{
29 unsigned long j_flags;
30 int j_errno;
31 struct buffer_head * j_sb_buffer;
32 struct journal_superblock_s *j_superblock;
33 int j_format_version;
34 unsigned long j_head;
35 unsigned long j_tail;
36 unsigned long j_free;
37 unsigned long j_first, j_last;
38 kdev_t j_dev;
39 kdev_t j_fs_dev;
40 int j_blocksize;
41 unsigned int j_blk_offset;
42 unsigned int j_maxlen;
43 struct inode * j_inode;
44 tid_t j_tail_sequence;
45 tid_t j_transaction_sequence;
46 __u8 j_uuid[16];
47 struct jbd_revoke_table_s *j_revoke;
48};
49
50#define J_ASSERT(assert) \
51 do { if (!(assert)) { \
52 printf ("Assertion failure in %s() at %s line %d: " \
53 "\"%s\"\n", \
54 __FUNCTION__, __FILE__, __LINE__, # assert); \
55 fatal_error(e2fsck_global_ctx, 0); \
56 } } while (0)
57
58#define is_journal_abort(x) 0
59
60#define BUFFER_TRACE(bh, info) do {} while (0)
61
62/* Need this so we can compile with configure --enable-gcc-wall */
63#ifdef NO_INLINE_FUNCS
64#define inline
65#endif
66
67#endif /* _JFS_COMPAT_H */
diff --git a/e2fsprogs/ext2fs/jfs_dat.h b/e2fsprogs/ext2fs/jfs_dat.h
new file mode 100644
index 000000000..d6ad9c489
--- /dev/null
+++ b/e2fsprogs/ext2fs/jfs_dat.h
@@ -0,0 +1,64 @@
1/*
2 * jfs_dat.h --- stripped down header file which only contains the JFS
3 * on-disk data structures
4 */
5
6#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
7
8/*
9 * On-disk structures
10 */
11
12/*
13 * Descriptor block types:
14 */
15
16#define JFS_DESCRIPTOR_BLOCK 1
17#define JFS_COMMIT_BLOCK 2
18#define JFS_SUPERBLOCK 3
19
20/*
21 * Standard header for all descriptor blocks:
22 */
23typedef struct journal_header_s
24{
25 __u32 h_magic;
26 __u32 h_blocktype;
27 __u32 h_sequence;
28} journal_header_t;
29
30
31/*
32 * The block tag: used to describe a single buffer in the journal
33 */
34typedef struct journal_block_tag_s
35{
36 __u32 t_blocknr; /* The on-disk block number */
37 __u32 t_flags; /* See below */
38} journal_block_tag_t;
39
40/* Definitions for the journal tag flags word: */
41#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */
42#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */
43#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */
44#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
45
46
47/*
48 * The journal superblock
49 */
50typedef struct journal_superblock_s
51{
52 journal_header_t s_header;
53
54 /* Static information describing the journal */
55 __u32 s_blocksize; /* journal device blocksize */
56 __u32 s_maxlen; /* total blocks in journal file */
57 __u32 s_first; /* first block of log information */
58
59 /* Dynamic information describing the current state of the log */
60 __u32 s_sequence; /* first commit ID expected in log */
61 __u32 s_start; /* blocknr of start of log */
62
63} journal_superblock_t;
64
diff --git a/e2fsprogs/ext2fs/jfs_user.h b/e2fsprogs/ext2fs/jfs_user.h
new file mode 100644
index 000000000..3a521230e
--- /dev/null
+++ b/e2fsprogs/ext2fs/jfs_user.h
@@ -0,0 +1,8 @@
1#ifndef _JFS_USER_H
2#define _JFS_USER_H
3
4typedef unsigned short kdev_t;
5
6#include "kernel-jbd.h"
7
8#endif /* _JFS_USER_H */
diff --git a/e2fsprogs/ext2fs/kernel-jbd.h b/e2fsprogs/ext2fs/kernel-jbd.h
new file mode 100644
index 000000000..d0efdb3f7
--- /dev/null
+++ b/e2fsprogs/ext2fs/kernel-jbd.h
@@ -0,0 +1,910 @@
1/*
2 * linux/include/linux/jbd.h
3 *
4 * Written by Stephen C. Tweedie <sct@redhat.com>
5 *
6 * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
7 *
8 * This file is part of the Linux kernel and is made available under
9 * the terms of the GNU General Public License, version 2, or at your
10 * option, any later version, incorporated herein by reference.
11 *
12 * Definitions for transaction data structures for the buffer cache
13 * filesystem journaling support.
14 */
15
16#ifndef _LINUX_JBD_H
17#define _LINUX_JBD_H
18
19#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE) || !defined(__KERNEL__)
20
21/* Allow this file to be included directly into e2fsprogs */
22#ifndef __KERNEL__
23#include "jfs_compat.h"
24#define JFS_DEBUG
25#define jfs_debug jbd_debug
26#else
27
28#include <linux/journal-head.h>
29#include <linux/stddef.h>
30#include <asm/semaphore.h>
31#endif
32
33#ifndef __GNUC__
34#define __FUNCTION__ ""
35#endif
36
37#define journal_oom_retry 1
38
39#ifdef __STDC__
40#ifdef __CONFIG_JBD_DEBUG__E2FS
41/*
42 * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
43 * consistency checks. By default we don't do this unless
44 * __CONFIG_JBD_DEBUG__E2FS is on.
45 */
46#define JBD_EXPENSIVE_CHECKING
47extern int journal_enable_debug;
48
49#define jbd_debug(n, f, a...) \
50 do { \
51 if ((n) <= journal_enable_debug) { \
52 printk (KERN_DEBUG "(%s, %d): %s: ", \
53 __FILE__, __LINE__, __FUNCTION__); \
54 printk (f, ## a); \
55 } \
56 } while (0)
57#else
58#ifdef __GNUC__
59#define jbd_debug(f, a...) /**/
60#else
61#define jbd_debug(f, ...) /**/
62#endif
63#endif
64#else
65#define jbd_debug(x) /* AIX doesn't do STDC */
66#endif
67
68extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry);
69#define jbd_kmalloc(size, flags) \
70 __jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry)
71#define jbd_rep_kmalloc(size, flags) \
72 __jbd_kmalloc(__FUNCTION__, (size), (flags), 1)
73
74#define JFS_MIN_JOURNAL_BLOCKS 1024
75
76#ifdef __KERNEL__
77typedef struct handle_s handle_t; /* Atomic operation type */
78typedef struct journal_s journal_t; /* Journal control structure */
79#endif
80
81/*
82 * Internal structures used by the logging mechanism:
83 */
84
85#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
86
87/*
88 * On-disk structures
89 */
90
91/*
92 * Descriptor block types:
93 */
94
95#define JFS_DESCRIPTOR_BLOCK 1
96#define JFS_COMMIT_BLOCK 2
97#define JFS_SUPERBLOCK_V1 3
98#define JFS_SUPERBLOCK_V2 4
99#define JFS_REVOKE_BLOCK 5
100
101/*
102 * Standard header for all descriptor blocks:
103 */
104typedef struct journal_header_s
105{
106 __u32 h_magic;
107 __u32 h_blocktype;
108 __u32 h_sequence;
109} journal_header_t;
110
111
112/*
113 * The block tag: used to describe a single buffer in the journal
114 */
115typedef struct journal_block_tag_s
116{
117 __u32 t_blocknr; /* The on-disk block number */
118 __u32 t_flags; /* See below */
119} journal_block_tag_t;
120
121/*
122 * The revoke descriptor: used on disk to describe a series of blocks to
123 * be revoked from the log
124 */
125typedef struct journal_revoke_header_s
126{
127 journal_header_t r_header;
128 int r_count; /* Count of bytes used in the block */
129} journal_revoke_header_t;
130
131
132/* Definitions for the journal tag flags word: */
133#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */
134#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */
135#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */
136#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
137
138
139/*
140 * The journal superblock. All fields are in big-endian byte order.
141 */
142typedef struct journal_superblock_s
143{
144/* 0x0000 */
145 journal_header_t s_header;
146
147/* 0x000C */
148 /* Static information describing the journal */
149 __u32 s_blocksize; /* journal device blocksize */
150 __u32 s_maxlen; /* total blocks in journal file */
151 __u32 s_first; /* first block of log information */
152
153/* 0x0018 */
154 /* Dynamic information describing the current state of the log */
155 __u32 s_sequence; /* first commit ID expected in log */
156 __u32 s_start; /* blocknr of start of log */
157
158/* 0x0020 */
159 /* Error value, as set by journal_abort(). */
160 __s32 s_errno;
161
162/* 0x0024 */
163 /* Remaining fields are only valid in a version-2 superblock */
164 __u32 s_feature_compat; /* compatible feature set */
165 __u32 s_feature_incompat; /* incompatible feature set */
166 __u32 s_feature_ro_compat; /* readonly-compatible feature set */
167/* 0x0030 */
168 __u8 s_uuid[16]; /* 128-bit uuid for journal */
169
170/* 0x0040 */
171 __u32 s_nr_users; /* Nr of filesystems sharing log */
172
173 __u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/
174
175/* 0x0048 */
176 __u32 s_max_transaction; /* Limit of journal blocks per trans.*/
177 __u32 s_max_trans_data; /* Limit of data blocks per trans. */
178
179/* 0x0050 */
180 __u32 s_padding[44];
181
182/* 0x0100 */
183 __u8 s_users[16*48]; /* ids of all fs'es sharing the log */
184/* 0x0400 */
185} journal_superblock_t;
186
187#define JFS_HAS_COMPAT_FEATURE(j,mask) \
188 ((j)->j_format_version >= 2 && \
189 ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
190#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \
191 ((j)->j_format_version >= 2 && \
192 ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
193#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \
194 ((j)->j_format_version >= 2 && \
195 ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
196
197#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001
198
199/* Features known to this kernel version: */
200#define JFS_KNOWN_COMPAT_FEATURES 0
201#define JFS_KNOWN_ROCOMPAT_FEATURES 0
202#define JFS_KNOWN_INCOMPAT_FEATURES JFS_FEATURE_INCOMPAT_REVOKE
203
204#ifdef __KERNEL__
205
206#include <linux/fs.h>
207#include <linux/sched.h>
208
209#define JBD_ASSERTIONS
210#ifdef JBD_ASSERTIONS
211#define J_ASSERT(assert) \
212do { \
213 if (!(assert)) { \
214 printk (KERN_EMERG \
215 "Assertion failure in %s() at %s:%d: \"%s\"\n", \
216 __FUNCTION__, __FILE__, __LINE__, # assert); \
217 BUG(); \
218 } \
219} while (0)
220
221#if defined(CONFIG_BUFFER_DEBUG)
222void buffer_assertion_failure(struct buffer_head *bh);
223#define J_ASSERT_BH(bh, expr) \
224 do { \
225 if (!(expr)) \
226 buffer_assertion_failure(bh); \
227 J_ASSERT(expr); \
228 } while (0)
229#define J_ASSERT_JH(jh, expr) J_ASSERT_BH(jh2bh(jh), expr)
230#else
231#define J_ASSERT_BH(bh, expr) J_ASSERT(expr)
232#define J_ASSERT_JH(jh, expr) J_ASSERT(expr)
233#endif
234
235#else
236#define J_ASSERT(assert)
237#endif /* JBD_ASSERTIONS */
238
239enum jbd_state_bits {
240 BH_JWrite
241 = BH_PrivateStart, /* 1 if being written to log (@@@ DEBUGGING) */
242 BH_Freed, /* 1 if buffer has been freed (truncated) */
243 BH_Revoked, /* 1 if buffer has been revoked from the log */
244 BH_RevokeValid, /* 1 if buffer revoked flag is valid */
245 BH_JBDDirty, /* 1 if buffer is dirty but journaled */
246};
247
248/* Return true if the buffer is one which JBD is managing */
249static inline int buffer_jbd(struct buffer_head *bh)
250{
251 return __buffer_state(bh, JBD);
252}
253
254static inline struct buffer_head *jh2bh(struct journal_head *jh)
255{
256 return jh->b_bh;
257}
258
259static inline struct journal_head *bh2jh(struct buffer_head *bh)
260{
261 return bh->b_private;
262}
263
264struct jbd_revoke_table_s;
265
266/* The handle_t type represents a single atomic update being performed
267 * by some process. All filesystem modifications made by the process go
268 * through this handle. Recursive operations (such as quota operations)
269 * are gathered into a single update.
270 *
271 * The buffer credits field is used to account for journaled buffers
272 * being modified by the running process. To ensure that there is
273 * enough log space for all outstanding operations, we need to limit the
274 * number of outstanding buffers possible at any time. When the
275 * operation completes, any buffer credits not used are credited back to
276 * the transaction, so that at all times we know how many buffers the
277 * outstanding updates on a transaction might possibly touch. */
278
279struct handle_s
280{
281 /* Which compound transaction is this update a part of? */
282 transaction_t * h_transaction;
283
284 /* Number of remaining buffers we are allowed to dirty: */
285 int h_buffer_credits;
286
287 /* Reference count on this handle */
288 int h_ref;
289
290 /* Field for caller's use to track errors through large fs
291 operations */
292 int h_err;
293
294 /* Flags */
295 unsigned int h_sync: 1; /* sync-on-close */
296 unsigned int h_jdata: 1; /* force data journaling */
297 unsigned int h_aborted: 1; /* fatal error on handle */
298};
299
300
301/* The transaction_t type is the guts of the journaling mechanism. It
302 * tracks a compound transaction through its various states:
303 *
304 * RUNNING: accepting new updates
305 * LOCKED: Updates still running but we don't accept new ones
306 * RUNDOWN: Updates are tidying up but have finished requesting
307 * new buffers to modify (state not used for now)
308 * FLUSH: All updates complete, but we are still writing to disk
309 * COMMIT: All data on disk, writing commit record
310 * FINISHED: We still have to keep the transaction for checkpointing.
311 *
312 * The transaction keeps track of all of the buffers modified by a
313 * running transaction, and all of the buffers committed but not yet
314 * flushed to home for finished transactions.
315 */
316
317struct transaction_s
318{
319 /* Pointer to the journal for this transaction. */
320 journal_t * t_journal;
321
322 /* Sequence number for this transaction */
323 tid_t t_tid;
324
325 /* Transaction's current state */
326 enum {
327 T_RUNNING,
328 T_LOCKED,
329 T_RUNDOWN,
330 T_FLUSH,
331 T_COMMIT,
332 T_FINISHED
333 } t_state;
334
335 /* Where in the log does this transaction's commit start? */
336 unsigned long t_log_start;
337
338 /* Doubly-linked circular list of all inodes owned by this
339 transaction */ /* AKPM: unused */
340 struct inode * t_ilist;
341
342 /* Number of buffers on the t_buffers list */
343 int t_nr_buffers;
344
345 /* Doubly-linked circular list of all buffers reserved but not
346 yet modified by this transaction */
347 struct journal_head * t_reserved_list;
348
349 /* Doubly-linked circular list of all metadata buffers owned by this
350 transaction */
351 struct journal_head * t_buffers;
352
353 /*
354 * Doubly-linked circular list of all data buffers still to be
355 * flushed before this transaction can be committed.
356 * Protected by journal_datalist_lock.
357 */
358 struct journal_head * t_sync_datalist;
359
360 /*
361 * Doubly-linked circular list of all writepage data buffers
362 * still to be written before this transaction can be committed.
363 * Protected by journal_datalist_lock.
364 */
365 struct journal_head * t_async_datalist;
366
367 /* Doubly-linked circular list of all forget buffers (superceded
368 buffers which we can un-checkpoint once this transaction
369 commits) */
370 struct journal_head * t_forget;
371
372 /*
373 * Doubly-linked circular list of all buffers still to be
374 * flushed before this transaction can be checkpointed.
375 */
376 /* Protected by journal_datalist_lock */
377 struct journal_head * t_checkpoint_list;
378
379 /* Doubly-linked circular list of temporary buffers currently
380 undergoing IO in the log */
381 struct journal_head * t_iobuf_list;
382
383 /* Doubly-linked circular list of metadata buffers being
384 shadowed by log IO. The IO buffers on the iobuf list and the
385 shadow buffers on this list match each other one for one at
386 all times. */
387 struct journal_head * t_shadow_list;
388
389 /* Doubly-linked circular list of control buffers being written
390 to the log. */
391 struct journal_head * t_log_list;
392
393 /* Number of outstanding updates running on this transaction */
394 int t_updates;
395
396 /* Number of buffers reserved for use by all handles in this
397 * transaction handle but not yet modified. */
398 int t_outstanding_credits;
399
400 /*
401 * Forward and backward links for the circular list of all
402 * transactions awaiting checkpoint.
403 */
404 /* Protected by journal_datalist_lock */
405 transaction_t *t_cpnext, *t_cpprev;
406
407 /* When will the transaction expire (become due for commit), in
408 * jiffies ? */
409 unsigned long t_expires;
410
411 /* How many handles used this transaction? */
412 int t_handle_count;
413};
414
415
416/* The journal_t maintains all of the journaling state information for a
417 * single filesystem. It is linked to from the fs superblock structure.
418 *
419 * We use the journal_t to keep track of all outstanding transaction
420 * activity on the filesystem, and to manage the state of the log
421 * writing process. */
422
423struct journal_s
424{
425 /* General journaling state flags */
426 unsigned long j_flags;
427
428 /* Is there an outstanding uncleared error on the journal (from
429 * a prior abort)? */
430 int j_errno;
431
432 /* The superblock buffer */
433 struct buffer_head * j_sb_buffer;
434 journal_superblock_t * j_superblock;
435
436 /* Version of the superblock format */
437 int j_format_version;
438
439 /* Number of processes waiting to create a barrier lock */
440 int j_barrier_count;
441
442 /* The barrier lock itself */
443 struct semaphore j_barrier;
444
445 /* Transactions: The current running transaction... */
446 transaction_t * j_running_transaction;
447
448 /* ... the transaction we are pushing to disk ... */
449 transaction_t * j_committing_transaction;
450
451 /* ... and a linked circular list of all transactions waiting
452 * for checkpointing. */
453 /* Protected by journal_datalist_lock */
454 transaction_t * j_checkpoint_transactions;
455
456 /* Wait queue for waiting for a locked transaction to start
457 committing, or for a barrier lock to be released */
458 wait_queue_head_t j_wait_transaction_locked;
459
460 /* Wait queue for waiting for checkpointing to complete */
461 wait_queue_head_t j_wait_logspace;
462
463 /* Wait queue for waiting for commit to complete */
464 wait_queue_head_t j_wait_done_commit;
465
466 /* Wait queue to trigger checkpointing */
467 wait_queue_head_t j_wait_checkpoint;
468
469 /* Wait queue to trigger commit */
470 wait_queue_head_t j_wait_commit;
471
472 /* Wait queue to wait for updates to complete */
473 wait_queue_head_t j_wait_updates;
474
475 /* Semaphore for locking against concurrent checkpoints */
476 struct semaphore j_checkpoint_sem;
477
478 /* The main journal lock, used by lock_journal() */
479 struct semaphore j_sem;
480
481 /* Journal head: identifies the first unused block in the journal. */
482 unsigned long j_head;
483
484 /* Journal tail: identifies the oldest still-used block in the
485 * journal. */
486 unsigned long j_tail;
487
488 /* Journal free: how many free blocks are there in the journal? */
489 unsigned long j_free;
490
491 /* Journal start and end: the block numbers of the first usable
492 * block and one beyond the last usable block in the journal. */
493 unsigned long j_first, j_last;
494
495 /* Device, blocksize and starting block offset for the location
496 * where we store the journal. */
497 kdev_t j_dev;
498 int j_blocksize;
499 unsigned int j_blk_offset;
500
501 /* Device which holds the client fs. For internal journal this
502 * will be equal to j_dev. */
503 kdev_t j_fs_dev;
504
505 /* Total maximum capacity of the journal region on disk. */
506 unsigned int j_maxlen;
507
508 /* Optional inode where we store the journal. If present, all
509 * journal block numbers are mapped into this inode via
510 * bmap(). */
511 struct inode * j_inode;
512
513 /* Sequence number of the oldest transaction in the log */
514 tid_t j_tail_sequence;
515 /* Sequence number of the next transaction to grant */
516 tid_t j_transaction_sequence;
517 /* Sequence number of the most recently committed transaction */
518 tid_t j_commit_sequence;
519 /* Sequence number of the most recent transaction wanting commit */
520 tid_t j_commit_request;
521
522 /* Journal uuid: identifies the object (filesystem, LVM volume
523 * etc) backed by this journal. This will eventually be
524 * replaced by an array of uuids, allowing us to index multiple
525 * devices within a single journal and to perform atomic updates
526 * across them. */
527
528 __u8 j_uuid[16];
529
530 /* Pointer to the current commit thread for this journal */
531 struct task_struct * j_task;
532
533 /* Maximum number of metadata buffers to allow in a single
534 * compound commit transaction */
535 int j_max_transaction_buffers;
536
537 /* What is the maximum transaction lifetime before we begin a
538 * commit? */
539 unsigned long j_commit_interval;
540
541 /* The timer used to wakeup the commit thread: */
542 struct timer_list * j_commit_timer;
543 int j_commit_timer_active;
544
545 /* Link all journals together - system-wide */
546 struct list_head j_all_journals;
547
548 /* The revoke table: maintains the list of revoked blocks in the
549 current transaction. */
550 struct jbd_revoke_table_s *j_revoke;
551};
552
553/*
554 * Journal flag definitions
555 */
556#define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */
557#define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */
558#define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */
559#define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */
560#define JFS_LOADED 0x010 /* The journal superblock has been loaded */
561
562/*
563 * Function declarations for the journaling transaction and buffer
564 * management
565 */
566
567/* Filing buffers */
568extern void __journal_unfile_buffer(struct journal_head *);
569extern void journal_unfile_buffer(struct journal_head *);
570extern void __journal_refile_buffer(struct journal_head *);
571extern void journal_refile_buffer(struct journal_head *);
572extern void __journal_file_buffer(struct journal_head *, transaction_t *, int);
573extern void __journal_free_buffer(struct journal_head *bh);
574extern void journal_file_buffer(struct journal_head *, transaction_t *, int);
575extern void __journal_clean_data_list(transaction_t *transaction);
576
577/* Log buffer allocation */
578extern struct journal_head * journal_get_descriptor_buffer(journal_t *);
579extern unsigned long journal_next_log_block(journal_t *);
580
581/* Commit management */
582extern void journal_commit_transaction(journal_t *);
583
584/* Checkpoint list management */
585int __journal_clean_checkpoint_list(journal_t *journal);
586extern void journal_remove_checkpoint(struct journal_head *);
587extern void __journal_remove_checkpoint(struct journal_head *);
588extern void journal_insert_checkpoint(struct journal_head *, transaction_t *);
589extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *);
590
591/* Buffer IO */
592extern int
593journal_write_metadata_buffer(transaction_t *transaction,
594 struct journal_head *jh_in,
595 struct journal_head **jh_out,
596 int blocknr);
597
598/* Transaction locking */
599extern void __wait_on_journal (journal_t *);
600
601/*
602 * Journal locking.
603 *
604 * We need to lock the journal during transaction state changes so that
605 * nobody ever tries to take a handle on the running transaction while
606 * we are in the middle of moving it to the commit phase.
607 *
608 * Note that the locking is completely interrupt unsafe. We never touch
609 * journal structures from interrupts.
610 *
611 * In 2.2, the BKL was required for lock_journal. This is no longer
612 * the case.
613 */
614
615static inline void lock_journal(journal_t *journal)
616{
617 down(&journal->j_sem);
618}
619
620/* This returns zero if we acquired the semaphore */
621static inline int try_lock_journal(journal_t * journal)
622{
623 return down_trylock(&journal->j_sem);
624}
625
626static inline void unlock_journal(journal_t * journal)
627{
628 up(&journal->j_sem);
629}
630
631
632static inline handle_t *journal_current_handle(void)
633{
634 return current->journal_info;
635}
636
637/* The journaling code user interface:
638 *
639 * Create and destroy handles
640 * Register buffer modifications against the current transaction.
641 */
642
643extern handle_t *journal_start(journal_t *, int nblocks);
644extern handle_t *journal_try_start(journal_t *, int nblocks);
645extern int journal_restart (handle_t *, int nblocks);
646extern int journal_extend (handle_t *, int nblocks);
647extern int journal_get_write_access (handle_t *, struct buffer_head *);
648extern int journal_get_create_access (handle_t *, struct buffer_head *);
649extern int journal_get_undo_access (handle_t *, struct buffer_head *);
650extern int journal_dirty_data (handle_t *,
651 struct buffer_head *, int async);
652extern int journal_dirty_metadata (handle_t *, struct buffer_head *);
653extern void journal_release_buffer (handle_t *, struct buffer_head *);
654extern void journal_forget (handle_t *, struct buffer_head *);
655extern void journal_sync_buffer (struct buffer_head *);
656extern int journal_flushpage(journal_t *, struct page *, unsigned long);
657extern int journal_try_to_free_buffers(journal_t *, struct page *, int);
658extern int journal_stop(handle_t *);
659extern int journal_flush (journal_t *);
660
661extern void journal_lock_updates (journal_t *);
662extern void journal_unlock_updates (journal_t *);
663
664extern journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev,
665 int start, int len, int bsize);
666extern journal_t * journal_init_inode (struct inode *);
667extern int journal_update_format (journal_t *);
668extern int journal_check_used_features
669 (journal_t *, unsigned long, unsigned long, unsigned long);
670extern int journal_check_available_features
671 (journal_t *, unsigned long, unsigned long, unsigned long);
672extern int journal_set_features
673 (journal_t *, unsigned long, unsigned long, unsigned long);
674extern int journal_create (journal_t *);
675extern int journal_load (journal_t *journal);
676extern void journal_destroy (journal_t *);
677extern int journal_recover (journal_t *journal);
678extern int journal_wipe (journal_t *, int);
679extern int journal_skip_recovery (journal_t *);
680extern void journal_update_superblock (journal_t *, int);
681extern void __journal_abort (journal_t *);
682extern void journal_abort (journal_t *, int);
683extern int journal_errno (journal_t *);
684extern void journal_ack_err (journal_t *);
685extern int journal_clear_err (journal_t *);
686extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr);
687extern int journal_force_commit(journal_t *journal);
688
689/*
690 * journal_head management
691 */
692extern struct journal_head
693 *journal_add_journal_head(struct buffer_head *bh);
694extern void journal_remove_journal_head(struct buffer_head *bh);
695extern void __journal_remove_journal_head(struct buffer_head *bh);
696extern void journal_unlock_journal_head(struct journal_head *jh);
697
698/* Primary revoke support */
699#define JOURNAL_REVOKE_DEFAULT_HASH 256
700extern int journal_init_revoke(journal_t *, int);
701extern void journal_destroy_revoke_caches(void);
702extern int journal_init_revoke_caches(void);
703
704extern void journal_destroy_revoke(journal_t *);
705extern int journal_revoke (handle_t *,
706 unsigned long, struct buffer_head *);
707extern int journal_cancel_revoke(handle_t *, struct journal_head *);
708extern void journal_write_revoke_records(journal_t *, transaction_t *);
709
710/* Recovery revoke support */
711extern int journal_set_revoke(journal_t *, unsigned long, tid_t);
712extern int journal_test_revoke(journal_t *, unsigned long, tid_t);
713extern void journal_clear_revoke(journal_t *);
714extern void journal_brelse_array(struct buffer_head *b[], int n);
715
716/* The log thread user interface:
717 *
718 * Request space in the current transaction, and force transaction commit
719 * transitions on demand.
720 */
721
722extern int log_space_left (journal_t *); /* Called with journal locked */
723extern tid_t log_start_commit (journal_t *, transaction_t *);
724extern void log_wait_commit (journal_t *, tid_t);
725extern int log_do_checkpoint (journal_t *, int);
726
727extern void log_wait_for_space(journal_t *, int nblocks);
728extern void __journal_drop_transaction(journal_t *, transaction_t *);
729extern int cleanup_journal_tail(journal_t *);
730
731/* Reduce journal memory usage by flushing */
732extern void shrink_journal_memory(void);
733
734/* Debugging code only: */
735
736#define jbd_ENOSYS() \
737do { \
738 printk (KERN_ERR "JBD unimplemented function " __FUNCTION__); \
739 current->state = TASK_UNINTERRUPTIBLE; \
740 schedule(); \
741} while (1)
742
743/*
744 * is_journal_abort
745 *
746 * Simple test wrapper function to test the JFS_ABORT state flag. This
747 * bit, when set, indicates that we have had a fatal error somewhere,
748 * either inside the journaling layer or indicated to us by the client
749 * (eg. ext3), and that we and should not commit any further
750 * transactions.
751 */
752
753static inline int is_journal_aborted(journal_t *journal)
754{
755 return journal->j_flags & JFS_ABORT;
756}
757
758static inline int is_handle_aborted(handle_t *handle)
759{
760 if (handle->h_aborted)
761 return 1;
762 return is_journal_aborted(handle->h_transaction->t_journal);
763}
764
765static inline void journal_abort_handle(handle_t *handle)
766{
767 handle->h_aborted = 1;
768}
769
770/* Not all architectures define BUG() */
771#ifndef BUG
772#define BUG() do { \
773 printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
774 * ((char *) 0) = 0; \
775 } while (0)
776#endif /* BUG */
777
778#else
779
780extern int journal_recover (journal_t *journal);
781extern int journal_skip_recovery (journal_t *);
782
783/* Primary revoke support */
784extern int journal_init_revoke(journal_t *, int);
785extern void journal_destroy_revoke_caches(void);
786extern int journal_init_revoke_caches(void);
787
788/* Recovery revoke support */
789extern int journal_set_revoke(journal_t *, unsigned long, tid_t);
790extern int journal_test_revoke(journal_t *, unsigned long, tid_t);
791extern void journal_clear_revoke(journal_t *);
792extern void journal_brelse_array(struct buffer_head *b[], int n);
793
794extern void journal_destroy_revoke(journal_t *);
795#endif /* __KERNEL__ */
796
797/* Comparison functions for transaction IDs: perform comparisons using
798 * modulo arithmetic so that they work over sequence number wraps. */
799
800static inline int tid_gt(tid_t x, tid_t y)
801{
802 int difference = (x - y);
803 return (difference > 0);
804}
805
806static inline int tid_geq(tid_t x, tid_t y)
807{
808 int difference = (x - y);
809 return (difference >= 0);
810}
811
812extern int journal_blocks_per_page(struct inode *inode);
813
814/*
815 * Definitions which augment the buffer_head layer
816 */
817
818/* journaling buffer types */
819#define BJ_None 0 /* Not journaled */
820#define BJ_SyncData 1 /* Normal data: flush before commit */
821#define BJ_AsyncData 2 /* writepage data: wait on it before commit */
822#define BJ_Metadata 3 /* Normal journaled metadata */
823#define BJ_Forget 4 /* Buffer superceded by this transaction */
824#define BJ_IO 5 /* Buffer is for temporary IO use */
825#define BJ_Shadow 6 /* Buffer contents being shadowed to the log */
826#define BJ_LogCtl 7 /* Buffer contains log descriptors */
827#define BJ_Reserved 8 /* Buffer is reserved for access by journal */
828#define BJ_Types 9
829
830extern int jbd_blocks_per_page(struct inode *inode);
831
832#ifdef __KERNEL__
833
834extern spinlock_t jh_splice_lock;
835/*
836 * Once `expr1' has been found true, take jh_splice_lock
837 * and then reevaluate everything.
838 */
839#define SPLICE_LOCK(expr1, expr2) \
840 ({ \
841 int ret = (expr1); \
842 if (ret) { \
843 spin_lock(&jh_splice_lock); \
844 ret = (expr1) && (expr2); \
845 spin_unlock(&jh_splice_lock); \
846 } \
847 ret; \
848 })
849
850/*
851 * A number of buffer state predicates. They test for
852 * buffer_jbd() because they are used in core kernel code.
853 *
854 * These will be racy on SMP unless we're *sure* that the
855 * buffer won't be detached from the journalling system
856 * in parallel.
857 */
858
859/* Return true if the buffer is on journal list `list' */
860static inline int buffer_jlist_eq(struct buffer_head *bh, int list)
861{
862 return SPLICE_LOCK(buffer_jbd(bh), bh2jh(bh)->b_jlist == list);
863}
864
865/* Return true if this bufer is dirty wrt the journal */
866static inline int buffer_jdirty(struct buffer_head *bh)
867{
868 return buffer_jbd(bh) && __buffer_state(bh, JBDDirty);
869}
870
871/* Return true if it's a data buffer which journalling is managing */
872static inline int buffer_jbd_data(struct buffer_head *bh)
873{
874 return SPLICE_LOCK(buffer_jbd(bh),
875 bh2jh(bh)->b_jlist == BJ_SyncData ||
876 bh2jh(bh)->b_jlist == BJ_AsyncData);
877}
878
879#ifdef CONFIG_SMP
880#define assert_spin_locked(lock) J_ASSERT(spin_is_locked(lock))
881#else
882#define assert_spin_locked(lock) do {} while(0)
883#endif
884
885#define buffer_trace_init(bh) do {} while (0)
886#define print_buffer_fields(bh) do {} while (0)
887#define print_buffer_trace(bh) do {} while (0)
888#define BUFFER_TRACE(bh, info) do {} while (0)
889#define BUFFER_TRACE2(bh, bh2, info) do {} while (0)
890#define JBUFFER_TRACE(jh, info) do {} while (0)
891
892#endif /* __KERNEL__ */
893
894#endif /* CONFIG_JBD || CONFIG_JBD_MODULE || !__KERNEL__ */
895
896/*
897 * Compatibility no-ops which allow the kernel to compile without CONFIG_JBD
898 * go here.
899 */
900
901#if defined(__KERNEL__) && !(defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE))
902
903#define J_ASSERT(expr) do {} while (0)
904#define J_ASSERT_BH(bh, expr) do {} while (0)
905#define buffer_jbd(bh) 0
906#define buffer_jlist_eq(bh, val) 0
907#define journal_buffer_journal_lru(bh) 0
908
909#endif /* defined(__KERNEL__) && !defined(CONFIG_JBD) */
910#endif /* _LINUX_JBD_H */
diff --git a/e2fsprogs/ext2fs/kernel-list.h b/e2fsprogs/ext2fs/kernel-list.h
new file mode 100644
index 000000000..24e6ab4a1
--- /dev/null
+++ b/e2fsprogs/ext2fs/kernel-list.h
@@ -0,0 +1,112 @@
1#ifndef _LINUX_LIST_H
2#define _LINUX_LIST_H
3
4/*
5 * Simple doubly linked list implementation.
6 *
7 * Some of the internal functions ("__xxx") are useful when
8 * manipulating whole lists rather than single entries, as
9 * sometimes we already know the next/prev entries and we can
10 * generate better code by using them directly rather than
11 * using the generic single-entry routines.
12 */
13
14struct list_head {
15 struct list_head *next, *prev;
16};
17
18#define LIST_HEAD_INIT(name) { &(name), &(name) }
19
20#define LIST_HEAD(name) \
21 struct list_head name = { &name, &name }
22
23#define INIT_LIST_HEAD(ptr) do { \
24 (ptr)->next = (ptr); (ptr)->prev = (ptr); \
25} while (0)
26
27#if (!defined(__GNUC__) && !defined(__WATCOMC__))
28#define __inline__
29#endif
30
31/*
32 * Insert a new entry between two known consecutive entries.
33 *
34 * This is only for internal list manipulation where we know
35 * the prev/next entries already!
36 */
37static __inline__ void __list_add(struct list_head * new,
38 struct list_head * prev,
39 struct list_head * next)
40{
41 next->prev = new;
42 new->next = next;
43 new->prev = prev;
44 prev->next = new;
45}
46
47/*
48 * Insert a new entry after the specified head..
49 */
50static __inline__ void list_add(struct list_head *new, struct list_head *head)
51{
52 __list_add(new, head, head->next);
53}
54
55/*
56 * Insert a new entry at the tail
57 */
58static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
59{
60 __list_add(new, head->prev, head);
61}
62
63/*
64 * Delete a list entry by making the prev/next entries
65 * point to each other.
66 *
67 * This is only for internal list manipulation where we know
68 * the prev/next entries already!
69 */
70static __inline__ void __list_del(struct list_head * prev,
71 struct list_head * next)
72{
73 next->prev = prev;
74 prev->next = next;
75}
76
77static __inline__ void list_del(struct list_head *entry)
78{
79 __list_del(entry->prev, entry->next);
80}
81
82static __inline__ int list_empty(struct list_head *head)
83{
84 return head->next == head;
85}
86
87/*
88 * Splice in "list" into "head"
89 */
90static __inline__ void list_splice(struct list_head *list, struct list_head *head)
91{
92 struct list_head *first = list->next;
93
94 if (first != list) {
95 struct list_head *last = list->prev;
96 struct list_head *at = head->next;
97
98 first->prev = head;
99 head->next = first;
100
101 last->next = at;
102 at->prev = last;
103 }
104}
105
106#define list_entry(ptr, type, member) \
107 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
108
109#define list_for_each(pos, head) \
110 for (pos = (head)->next; pos != (head); pos = pos->next)
111
112#endif
diff --git a/e2fsprogs/ext2fs/link.c b/e2fsprogs/ext2fs/link.c
new file mode 100644
index 000000000..5e0f4f3c0
--- /dev/null
+++ b/e2fsprogs/ext2fs/link.c
@@ -0,0 +1,134 @@
1/*
2 * link.c --- create links in a ext2fs directory
3 *
4 * Copyright (C) 1993, 1994 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21struct link_struct {
22 const char *name;
23 int namelen;
24 ext2_ino_t inode;
25 int flags;
26 int done;
27 struct ext2_super_block *sb;
28};
29
30static int link_proc(struct ext2_dir_entry *dirent,
31 int offset,
32 int blocksize,
33 char *buf,
34 void *priv_data)
35{
36 struct link_struct *ls = (struct link_struct *) priv_data;
37 struct ext2_dir_entry *next;
38 int rec_len, min_rec_len;
39 int ret = 0;
40
41 rec_len = EXT2_DIR_REC_LEN(ls->namelen);
42
43 /*
44 * See if the following directory entry (if any) is unused;
45 * if so, absorb it into this one.
46 */
47 next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len);
48 if ((offset + dirent->rec_len < blocksize - 8) &&
49 (next->inode == 0) &&
50 (offset + dirent->rec_len + next->rec_len <= blocksize)) {
51 dirent->rec_len += next->rec_len;
52 ret = DIRENT_CHANGED;
53 }
54
55 /*
56 * If the directory entry is used, see if we can split the
57 * directory entry to make room for the new name. If so,
58 * truncate it and return.
59 */
60 if (dirent->inode) {
61 min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
62 if (dirent->rec_len < (min_rec_len + rec_len))
63 return ret;
64 rec_len = dirent->rec_len - min_rec_len;
65 dirent->rec_len = min_rec_len;
66 next = (struct ext2_dir_entry *) (buf + offset +
67 dirent->rec_len);
68 next->inode = 0;
69 next->name_len = 0;
70 next->rec_len = rec_len;
71 return DIRENT_CHANGED;
72 }
73
74 /*
75 * If we get this far, then the directory entry is not used.
76 * See if we can fit the request entry in. If so, do it.
77 */
78 if (dirent->rec_len < rec_len)
79 return ret;
80 dirent->inode = ls->inode;
81 dirent->name_len = ls->namelen;
82 strncpy(dirent->name, ls->name, ls->namelen);
83 if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
84 dirent->name_len |= (ls->flags & 0x7) << 8;
85
86 ls->done++;
87 return DIRENT_ABORT|DIRENT_CHANGED;
88}
89
90/*
91 * Note: the low 3 bits of the flags field are used as the directory
92 * entry filetype.
93 */
94#ifdef __TURBOC__
95 #pragma argsused
96#endif
97errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
98 ext2_ino_t ino, int flags)
99{
100 errcode_t retval;
101 struct link_struct ls;
102 struct ext2_inode inode;
103
104 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
105
106 if (!(fs->flags & EXT2_FLAG_RW))
107 return EXT2_ET_RO_FILSYS;
108
109 ls.name = name;
110 ls.namelen = name ? strlen(name) : 0;
111 ls.inode = ino;
112 ls.flags = flags;
113 ls.done = 0;
114 ls.sb = fs->super;
115
116 retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
117 0, link_proc, &ls);
118 if (retval)
119 return retval;
120
121 if (!ls.done)
122 return EXT2_ET_DIR_NO_SPACE;
123
124 if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
125 return retval;
126
127 if (inode.i_flags & EXT2_INDEX_FL) {
128 inode.i_flags &= ~EXT2_INDEX_FL;
129 if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)
130 return retval;
131 }
132
133 return 0;
134}
diff --git a/e2fsprogs/ext2fs/llseek.c b/e2fsprogs/ext2fs/llseek.c
new file mode 100644
index 000000000..e0bedb57d
--- /dev/null
+++ b/e2fsprogs/ext2fs/llseek.c
@@ -0,0 +1,135 @@
1/*
2 * llseek.c -- stub calling the llseek system call
3 *
4 * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#if HAVE_SYS_TYPES_H
13#include <sys/types.h>
14#endif
15
16#if HAVE_ERRNO_H
17#include <errno.h>
18#endif
19#if HAVE_UNISTD_H
20#include <unistd.h>
21#endif
22#ifdef __MSDOS__
23#include <io.h>
24#endif
25#include "et/com_err.h"
26#include "ext2fs/ext2_io.h"
27
28#ifdef __linux__
29
30#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
31
32#define my_llseek lseek64
33
34#else
35#if defined(HAVE_LLSEEK)
36#include <syscall.h>
37
38#ifndef HAVE_LLSEEK_PROTOTYPE
39extern long long llseek (int fd, long long offset, int origin);
40#endif
41
42#define my_llseek llseek
43
44#else /* ! HAVE_LLSEEK */
45
46#if defined(__alpha__) || defined (__ia64__)
47
48#define llseek lseek
49
50#else /* !__alpha__ && !__ia64__*/
51
52#include <linux/unistd.h>
53
54#ifndef __NR__llseek
55#define __NR__llseek 140
56#endif
57
58#ifndef __i386__
59static int _llseek (unsigned int, unsigned long,
60 unsigned long, ext2_loff_t *, unsigned int);
61
62static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high,
63 unsigned long, offset_low,ext2_loff_t *,result,
64 unsigned int, origin)
65#endif
66
67static ext2_loff_t my_llseek (int fd, ext2_loff_t offset, int origin)
68{
69 ext2_loff_t result;
70 int retval;
71
72#ifndef __i386__
73 retval = _llseek(fd, ((unsigned long long) offset) >> 32,
74#else
75 retval = syscall(__NR__llseek, fd, (unsigned long long) (offset >> 32),
76#endif
77 ((unsigned long long) offset) & 0xffffffff,
78 &result, origin);
79 return (retval == -1 ? (ext2_loff_t) retval : result);
80}
81
82#endif /* __alpha__ || __ia64__ */
83
84#endif /* HAVE_LLSEEK */
85#endif /* defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) */
86
87ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
88{
89 ext2_loff_t result;
90 static int do_compat = 0;
91
92 if ((sizeof(off_t) >= sizeof(ext2_loff_t)) ||
93 (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1))))
94 return lseek(fd, (off_t) offset, origin);
95
96 if (do_compat) {
97 errno = EINVAL;
98 return -1;
99 }
100
101 result = my_llseek (fd, offset, origin);
102 if (result == -1 && errno == ENOSYS) {
103 /*
104 * Just in case this code runs on top of an old kernel
105 * which does not support the llseek system call
106 */
107 do_compat++;
108 errno = EINVAL;
109 }
110 return result;
111}
112
113#else /* !linux */
114
115#ifndef EINVAL
116#define EINVAL EXT2_ET_INVALID_ARGUMENT
117#endif
118
119ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
120{
121#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
122 return lseek64 (fd, offset, origin);
123#else
124 if ((sizeof(off_t) < sizeof(ext2_loff_t)) &&
125 (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) {
126 errno = EINVAL;
127 return -1;
128 }
129 return lseek (fd, (off_t) offset, origin);
130#endif
131}
132
133#endif /* linux */
134
135
diff --git a/e2fsprogs/ext2fs/lookup.c b/e2fsprogs/ext2fs/lookup.c
new file mode 100644
index 000000000..1745f33ab
--- /dev/null
+++ b/e2fsprogs/ext2fs/lookup.c
@@ -0,0 +1,69 @@
1/*
2 * lookup.c --- ext2fs directory lookup operations
3 *
4 * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21struct lookup_struct {
22 const char *name;
23 int len;
24 ext2_ino_t *inode;
25 int found;
26};
27
28#ifdef __TURBOC__
29 #pragma argsused
30#endif
31static int lookup_proc(struct ext2_dir_entry *dirent,
32 int offset EXT2FS_ATTR((unused)),
33 int blocksize EXT2FS_ATTR((unused)),
34 char *buf EXT2FS_ATTR((unused)),
35 void *priv_data)
36{
37 struct lookup_struct *ls = (struct lookup_struct *) priv_data;
38
39 if (ls->len != (dirent->name_len & 0xFF))
40 return 0;
41 if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF)))
42 return 0;
43 *ls->inode = dirent->inode;
44 ls->found++;
45 return DIRENT_ABORT;
46}
47
48
49errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
50 int namelen, char *buf, ext2_ino_t *inode)
51{
52 errcode_t retval;
53 struct lookup_struct ls;
54
55 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
56
57 ls.name = name;
58 ls.len = namelen;
59 ls.inode = inode;
60 ls.found = 0;
61
62 retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls);
63 if (retval)
64 return retval;
65
66 return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND;
67}
68
69
diff --git a/e2fsprogs/ext2fs/mkdir.c b/e2fsprogs/ext2fs/mkdir.c
new file mode 100644
index 000000000..81e7aea58
--- /dev/null
+++ b/e2fsprogs/ext2fs/mkdir.c
@@ -0,0 +1,142 @@
1/*
2 * mkdir.c --- make a directory in the filesystem
3 *
4 * Copyright (C) 1994, 1995 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28
29#ifndef EXT2_FT_DIR
30#define EXT2_FT_DIR 2
31#endif
32
33errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
34 const char *name)
35{
36 errcode_t retval;
37 struct ext2_inode parent_inode, inode;
38 ext2_ino_t ino = inum;
39 ext2_ino_t scratch_ino;
40 blk_t blk;
41 char *block = 0;
42
43 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
44
45 /*
46 * Allocate an inode, if necessary
47 */
48 if (!ino) {
49 retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755,
50 0, &ino);
51 if (retval)
52 goto cleanup;
53 }
54
55 /*
56 * Allocate a data block for the directory
57 */
58 retval = ext2fs_new_block(fs, 0, 0, &blk);
59 if (retval)
60 goto cleanup;
61
62 /*
63 * Create a scratch template for the directory
64 */
65 retval = ext2fs_new_dir_block(fs, ino, parent, &block);
66 if (retval)
67 goto cleanup;
68
69 /*
70 * Get the parent's inode, if necessary
71 */
72 if (parent != ino) {
73 retval = ext2fs_read_inode(fs, parent, &parent_inode);
74 if (retval)
75 goto cleanup;
76 } else
77 memset(&parent_inode, 0, sizeof(parent_inode));
78
79 /*
80 * Create the inode structure....
81 */
82 memset(&inode, 0, sizeof(struct ext2_inode));
83 inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
84 inode.i_uid = inode.i_gid = 0;
85 inode.i_blocks = fs->blocksize / 512;
86 inode.i_block[0] = blk;
87 inode.i_links_count = 2;
88 inode.i_ctime = inode.i_atime = inode.i_mtime = time(NULL);
89 inode.i_size = fs->blocksize;
90
91 /*
92 * Write out the inode and inode data block
93 */
94 retval = ext2fs_write_dir_block(fs, blk, block);
95 if (retval)
96 goto cleanup;
97 retval = ext2fs_write_new_inode(fs, ino, &inode);
98 if (retval)
99 goto cleanup;
100
101 /*
102 * Link the directory into the filesystem hierarchy
103 */
104 if (name) {
105 retval = ext2fs_lookup(fs, parent, name, strlen(name), 0,
106 &scratch_ino);
107 if (!retval) {
108 retval = EXT2_ET_DIR_EXISTS;
109 name = 0;
110 goto cleanup;
111 }
112 if (retval != EXT2_ET_FILE_NOT_FOUND)
113 goto cleanup;
114 retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR);
115 if (retval)
116 goto cleanup;
117 }
118
119 /*
120 * Update parent inode's counts
121 */
122 if (parent != ino) {
123 parent_inode.i_links_count++;
124 retval = ext2fs_write_inode(fs, parent, &parent_inode);
125 if (retval)
126 goto cleanup;
127 }
128
129 /*
130 * Update accounting....
131 */
132 ext2fs_block_alloc_stats(fs, blk, +1);
133 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
134
135cleanup:
136 if (block)
137 ext2fs_free_mem(&block);
138 return retval;
139
140}
141
142
diff --git a/e2fsprogs/ext2fs/mkjournal.c b/e2fsprogs/ext2fs/mkjournal.c
new file mode 100644
index 000000000..427a08e72
--- /dev/null
+++ b/e2fsprogs/ext2fs/mkjournal.c
@@ -0,0 +1,425 @@
1/*
2 * mkjournal.c --- make a journal for a filesystem
3 *
4 * Copyright (C) 2000 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.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#include <time.h>
22#if HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#if HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#if HAVE_SYS_IOCTL_H
29#include <sys/ioctl.h>
30#endif
31#if HAVE_NETINET_IN_H
32#include <netinet/in.h>
33#endif
34
35#include "ext2_fs.h"
36#include "e2p/e2p.h"
37#include "ext2fs.h"
38#include "jfs_user.h"
39
40/*
41 * This function automatically sets up the journal superblock and
42 * returns it as an allocated block.
43 */
44errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
45 __u32 size, int flags,
46 char **ret_jsb)
47{
48 errcode_t retval;
49 journal_superblock_t *jsb;
50
51 if (size < 1024)
52 return EXT2_ET_JOURNAL_TOO_SMALL;
53
54 if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
55 return retval;
56
57 memset (jsb, 0, fs->blocksize);
58
59 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
60 if (flags & EXT2_MKJOURNAL_V1_SUPER)
61 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
62 else
63 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
64 jsb->s_blocksize = htonl(fs->blocksize);
65 jsb->s_maxlen = htonl(size);
66 jsb->s_nr_users = htonl(1);
67 jsb->s_first = htonl(1);
68 jsb->s_sequence = htonl(1);
69 memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
70 /*
71 * If we're creating an external journal device, we need to
72 * adjust these fields.
73 */
74 if (fs->super->s_feature_incompat &
75 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
76 jsb->s_nr_users = 0;
77 if (fs->blocksize == 1024)
78 jsb->s_first = htonl(3);
79 else
80 jsb->s_first = htonl(2);
81 }
82
83 *ret_jsb = (char *) jsb;
84 return 0;
85}
86
87/*
88 * This function writes a journal using POSIX routines. It is used
89 * for creating external journals and creating journals on live
90 * filesystems.
91 */
92static errcode_t write_journal_file(ext2_filsys fs, char *filename,
93 blk_t size, int flags)
94{
95 errcode_t retval;
96 char *buf = 0;
97 int fd, ret_size;
98 blk_t i;
99
100 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
101 return retval;
102
103 /* Open the device or journal file */
104 if ((fd = open(filename, O_WRONLY)) < 0) {
105 retval = errno;
106 goto errout;
107 }
108
109 /* Write the superblock out */
110 retval = EXT2_ET_SHORT_WRITE;
111 ret_size = write(fd, buf, fs->blocksize);
112 if (ret_size < 0) {
113 retval = errno;
114 goto errout;
115 }
116 if (ret_size != (int) fs->blocksize)
117 goto errout;
118 memset(buf, 0, fs->blocksize);
119
120 for (i = 1; i < size; i++) {
121 ret_size = write(fd, buf, fs->blocksize);
122 if (ret_size < 0) {
123 retval = errno;
124 goto errout;
125 }
126 if (ret_size != (int) fs->blocksize)
127 goto errout;
128 }
129 close(fd);
130
131 retval = 0;
132errout:
133 ext2fs_free_mem(&buf);
134 return retval;
135}
136
137/*
138 * Helper function for creating the journal using direct I/O routines
139 */
140struct mkjournal_struct {
141 int num_blocks;
142 int newblocks;
143 char *buf;
144 errcode_t err;
145};
146
147static int mkjournal_proc(ext2_filsys fs,
148 blk_t *blocknr,
149 e2_blkcnt_t blockcnt,
150 blk_t ref_block EXT2FS_ATTR((unused)),
151 int ref_offset EXT2FS_ATTR((unused)),
152 void *priv_data)
153{
154 struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
155 blk_t new_blk;
156 static blk_t last_blk = 0;
157 errcode_t retval;
158
159 if (*blocknr) {
160 last_blk = *blocknr;
161 return 0;
162 }
163 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
164 if (retval) {
165 es->err = retval;
166 return BLOCK_ABORT;
167 }
168 if (blockcnt > 0)
169 es->num_blocks--;
170
171 es->newblocks++;
172 retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
173
174 if (blockcnt == 0)
175 memset(es->buf, 0, fs->blocksize);
176
177 if (retval) {
178 es->err = retval;
179 return BLOCK_ABORT;
180 }
181 *blocknr = new_blk;
182 last_blk = new_blk;
183 ext2fs_block_alloc_stats(fs, new_blk, +1);
184
185 if (es->num_blocks == 0)
186 return (BLOCK_CHANGED | BLOCK_ABORT);
187 else
188 return BLOCK_CHANGED;
189
190}
191
192/*
193 * This function creates a journal using direct I/O routines.
194 */
195static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
196 blk_t size, int flags)
197{
198 char *buf;
199 errcode_t retval;
200 struct ext2_inode inode;
201 struct mkjournal_struct es;
202
203 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
204 return retval;
205
206 if ((retval = ext2fs_read_bitmaps(fs)))
207 return retval;
208
209 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
210 return retval;
211
212 if (inode.i_blocks > 0)
213 return EEXIST;
214
215 es.num_blocks = size;
216 es.newblocks = 0;
217 es.buf = buf;
218 es.err = 0;
219
220 retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
221 0, mkjournal_proc, &es);
222 if (es.err) {
223 retval = es.err;
224 goto errout;
225 }
226
227 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
228 goto errout;
229
230 inode.i_size += fs->blocksize * size;
231 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
232 inode.i_mtime = inode.i_ctime = time(0);
233 inode.i_links_count = 1;
234 inode.i_mode = LINUX_S_IFREG | 0600;
235
236 if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
237 goto errout;
238 retval = 0;
239
240 memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
241 fs->super->s_jnl_blocks[16] = inode.i_size;
242 fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
243 ext2fs_mark_super_dirty(fs);
244
245errout:
246 ext2fs_free_mem(&buf);
247 return retval;
248}
249
250/*
251 * This function adds a journal device to a filesystem
252 */
253errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
254{
255 struct stat st;
256 errcode_t retval;
257 char buf[1024];
258 journal_superblock_t *jsb;
259 int start;
260 __u32 i, nr_users;
261
262 /* Make sure the device exists and is a block device */
263 if (stat(journal_dev->device_name, &st) < 0)
264 return errno;
265
266 if (!S_ISBLK(st.st_mode))
267 return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
268
269 /* Get the journal superblock */
270 start = 1;
271 if (journal_dev->blocksize == 1024)
272 start++;
273 if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
274 return retval;
275
276 jsb = (journal_superblock_t *) buf;
277 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
278 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
279 return EXT2_ET_NO_JOURNAL_SB;
280
281 if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
282 return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
283
284 /* Check and see if this filesystem has already been added */
285 nr_users = ntohl(jsb->s_nr_users);
286 for (i=0; i < nr_users; i++) {
287 if (memcmp(fs->super->s_uuid,
288 &jsb->s_users[i*16], 16) == 0)
289 break;
290 }
291 if (i >= nr_users) {
292 memcpy(&jsb->s_users[nr_users*16],
293 fs->super->s_uuid, 16);
294 jsb->s_nr_users = htonl(nr_users+1);
295 }
296
297 /* Writeback the journal superblock */
298 if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
299 return retval;
300
301 fs->super->s_journal_inum = 0;
302 fs->super->s_journal_dev = st.st_rdev;
303 memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
304 sizeof(fs->super->s_journal_uuid));
305 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
306 ext2fs_mark_super_dirty(fs);
307 return 0;
308}
309
310/*
311 * This function adds a journal inode to a filesystem, using either
312 * POSIX routines if the filesystem is mounted, or using direct I/O
313 * functions if it is not.
314 */
315errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
316{
317 errcode_t retval;
318 ext2_ino_t journal_ino;
319 struct stat st;
320 char jfile[1024];
321 int fd, mount_flags, f;
322
323 if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
324 jfile, sizeof(jfile)-10)))
325 return retval;
326
327 if (mount_flags & EXT2_MF_MOUNTED) {
328 strcat(jfile, "/.journal");
329
330 /*
331 * If .../.journal already exists, make sure any
332 * immutable or append-only flags are cleared.
333 */
334#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
335 (void) chflags (jfile, 0);
336#else
337#if HAVE_EXT2_IOCTLS
338 fd = open(jfile, O_RDONLY);
339 if (fd >= 0) {
340 f = 0;
341 ioctl(fd, EXT2_IOC_SETFLAGS, &f);
342 close(fd);
343 }
344#endif
345#endif
346
347 /* Create the journal file */
348 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
349 return errno;
350
351 if ((retval = write_journal_file(fs, jfile, size, flags)))
352 goto errout;
353
354 /* Get inode number of the journal file */
355 if (fstat(fd, &st) < 0)
356 goto errout;
357
358#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
359 retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
360#else
361#if HAVE_EXT2_IOCTLS
362 f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
363 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
364#endif
365#endif
366 if (retval)
367 goto errout;
368
369 close(fd);
370 journal_ino = st.st_ino;
371 } else {
372 journal_ino = EXT2_JOURNAL_INO;
373 if ((retval = write_journal_inode(fs, journal_ino,
374 size, flags)))
375 return retval;
376 }
377
378 fs->super->s_journal_inum = journal_ino;
379 fs->super->s_journal_dev = 0;
380 memset(fs->super->s_journal_uuid, 0,
381 sizeof(fs->super->s_journal_uuid));
382 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
383
384 ext2fs_mark_super_dirty(fs);
385 return 0;
386errout:
387 close(fd);
388 return retval;
389}
390
391#ifdef DEBUG
392main(int argc, char **argv)
393{
394 errcode_t retval;
395 char *device_name;
396 ext2_filsys fs;
397
398 if (argc < 2) {
399 fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
400 exit(1);
401 }
402 device_name = argv[1];
403
404 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
405 unix_io_manager, &fs);
406 if (retval) {
407 com_err(argv[0], retval, "while opening %s", device_name);
408 exit(1);
409 }
410
411 retval = ext2fs_add_journal_inode(fs, 1024);
412 if (retval) {
413 com_err(argv[0], retval, "while adding journal to %s",
414 device_name);
415 exit(1);
416 }
417 retval = ext2fs_flush(fs);
418 if (retval) {
419 printf("Warning, had trouble writing out superblocks.\n");
420 }
421 ext2fs_close(fs);
422 exit(0);
423
424}
425#endif
diff --git a/e2fsprogs/ext2fs/namei.c b/e2fsprogs/ext2fs/namei.c
new file mode 100644
index 000000000..13d13adfe
--- /dev/null
+++ b/e2fsprogs/ext2fs/namei.c
@@ -0,0 +1,205 @@
1/*
2 * namei.c --- ext2fs directory lookup operations
3 *
4 * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18/* #define NAMEI_DEBUG */
19
20#include "ext2_fs.h"
21#include "ext2fs.h"
22
23static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
24 const char *pathname, size_t pathlen, int follow,
25 int link_count, char *buf, ext2_ino_t *res_inode);
26
27static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
28 ext2_ino_t inode, int link_count,
29 char *buf, ext2_ino_t *res_inode)
30{
31 char *pathname;
32 char *buffer = 0;
33 errcode_t retval;
34 struct ext2_inode ei;
35
36#ifdef NAMEI_DEBUG
37 printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
38 root, dir, inode, link_count);
39
40#endif
41 retval = ext2fs_read_inode (fs, inode, &ei);
42 if (retval) return retval;
43 if (!LINUX_S_ISLNK (ei.i_mode)) {
44 *res_inode = inode;
45 return 0;
46 }
47 if (link_count++ > 5) {
48 return EXT2_ET_SYMLINK_LOOP;
49 }
50 if (ext2fs_inode_data_blocks(fs,&ei)) {
51 retval = ext2fs_get_mem(fs->blocksize, &buffer);
52 if (retval)
53 return retval;
54 retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
55 if (retval) {
56 ext2fs_free_mem(&buffer);
57 return retval;
58 }
59 pathname = buffer;
60 } else
61 pathname = (char *)&(ei.i_block[0]);
62 retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
63 link_count, buf, res_inode);
64 if (buffer)
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/ext2fs/native.c b/e2fsprogs/ext2fs/native.c
new file mode 100644
index 000000000..85d098967
--- /dev/null
+++ b/e2fsprogs/ext2fs/native.c
@@ -0,0 +1,27 @@
1/*
2 * native.c --- returns the ext2_flag for a native byte order
3 *
4 * Copyright (C) 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13
14#include "ext2_fs.h"
15#include "ext2fs.h"
16
17int ext2fs_native_flag(void)
18{
19#ifdef WORDS_BIGENDIAN
20 return EXT2_FLAG_SWAP_BYTES;
21#else
22 return 0;
23#endif
24}
25
26
27
diff --git a/e2fsprogs/ext2fs/newdir.c b/e2fsprogs/ext2fs/newdir.c
new file mode 100644
index 000000000..3904d9112
--- /dev/null
+++ b/e2fsprogs/ext2fs/newdir.c
@@ -0,0 +1,72 @@
1/*
2 * newdir.c --- create a new directory block
3 *
4 * Copyright (C) 1994, 1995 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21#ifndef EXT2_FT_DIR
22#define EXT2_FT_DIR 2
23#endif
24
25/*
26 * Create new directory block
27 */
28errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
29 ext2_ino_t parent_ino, char **block)
30{
31 struct ext2_dir_entry *dir = NULL;
32 errcode_t retval;
33 char *buf;
34 int rec_len;
35 int filetype = 0;
36
37 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
38
39 retval = ext2fs_get_mem(fs->blocksize, &buf);
40 if (retval)
41 return retval;
42 memset(buf, 0, fs->blocksize);
43 dir = (struct ext2_dir_entry *) buf;
44 dir->rec_len = fs->blocksize;
45
46 if (dir_ino) {
47 if (fs->super->s_feature_incompat &
48 EXT2_FEATURE_INCOMPAT_FILETYPE)
49 filetype = EXT2_FT_DIR << 8;
50 /*
51 * Set up entry for '.'
52 */
53 dir->inode = dir_ino;
54 dir->name_len = 1 | filetype;
55 dir->name[0] = '.';
56 rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);
57 dir->rec_len = EXT2_DIR_REC_LEN(1);
58
59 /*
60 * Set up entry for '..'
61 */
62 dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
63 dir->rec_len = rec_len;
64 dir->inode = parent_ino;
65 dir->name_len = 2 | filetype;
66 dir->name[0] = '.';
67 dir->name[1] = '.';
68
69 }
70 *block = buf;
71 return 0;
72}
diff --git a/e2fsprogs/ext2fs/openfs.c b/e2fsprogs/ext2fs/openfs.c
new file mode 100644
index 000000000..d27c1b913
--- /dev/null
+++ b/e2fsprogs/ext2fs/openfs.c
@@ -0,0 +1,326 @@
1/*
2 * openfs.c --- open an ext2 filesystem
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27
28
29#include "ext2fs.h"
30#include "e2image.h"
31
32blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
33{
34 int bg;
35 int has_super = 0;
36 int ret_blk;
37
38 if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
39 (i < fs->super->s_first_meta_bg))
40 return (group_block + i + 1);
41
42 bg = (fs->blocksize / sizeof (struct ext2_group_desc)) * i;
43 if (ext2fs_bg_has_super(fs, bg))
44 has_super = 1;
45 ret_blk = (fs->super->s_first_data_block + has_super +
46 (bg * fs->super->s_blocks_per_group));
47 /*
48 * If group_block is not the normal value, we're trying to use
49 * the backup group descriptors and superblock --- so use the
50 * alternate location of the second block group in the
51 * metablock group. Ideally we should be testing each bg
52 * descriptor block individually for correctness, but we don't
53 * have the infrastructure in place to do that.
54 */
55 if (group_block != fs->super->s_first_data_block &&
56 ((ret_blk + fs->super->s_blocks_per_group) <
57 fs->super->s_blocks_count))
58 ret_blk += fs->super->s_blocks_per_group;
59 return ret_blk;
60}
61
62errcode_t ext2fs_open(const char *name, int flags, int superblock,
63 unsigned int block_size, io_manager manager,
64 ext2_filsys *ret_fs)
65{
66 return ext2fs_open2(name, 0, flags, superblock, block_size,
67 manager, ret_fs);
68}
69
70/*
71 * Note: if superblock is non-zero, block-size must also be non-zero.
72 * Superblock and block_size can be zero to use the default size.
73 *
74 * Valid flags for ext2fs_open()
75 *
76 * EXT2_FLAG_RW - Open the filesystem for read/write.
77 * EXT2_FLAG_FORCE - Open the filesystem even if some of the
78 * features aren't supported.
79 * EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
80 */
81errcode_t ext2fs_open2(const char *name, const char *io_options,
82 int flags, int superblock,
83 unsigned int block_size, io_manager manager,
84 ext2_filsys *ret_fs)
85{
86 ext2_filsys fs;
87 errcode_t retval;
88 unsigned long i;
89 int j, groups_per_block, blocks_per_group;
90 blk_t group_block, blk;
91 char *dest, *cp;
92 struct ext2_group_desc *gdp;
93
94 EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
95
96 retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
97 if (retval)
98 return retval;
99
100 memset(fs, 0, sizeof(struct struct_ext2_filsys));
101 fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
102 fs->flags = flags;
103 fs->umask = 022;
104 retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
105 if (retval)
106 goto cleanup;
107 strcpy(fs->device_name, name);
108 cp = strchr(fs->device_name, '?');
109 if (!io_options && cp) {
110 *cp++ = 0;
111 io_options = cp;
112 }
113
114 retval = manager->open(fs->device_name,
115 (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
116 &fs->io);
117 if (retval)
118 goto cleanup;
119 if (io_options &&
120 (retval = io_channel_set_options(fs->io, io_options)))
121 goto cleanup;
122 fs->image_io = fs->io;
123 fs->io->app_data = fs;
124 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
125 if (retval)
126 goto cleanup;
127 if (flags & EXT2_FLAG_IMAGE_FILE) {
128 retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
129 &fs->image_header);
130 if (retval)
131 goto cleanup;
132 retval = io_channel_read_blk(fs->io, 0,
133 -(int)sizeof(struct ext2_image_hdr),
134 fs->image_header);
135 if (retval)
136 goto cleanup;
137 if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE)
138 return EXT2_ET_MAGIC_E2IMAGE;
139 superblock = 1;
140 block_size = fs->image_header->fs_blocksize;
141 }
142
143 /*
144 * If the user specifies a specific block # for the
145 * superblock, then he/she must also specify the block size!
146 * Otherwise, read the master superblock located at offset
147 * SUPERBLOCK_OFFSET from the start of the partition.
148 *
149 * Note: we only save a backup copy of the superblock if we
150 * are reading the superblock from the primary superblock location.
151 */
152 if (superblock) {
153 if (!block_size) {
154 retval = EXT2_ET_INVALID_ARGUMENT;
155 goto cleanup;
156 }
157 io_channel_set_blksize(fs->io, block_size);
158 group_block = superblock;
159 fs->orig_super = 0;
160 } else {
161 io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
162 superblock = 1;
163 group_block = 0;
164 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
165 if (retval)
166 goto cleanup;
167 }
168 retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
169 fs->super);
170 if (retval)
171 goto cleanup;
172 if (fs->orig_super)
173 memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
174
175#ifdef EXT2FS_ENABLE_SWAPFS
176 if ((fs->super->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ||
177 (fs->flags & EXT2_FLAG_SWAP_BYTES)) {
178 fs->flags |= EXT2_FLAG_SWAP_BYTES;
179
180 ext2fs_swap_super(fs->super);
181 }
182#endif
183
184 if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
185 retval = EXT2_ET_BAD_MAGIC;
186 goto cleanup;
187 }
188 if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
189 retval = EXT2_ET_REV_TOO_HIGH;
190 goto cleanup;
191 }
192
193 /*
194 * Check for feature set incompatibility
195 */
196 if (!(flags & EXT2_FLAG_FORCE)) {
197 if (fs->super->s_feature_incompat &
198 ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
199 retval = EXT2_ET_UNSUPP_FEATURE;
200 goto cleanup;
201 }
202 if ((flags & EXT2_FLAG_RW) &&
203 (fs->super->s_feature_ro_compat &
204 ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
205 retval = EXT2_ET_RO_UNSUPP_FEATURE;
206 goto cleanup;
207 }
208 if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
209 (fs->super->s_feature_incompat &
210 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
211 retval = EXT2_ET_UNSUPP_FEATURE;
212 goto cleanup;
213 }
214 }
215
216 fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
217 if (fs->blocksize == 0) {
218 retval = EXT2_ET_CORRUPT_SUPERBLOCK;
219 goto cleanup;
220 }
221 fs->fragsize = EXT2_FRAG_SIZE(fs->super);
222 fs->inode_blocks_per_group = ((fs->super->s_inodes_per_group *
223 EXT2_INODE_SIZE(fs->super) +
224 EXT2_BLOCK_SIZE(fs->super) - 1) /
225 EXT2_BLOCK_SIZE(fs->super));
226 if (block_size) {
227 if (block_size != fs->blocksize) {
228 retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
229 goto cleanup;
230 }
231 }
232 /*
233 * Set the blocksize to the filesystem's blocksize.
234 */
235 io_channel_set_blksize(fs->io, fs->blocksize);
236
237 /*
238 * If this is an external journal device, don't try to read
239 * the group descriptors, because they're not there.
240 */
241 if (fs->super->s_feature_incompat &
242 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
243 fs->group_desc_count = 0;
244 *ret_fs = fs;
245 return 0;
246 }
247
248 /*
249 * Read group descriptors
250 */
251 blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
252 if (blocks_per_group == 0 ||
253 blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
254 fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super)) {
255 retval = EXT2_ET_CORRUPT_SUPERBLOCK;
256 goto cleanup;
257 }
258 fs->group_desc_count = (fs->super->s_blocks_count -
259 fs->super->s_first_data_block +
260 blocks_per_group - 1) / blocks_per_group;
261 fs->desc_blocks = (fs->group_desc_count +
262 EXT2_DESC_PER_BLOCK(fs->super) - 1)
263 / EXT2_DESC_PER_BLOCK(fs->super);
264 retval = ext2fs_get_mem(fs->desc_blocks * fs->blocksize,
265 &fs->group_desc);
266 if (retval)
267 goto cleanup;
268 if (!group_block)
269 group_block = fs->super->s_first_data_block;
270 dest = (char *) fs->group_desc;
271 groups_per_block = fs->blocksize / sizeof(struct ext2_group_desc);
272 for (i=0 ; i < fs->desc_blocks; i++) {
273 blk = ext2fs_descriptor_block_loc(fs, group_block, i);
274 retval = io_channel_read_blk(fs->io, blk, 1, dest);
275 if (retval)
276 goto cleanup;
277#ifdef EXT2FS_ENABLE_SWAPFS
278 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
279 gdp = (struct ext2_group_desc *) dest;
280 for (j=0; j < groups_per_block; j++)
281 ext2fs_swap_group_desc(gdp++);
282 }
283#endif
284 dest += fs->blocksize;
285 }
286
287 *ret_fs = fs;
288 return 0;
289cleanup:
290 ext2fs_free(fs);
291 return retval;
292}
293
294/*
295 * Set/get the filesystem data I/O channel.
296 *
297 * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
298 */
299errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io)
300{
301 if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
302 return EXT2_ET_NOT_IMAGE_FILE;
303 if (old_io) {
304 *old_io = (fs->image_io == fs->io) ? 0 : fs->io;
305 }
306 return 0;
307}
308
309errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
310{
311 if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
312 return EXT2_ET_NOT_IMAGE_FILE;
313 fs->io = new_io ? new_io : fs->image_io;
314 return 0;
315}
316
317errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
318{
319 if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
320 return EXT2_ET_NOT_IMAGE_FILE;
321 fs->io = fs->image_io = new_io;
322 fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW |
323 EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
324 fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
325 return 0;
326}
diff --git a/e2fsprogs/ext2fs/read_bb.c b/e2fsprogs/ext2fs/read_bb.c
new file mode 100644
index 000000000..c717adcd2
--- /dev/null
+++ b/e2fsprogs/ext2fs/read_bb.c
@@ -0,0 +1,97 @@
1/*
2 * read_bb --- read the bad blocks inode
3 *
4 * Copyright (C) 1994 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28
29struct read_bb_record {
30 ext2_badblocks_list bb_list;
31 errcode_t err;
32};
33
34/*
35 * Helper function for ext2fs_read_bb_inode()
36 */
37#ifdef __TURBOC__
38 #pragma argsused
39#endif
40static int mark_bad_block(ext2_filsys fs, blk_t *block_nr,
41 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
42 blk_t ref_block EXT2FS_ATTR((unused)),
43 int ref_offset EXT2FS_ATTR((unused)),
44 void *priv_data)
45{
46 struct read_bb_record *rb = (struct read_bb_record *) priv_data;
47
48 if (blockcnt < 0)
49 return 0;
50
51 if ((*block_nr < fs->super->s_first_data_block) ||
52 (*block_nr >= fs->super->s_blocks_count))
53 return 0; /* Ignore illegal blocks */
54
55 rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr);
56 if (rb->err)
57 return BLOCK_ABORT;
58 return 0;
59}
60
61/*
62 * Reads the current bad blocks from the bad blocks inode.
63 */
64errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list)
65{
66 errcode_t retval;
67 struct read_bb_record rb;
68 struct ext2_inode inode;
69 blk_t numblocks;
70
71 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
72
73 if (!*bb_list) {
74 retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
75 if (retval)
76 return retval;
77 if (inode.i_blocks < 500)
78 numblocks = (inode.i_blocks /
79 (fs->blocksize / 512)) + 20;
80 else
81 numblocks = 500;
82 retval = ext2fs_badblocks_list_create(bb_list, numblocks);
83 if (retval)
84 return retval;
85 }
86
87 rb.bb_list = *bb_list;
88 rb.err = 0;
89 retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, 0, 0,
90 mark_bad_block, &rb);
91 if (retval)
92 return retval;
93
94 return rb.err;
95}
96
97
diff --git a/e2fsprogs/ext2fs/read_bb_file.c b/e2fsprogs/ext2fs/read_bb_file.c
new file mode 100644
index 000000000..40c34ee3c
--- /dev/null
+++ b/e2fsprogs/ext2fs/read_bb_file.c
@@ -0,0 +1,97 @@
1/*
2 * read_bb_file.c --- read a list of bad blocks from a FILE *
3 *
4 * Copyright (C) 1994, 1995, 2000 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28
29/*
30 * Reads a list of bad blocks from a FILE *
31 */
32errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
33 ext2_badblocks_list *bb_list,
34 void *priv_data,
35 void (*invalid)(ext2_filsys fs,
36 blk_t blk,
37 char *badstr,
38 void *priv_data))
39{
40 errcode_t retval;
41 blk_t blockno;
42 int count;
43 char buf[128];
44
45 if (fs)
46 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
47
48 if (!*bb_list) {
49 retval = ext2fs_badblocks_list_create(bb_list, 10);
50 if (retval)
51 return retval;
52 }
53
54 while (!feof (f)) {
55 if (fgets(buf, sizeof(buf), f) == NULL)
56 break;
57 count = sscanf(buf, "%u", &blockno);
58 if (count <= 0)
59 continue;
60 if (fs &&
61 ((blockno < fs->super->s_first_data_block) ||
62 (blockno >= fs->super->s_blocks_count))) {
63 if (invalid)
64 (invalid)(fs, blockno, buf, priv_data);
65 continue;
66 }
67 retval = ext2fs_badblocks_list_add(*bb_list, blockno);
68 if (retval)
69 return retval;
70 }
71 return 0;
72}
73
74static void call_compat_invalid(ext2_filsys fs, blk_t blk,
75 char *badstr EXT2FS_ATTR((unused)),
76 void *priv_data)
77{
78 void (*invalid)(ext2_filsys, blk_t);
79
80 invalid = (void (*)(ext2_filsys, blk_t)) priv_data;
81 if (invalid)
82 invalid(fs, blk);
83}
84
85
86/*
87 * Reads a list of bad blocks from a FILE *
88 */
89errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
90 ext2_badblocks_list *bb_list,
91 void (*invalid)(ext2_filsys fs, blk_t blk))
92{
93 return ext2fs_read_bb_FILE2(fs, f, bb_list, (void *) invalid,
94 call_compat_invalid);
95}
96
97
diff --git a/e2fsprogs/ext2fs/res_gdt.c b/e2fsprogs/ext2fs/res_gdt.c
new file mode 100644
index 000000000..8b4ddca6d
--- /dev/null
+++ b/e2fsprogs/ext2fs/res_gdt.c
@@ -0,0 +1,220 @@
1/*
2 * res_gdt.c --- reserve blocks for growing the group descriptor table
3 * during online resizing.
4 *
5 * Copyright (C) 2002 Andreas Dilger
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 <time.h>
16#include "ext2_fs.h"
17#include "ext2fs.h"
18
19/*
20 * Iterate through the groups which hold BACKUP superblock/GDT copies in an
21 * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
22 * calling this for the first time. In a sparse filesystem it will be the
23 * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
24 * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
25 */
26static unsigned int list_backups(ext2_filsys fs, unsigned int *three,
27 unsigned int *five, unsigned int *seven)
28{
29 unsigned int *min = three;
30 int mult = 3;
31 unsigned int ret;
32
33 if (!(fs->super->s_feature_ro_compat &
34 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
35 ret = *min;
36 *min += 1;
37 return ret;
38 }
39
40 if (*five < *min) {
41 min = five;
42 mult = 5;
43 }
44 if (*seven < *min) {
45 min = seven;
46 mult = 7;
47 }
48
49 ret = *min;
50 *min *= mult;
51
52 return ret;
53}
54
55/*
56 * This code assumes that the reserved blocks have already been marked in-use
57 * during ext2fs_initialize(), so that they are not allocated for other
58 * uses before we can add them to the resize inode (which has to come
59 * after the creation of the inode table).
60 */
61errcode_t ext2fs_create_resize_inode(ext2_filsys fs)
62{
63 errcode_t retval, retval2;
64 struct ext2_super_block *sb;
65 struct ext2_inode inode;
66 __u32 *dindir_buf, *gdt_buf;
67 int rsv_add;
68 unsigned long long apb, inode_size;
69 blk_t dindir_blk, rsv_off, gdt_off, gdt_blk;
70 int dindir_dirty = 0, inode_dirty = 0;
71
72 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
73
74 sb = fs->super;
75
76 retval = ext2fs_get_mem(2 * fs->blocksize, (void **)&dindir_buf);
77 if (retval)
78 goto out_free;
79 gdt_buf = (__u32 *)((char *)dindir_buf + fs->blocksize);
80
81 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
82 if (retval)
83 goto out_free;
84
85 /* Maximum possible file size (we donly use the dindirect blocks) */
86 apb = EXT2_ADDR_PER_BLOCK(sb);
87 rsv_add = fs->blocksize / 512;
88 if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) {
89#ifdef RES_GDT_DEBUG
90 printf("reading GDT dindir %u\n", dindir_blk);
91#endif
92 retval = ext2fs_read_ind_block(fs, dindir_blk, dindir_buf);
93 if (retval)
94 goto out_inode;
95 } else {
96 blk_t goal = 3 + sb->s_reserved_gdt_blocks +
97 fs->desc_blocks + fs->inode_blocks_per_group;
98
99 retval = ext2fs_alloc_block(fs, goal, 0, &dindir_blk);
100 if (retval)
101 goto out_free;
102 inode.i_mode = LINUX_S_IFREG | 0600;
103 inode.i_links_count = 1;
104 inode.i_block[EXT2_DIND_BLOCK] = dindir_blk;
105 inode.i_blocks = rsv_add;
106 memset(dindir_buf, 0, fs->blocksize);
107#ifdef RES_GDT_DEBUG
108 printf("allocated GDT dindir %u\n", dindir_blk);
109#endif
110 dindir_dirty = inode_dirty = 1;
111 inode_size = apb*apb + apb + EXT2_NDIR_BLOCKS;
112 inode_size *= fs->blocksize;
113 inode.i_size = inode_size & 0xFFFFFFFF;
114 inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF;
115 if(inode.i_size_high) {
116 sb->s_feature_ro_compat |=
117 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
118 }
119 inode.i_ctime = time(0);
120 }
121
122 for (rsv_off = 0, gdt_off = fs->desc_blocks,
123 gdt_blk = sb->s_first_data_block + 1 + fs->desc_blocks;
124 rsv_off < sb->s_reserved_gdt_blocks;
125 rsv_off++, gdt_off++, gdt_blk++) {
126 unsigned int three = 1, five = 5, seven = 7;
127 unsigned int grp, last = 0;
128 int gdt_dirty = 0;
129
130 gdt_off %= apb;
131 if (!dindir_buf[gdt_off]) {
132 /* FIXME XXX XXX
133 blk_t new_blk;
134
135 retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk);
136 if (retval)
137 goto out_free;
138 if (new_blk != gdt_blk) {
139 // XXX free block
140 retval = -1; // XXX
141 }
142 */
143 gdt_dirty = dindir_dirty = inode_dirty = 1;
144 memset(gdt_buf, 0, fs->blocksize);
145 dindir_buf[gdt_off] = gdt_blk;
146 inode.i_blocks += rsv_add;
147#ifdef RES_GDT_DEBUG
148 printf("added primary GDT block %u at %u[%u]\n",
149 gdt_blk, dindir_blk, gdt_off);
150#endif
151 } else if (dindir_buf[gdt_off] == gdt_blk) {
152#ifdef RES_GDT_DEBUG
153 printf("reading primary GDT block %u\n", gdt_blk);
154#endif
155 retval = ext2fs_read_ind_block(fs, gdt_blk, gdt_buf);
156 if (retval)
157 goto out_dindir;
158 } else {
159#ifdef RES_GDT_DEBUG
160 printf("bad primary GDT %u != %u at %u[%u]\n",
161 dindir_buf[gdt_off], gdt_blk,dindir_blk,gdt_off);
162#endif
163 retval = EXT2_ET_RESIZE_INODE_CORRUPT;
164 goto out_dindir;
165 }
166
167 while ((grp = list_backups(fs, &three, &five, &seven)) <
168 fs->group_desc_count) {
169 blk_t expect = gdt_blk + grp * sb->s_blocks_per_group;
170
171 if (!gdt_buf[last]) {
172#ifdef RES_GDT_DEBUG
173 printf("added backup GDT %u grp %u@%u[%u]\n",
174 expect, grp, gdt_blk, last);
175#endif
176 gdt_buf[last] = expect;
177 inode.i_blocks += rsv_add;
178 gdt_dirty = inode_dirty = 1;
179 } else if (gdt_buf[last] != expect) {
180#ifdef RES_GDT_DEBUG
181 printf("bad backup GDT %u != %u at %u[%u]\n",
182 gdt_buf[last], expect, gdt_blk, last);
183#endif
184 retval = EXT2_ET_RESIZE_INODE_CORRUPT;
185 goto out_dindir;
186 }
187 last++;
188 }
189 if (gdt_dirty) {
190#ifdef RES_GDT_DEBUG
191 printf("writing primary GDT block %u\n", gdt_blk);
192#endif
193 retval = ext2fs_write_ind_block(fs, gdt_blk, gdt_buf);
194 if (retval)
195 goto out_dindir;
196 }
197 }
198
199out_dindir:
200 if (dindir_dirty) {
201 retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf);
202 if (!retval)
203 retval = retval2;
204 }
205out_inode:
206#ifdef RES_GDT_DEBUG
207 printf("inode.i_blocks = %u, i_size = %u\n", inode.i_blocks,
208 inode.i_size);
209#endif
210 if (inode_dirty) {
211 inode.i_atime = inode.i_mtime = time(0);
212 retval2 = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
213 if (!retval)
214 retval = retval2;
215 }
216out_free:
217 ext2fs_free_mem((void **)&dindir_buf);
218 return retval;
219}
220
diff --git a/e2fsprogs/ext2fs/rs_bitmap.c b/e2fsprogs/ext2fs/rs_bitmap.c
new file mode 100644
index 000000000..46653f0ec
--- /dev/null
+++ b/e2fsprogs/ext2fs/rs_bitmap.c
@@ -0,0 +1,106 @@
1/*
2 * rs_bitmap.c --- routine for changing the size of a bitmap
3 *
4 * Copyright (C) 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#ifdef HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28
29errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, __u32 new_real_end,
30 ext2fs_generic_bitmap bmap)
31{
32 errcode_t retval;
33 size_t size, new_size;
34 __u32 bitno;
35
36 if (!bmap)
37 return EXT2_ET_INVALID_ARGUMENT;
38
39 EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP);
40
41 /*
42 * If we're expanding the bitmap, make sure all of the new
43 * parts of the bitmap are zero.
44 */
45 if (new_end > bmap->end) {
46 bitno = bmap->real_end;
47 if (bitno > new_end)
48 bitno = new_end;
49 for (; bitno > bmap->end; bitno--)
50 ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
51 }
52 if (new_real_end == bmap->real_end) {
53 bmap->end = new_end;
54 return 0;
55 }
56
57 size = ((bmap->real_end - bmap->start) / 8) + 1;
58 new_size = ((new_real_end - bmap->start) / 8) + 1;
59
60 if (size != new_size) {
61 retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap);
62 if (retval)
63 return retval;
64 }
65 if (new_size > size)
66 memset(bmap->bitmap + size, 0, new_size - size);
67
68 bmap->end = new_end;
69 bmap->real_end = new_real_end;
70 return 0;
71}
72
73errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
74 ext2fs_inode_bitmap bmap)
75{
76 errcode_t retval;
77
78 if (!bmap)
79 return EXT2_ET_INVALID_ARGUMENT;
80
81 EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_INODE_BITMAP);
82
83 bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
84 retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
85 bmap);
86 bmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
87 return retval;
88}
89
90errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
91 ext2fs_block_bitmap bmap)
92{
93 errcode_t retval;
94
95 if (!bmap)
96 return EXT2_ET_INVALID_ARGUMENT;
97
98 EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
99
100 bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
101 retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
102 bmap);
103 bmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
104 return retval;
105}
106
diff --git a/e2fsprogs/ext2fs/rw_bitmaps.c b/e2fsprogs/ext2fs/rw_bitmaps.c
new file mode 100644
index 000000000..b67a92599
--- /dev/null
+++ b/e2fsprogs/ext2fs/rw_bitmaps.c
@@ -0,0 +1,300 @@
1/*
2 * rw_bitmaps.c --- routines to read and write the inode and block bitmaps.
3 *
4 * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#ifdef HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28#include "e2image.h"
29
30#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
31/*
32 * On the PowerPC, the big-endian variant of the ext2 filesystem
33 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
34 * of each word. Thus a bitmap with only bit 0 set would be, as
35 * a string of bytes, 00 00 00 01 00 ...
36 * To cope with this, we byte-reverse each word of a bitmap if
37 * we have a big-endian filesystem, that is, if we are *not*
38 * byte-swapping other word-sized numbers.
39 */
40#define EXT2_BIG_ENDIAN_BITMAPS
41#endif
42
43#ifdef EXT2_BIG_ENDIAN_BITMAPS
44static void ext2fs_swap_bitmap(ext2_filsys fs, char *bitmap, int nbytes)
45{
46 __u32 *p = (__u32 *) bitmap;
47 int n;
48
49 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
50 *p = ext2fs_swab32(*p);
51}
52#endif
53
54errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
55{
56 dgrp_t i;
57 size_t nbytes;
58 errcode_t retval;
59 char * inode_bitmap = fs->inode_map->bitmap;
60 char * bitmap_block = NULL;
61 blk_t blk;
62
63 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
64
65 if (!(fs->flags & EXT2_FLAG_RW))
66 return EXT2_ET_RO_FILSYS;
67 if (!inode_bitmap)
68 return 0;
69 nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
70
71 retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
72 if (retval)
73 return retval;
74 memset(bitmap_block, 0xff, fs->blocksize);
75 for (i = 0; i < fs->group_desc_count; i++) {
76 memcpy(bitmap_block, inode_bitmap, nbytes);
77 blk = fs->group_desc[i].bg_inode_bitmap;
78 if (blk) {
79#ifdef EXT2_BIG_ENDIAN_BITMAPS
80 if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
81 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
82 ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
83#endif
84 retval = io_channel_write_blk(fs->io, blk, 1,
85 bitmap_block);
86 if (retval)
87 return EXT2_ET_INODE_BITMAP_WRITE;
88 }
89 inode_bitmap += nbytes;
90 }
91 fs->flags &= ~EXT2_FLAG_IB_DIRTY;
92 ext2fs_free_mem(&bitmap_block);
93 return 0;
94}
95
96errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
97{
98 dgrp_t i;
99 unsigned int j;
100 int nbytes;
101 unsigned int nbits;
102 errcode_t retval;
103 char * block_bitmap = fs->block_map->bitmap;
104 char * bitmap_block = NULL;
105 blk_t blk;
106
107 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
108
109 if (!(fs->flags & EXT2_FLAG_RW))
110 return EXT2_ET_RO_FILSYS;
111 if (!block_bitmap)
112 return 0;
113 nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
114 retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
115 if (retval)
116 return retval;
117 memset(bitmap_block, 0xff, fs->blocksize);
118 for (i = 0; i < fs->group_desc_count; i++) {
119 memcpy(bitmap_block, block_bitmap, nbytes);
120 if (i == fs->group_desc_count - 1) {
121 /* Force bitmap padding for the last group */
122 nbits = ((fs->super->s_blocks_count
123 - fs->super->s_first_data_block)
124 % EXT2_BLOCKS_PER_GROUP(fs->super));
125 if (nbits)
126 for (j = nbits; j < fs->blocksize * 8; j++)
127 ext2fs_set_bit(j, bitmap_block);
128 }
129 blk = fs->group_desc[i].bg_block_bitmap;
130 if (blk) {
131#ifdef EXT2_BIG_ENDIAN_BITMAPS
132 if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
133 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
134 ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
135#endif
136 retval = io_channel_write_blk(fs->io, blk, 1,
137 bitmap_block);
138 if (retval)
139 return EXT2_ET_BLOCK_BITMAP_WRITE;
140 }
141 block_bitmap += nbytes;
142 }
143 fs->flags &= ~EXT2_FLAG_BB_DIRTY;
144 ext2fs_free_mem(&bitmap_block);
145 return 0;
146}
147
148static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
149{
150 dgrp_t i;
151 char *block_bitmap = 0, *inode_bitmap = 0;
152 char *buf;
153 errcode_t retval;
154 int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
155 int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
156 blk_t blk;
157
158 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
159
160 fs->write_bitmaps = ext2fs_write_bitmaps;
161
162 retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
163 if (retval)
164 return retval;
165 if (do_block) {
166 if (fs->block_map)
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 if (fs->inode_map)
176 ext2fs_free_inode_bitmap(fs->inode_map);
177 sprintf(buf, "inode bitmap for %s", fs->device_name);
178 retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
179 if (retval)
180 goto cleanup;
181 inode_bitmap = fs->inode_map->bitmap;
182 }
183 ext2fs_free_mem(&buf);
184
185 if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
186 if (inode_bitmap) {
187 blk = (fs->image_header->offset_inodemap /
188 fs->blocksize);
189 retval = io_channel_read_blk(fs->image_io, blk,
190 -(inode_nbytes * fs->group_desc_count),
191 inode_bitmap);
192 if (retval)
193 goto cleanup;
194 }
195 if (block_bitmap) {
196 blk = (fs->image_header->offset_blockmap /
197 fs->blocksize);
198 retval = io_channel_read_blk(fs->image_io, blk,
199 -(block_nbytes * fs->group_desc_count),
200 block_bitmap);
201 if (retval)
202 goto cleanup;
203 }
204 return 0;
205 }
206
207 for (i = 0; i < fs->group_desc_count; i++) {
208 if (block_bitmap) {
209 blk = fs->group_desc[i].bg_block_bitmap;
210 if (blk) {
211 retval = io_channel_read_blk(fs->io, blk,
212 -block_nbytes, block_bitmap);
213 if (retval) {
214 retval = EXT2_ET_BLOCK_BITMAP_READ;
215 goto cleanup;
216 }
217#ifdef EXT2_BIG_ENDIAN_BITMAPS
218 if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
219 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
220 ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes);
221#endif
222 } else
223 memset(block_bitmap, 0, block_nbytes);
224 block_bitmap += block_nbytes;
225 }
226 if (inode_bitmap) {
227 blk = fs->group_desc[i].bg_inode_bitmap;
228 if (blk) {
229 retval = io_channel_read_blk(fs->io, blk,
230 -inode_nbytes, inode_bitmap);
231 if (retval) {
232 retval = EXT2_ET_INODE_BITMAP_READ;
233 goto cleanup;
234 }
235#ifdef EXT2_BIG_ENDIAN_BITMAPS
236 if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
237 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
238 ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes);
239#endif
240 } else
241 memset(inode_bitmap, 0, inode_nbytes);
242 inode_bitmap += inode_nbytes;
243 }
244 }
245 return 0;
246
247cleanup:
248 if (do_block) {
249 ext2fs_free_mem(&fs->block_map);
250 fs->block_map = 0;
251 }
252 if (do_inode) {
253 ext2fs_free_mem(&fs->inode_map);
254 fs->inode_map = 0;
255 }
256 if (buf)
257 ext2fs_free_mem(&buf);
258 return retval;
259}
260
261errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs)
262{
263 return read_bitmaps(fs, 1, 0);
264}
265
266errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
267{
268 return read_bitmaps(fs, 0, 1);
269}
270
271errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
272{
273
274 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
275
276 if (fs->inode_map && fs->block_map)
277 return 0;
278
279 return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
280}
281
282errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
283{
284 errcode_t retval;
285
286 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
287
288 if (fs->block_map && ext2fs_test_bb_dirty(fs)) {
289 retval = ext2fs_write_block_bitmap(fs);
290 if (retval)
291 return retval;
292 }
293 if (fs->inode_map && ext2fs_test_ib_dirty(fs)) {
294 retval = ext2fs_write_inode_bitmap(fs);
295 if (retval)
296 return retval;
297 }
298 return 0;
299}
300
diff --git a/e2fsprogs/ext2fs/sparse.c b/e2fsprogs/ext2fs/sparse.c
new file mode 100644
index 000000000..90b028f09
--- /dev/null
+++ b/e2fsprogs/ext2fs/sparse.c
@@ -0,0 +1,78 @@
1/*
2 * sparse.c --- find the groups in an ext2 filesystem with metadata backups
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 * Copyright (C) 2002 Andreas Dilger.
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 "ext2fsP.h"
17
18static int test_root(int a, int b)
19{
20 if (a == 0)
21 return 1;
22 while (1) {
23 if (a == 1)
24 return 1;
25 if (a % b)
26 return 0;
27 a = a / b;
28 }
29}
30
31int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
32{
33 if (!(fs->super->s_feature_ro_compat &
34 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
35 return 1;
36
37 if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
38 test_root(group_block, 7))
39 return 1;
40
41 return 0;
42}
43
44/*
45 * Iterate through the groups which hold BACKUP superblock/GDT copies in an
46 * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
47 * calling this for the first time. In a sparse filesystem it will be the
48 * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
49 * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
50 */
51unsigned int ext2fs_list_backups(ext2_filsys fs, unsigned int *three,
52 unsigned int *five, unsigned int *seven)
53{
54 unsigned int *min = three;
55 int mult = 3;
56 unsigned int ret;
57
58 if (!(fs->super->s_feature_ro_compat &
59 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
60 ret = *min;
61 *min += 1;
62 return ret;
63 }
64
65 if (*five < *min) {
66 min = five;
67 mult = 5;
68 }
69 if (*seven < *min) {
70 min = seven;
71 mult = 7;
72 }
73
74 ret = *min;
75 *min *= mult;
76
77 return ret;
78}
diff --git a/e2fsprogs/ext2fs/swapfs.c b/e2fsprogs/ext2fs/swapfs.c
new file mode 100644
index 000000000..908170129
--- /dev/null
+++ b/e2fsprogs/ext2fs/swapfs.c
@@ -0,0 +1,237 @@
1/*
2 * swapfs.c --- swap ext2 filesystem data structures
3 *
4 * Copyright (C) 1995, 1996, 2002 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#if HAVE_UNISTD_H
14#include <unistd.h>
15#endif
16#include <string.h>
17#include <time.h>
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21#include <ext2fs/ext2_ext_attr.h>
22
23#ifdef EXT2FS_ENABLE_SWAPFS
24void ext2fs_swap_super(struct ext2_super_block * sb)
25{
26 int i;
27 sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count);
28 sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count);
29 sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count);
30 sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count);
31 sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count);
32 sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block);
33 sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size);
34 sb->s_log_frag_size = ext2fs_swab32(sb->s_log_frag_size);
35 sb->s_blocks_per_group = ext2fs_swab32(sb->s_blocks_per_group);
36 sb->s_frags_per_group = ext2fs_swab32(sb->s_frags_per_group);
37 sb->s_inodes_per_group = ext2fs_swab32(sb->s_inodes_per_group);
38 sb->s_mtime = ext2fs_swab32(sb->s_mtime);
39 sb->s_wtime = ext2fs_swab32(sb->s_wtime);
40 sb->s_mnt_count = ext2fs_swab16(sb->s_mnt_count);
41 sb->s_max_mnt_count = ext2fs_swab16(sb->s_max_mnt_count);
42 sb->s_magic = ext2fs_swab16(sb->s_magic);
43 sb->s_state = ext2fs_swab16(sb->s_state);
44 sb->s_errors = ext2fs_swab16(sb->s_errors);
45 sb->s_minor_rev_level = ext2fs_swab16(sb->s_minor_rev_level);
46 sb->s_lastcheck = ext2fs_swab32(sb->s_lastcheck);
47 sb->s_checkinterval = ext2fs_swab32(sb->s_checkinterval);
48 sb->s_creator_os = ext2fs_swab32(sb->s_creator_os);
49 sb->s_rev_level = ext2fs_swab32(sb->s_rev_level);
50 sb->s_def_resuid = ext2fs_swab16(sb->s_def_resuid);
51 sb->s_def_resgid = ext2fs_swab16(sb->s_def_resgid);
52 sb->s_first_ino = ext2fs_swab32(sb->s_first_ino);
53 sb->s_inode_size = ext2fs_swab16(sb->s_inode_size);
54 sb->s_block_group_nr = ext2fs_swab16(sb->s_block_group_nr);
55 sb->s_feature_compat = ext2fs_swab32(sb->s_feature_compat);
56 sb->s_feature_incompat = ext2fs_swab32(sb->s_feature_incompat);
57 sb->s_feature_ro_compat = ext2fs_swab32(sb->s_feature_ro_compat);
58 sb->s_algorithm_usage_bitmap = ext2fs_swab32(sb->s_algorithm_usage_bitmap);
59 sb->s_reserved_gdt_blocks = ext2fs_swab16(sb->s_reserved_gdt_blocks);
60 sb->s_journal_inum = ext2fs_swab32(sb->s_journal_inum);
61 sb->s_journal_dev = ext2fs_swab32(sb->s_journal_dev);
62 sb->s_last_orphan = ext2fs_swab32(sb->s_last_orphan);
63 sb->s_default_mount_opts = ext2fs_swab32(sb->s_default_mount_opts);
64 sb->s_first_meta_bg = ext2fs_swab32(sb->s_first_meta_bg);
65 sb->s_mkfs_time = ext2fs_swab32(sb->s_mkfs_time);
66 for (i=0; i < 4; i++)
67 sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]);
68 for (i=0; i < 17; i++)
69 sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]);
70
71}
72
73void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)
74{
75 gdp->bg_block_bitmap = ext2fs_swab32(gdp->bg_block_bitmap);
76 gdp->bg_inode_bitmap = ext2fs_swab32(gdp->bg_inode_bitmap);
77 gdp->bg_inode_table = ext2fs_swab32(gdp->bg_inode_table);
78 gdp->bg_free_blocks_count = ext2fs_swab16(gdp->bg_free_blocks_count);
79 gdp->bg_free_inodes_count = ext2fs_swab16(gdp->bg_free_inodes_count);
80 gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
81}
82
83void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
84{
85 struct ext2_ext_attr_header *from_header =
86 (struct ext2_ext_attr_header *)from;
87 struct ext2_ext_attr_header *to_header =
88 (struct ext2_ext_attr_header *)to;
89 struct ext2_ext_attr_entry *from_entry, *to_entry;
90 char *from_end = (char *)from_header + bufsize;
91 int n;
92
93 if (to_header != from_header)
94 memcpy(to_header, from_header, bufsize);
95
96 from_entry = (struct ext2_ext_attr_entry *)from_header;
97 to_entry = (struct ext2_ext_attr_entry *)to_header;
98
99 if (has_header) {
100 to_header->h_magic = ext2fs_swab32(from_header->h_magic);
101 to_header->h_blocks = ext2fs_swab32(from_header->h_blocks);
102 to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
103 for (n=0; n<4; n++)
104 to_header->h_reserved[n] =
105 ext2fs_swab32(from_header->h_reserved[n]);
106 from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
107 to_entry = (struct ext2_ext_attr_entry *)(to_header+1);
108 }
109
110 while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
111 to_entry->e_value_offs =
112 ext2fs_swab16(from_entry->e_value_offs);
113 to_entry->e_value_block =
114 ext2fs_swab32(from_entry->e_value_block);
115 to_entry->e_value_size =
116 ext2fs_swab32(from_entry->e_value_size);
117 from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
118 to_entry = EXT2_EXT_ATTR_NEXT(to_entry);
119 }
120}
121
122void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
123 struct ext2_inode_large *f, int hostorder,
124 int bufsize)
125{
126 unsigned i;
127 int islnk = 0;
128 __u32 *eaf, *eat;
129
130 if (hostorder && LINUX_S_ISLNK(f->i_mode))
131 islnk = 1;
132 t->i_mode = ext2fs_swab16(f->i_mode);
133 if (!hostorder && LINUX_S_ISLNK(t->i_mode))
134 islnk = 1;
135 t->i_uid = ext2fs_swab16(f->i_uid);
136 t->i_size = ext2fs_swab32(f->i_size);
137 t->i_atime = ext2fs_swab32(f->i_atime);
138 t->i_ctime = ext2fs_swab32(f->i_ctime);
139 t->i_mtime = ext2fs_swab32(f->i_mtime);
140 t->i_dtime = ext2fs_swab32(f->i_dtime);
141 t->i_gid = ext2fs_swab16(f->i_gid);
142 t->i_links_count = ext2fs_swab16(f->i_links_count);
143 t->i_blocks = ext2fs_swab32(f->i_blocks);
144 t->i_flags = ext2fs_swab32(f->i_flags);
145 t->i_file_acl = ext2fs_swab32(f->i_file_acl);
146 t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
147 if (!islnk || ext2fs_inode_data_blocks(fs, (struct ext2_inode *)t)) {
148 for (i = 0; i < EXT2_N_BLOCKS; i++)
149 t->i_block[i] = ext2fs_swab32(f->i_block[i]);
150 } else if (t != f) {
151 for (i = 0; i < EXT2_N_BLOCKS; i++)
152 t->i_block[i] = f->i_block[i];
153 }
154 t->i_generation = ext2fs_swab32(f->i_generation);
155 t->i_faddr = ext2fs_swab32(f->i_faddr);
156
157 switch (fs->super->s_creator_os) {
158 case EXT2_OS_LINUX:
159 t->osd1.linux1.l_i_reserved1 =
160 ext2fs_swab32(f->osd1.linux1.l_i_reserved1);
161 t->osd2.linux2.l_i_frag = f->osd2.linux2.l_i_frag;
162 t->osd2.linux2.l_i_fsize = f->osd2.linux2.l_i_fsize;
163 t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1);
164 t->osd2.linux2.l_i_uid_high =
165 ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
166 t->osd2.linux2.l_i_gid_high =
167 ext2fs_swab16 (f->osd2.linux2.l_i_gid_high);
168 t->osd2.linux2.l_i_reserved2 =
169 ext2fs_swab32(f->osd2.linux2.l_i_reserved2);
170 break;
171 case EXT2_OS_HURD:
172 t->osd1.hurd1.h_i_translator =
173 ext2fs_swab32 (f->osd1.hurd1.h_i_translator);
174 t->osd2.hurd2.h_i_frag = f->osd2.hurd2.h_i_frag;
175 t->osd2.hurd2.h_i_fsize = f->osd2.hurd2.h_i_fsize;
176 t->osd2.hurd2.h_i_mode_high =
177 ext2fs_swab16 (f->osd2.hurd2.h_i_mode_high);
178 t->osd2.hurd2.h_i_uid_high =
179 ext2fs_swab16 (f->osd2.hurd2.h_i_uid_high);
180 t->osd2.hurd2.h_i_gid_high =
181 ext2fs_swab16 (f->osd2.hurd2.h_i_gid_high);
182 t->osd2.hurd2.h_i_author =
183 ext2fs_swab32 (f->osd2.hurd2.h_i_author);
184 break;
185 case EXT2_OS_MASIX:
186 t->osd1.masix1.m_i_reserved1 =
187 ext2fs_swab32(f->osd1.masix1.m_i_reserved1);
188 t->osd2.masix2.m_i_frag = f->osd2.masix2.m_i_frag;
189 t->osd2.masix2.m_i_fsize = f->osd2.masix2.m_i_fsize;
190 t->osd2.masix2.m_pad1 = ext2fs_swab16(f->osd2.masix2.m_pad1);
191 t->osd2.masix2.m_i_reserved2[0] =
192 ext2fs_swab32(f->osd2.masix2.m_i_reserved2[0]);
193 t->osd2.masix2.m_i_reserved2[1] =
194 ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]);
195 break;
196 }
197
198 if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
199 return; /* no i_extra_isize field */
200
201 t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
202 if (t->i_extra_isize > EXT2_INODE_SIZE(fs->super) -
203 sizeof(struct ext2_inode)) {
204 /* this is error case: i_extra_size is too large */
205 return;
206 }
207
208 i = sizeof(struct ext2_inode) + t->i_extra_isize + sizeof(__u32);
209 if (bufsize < (int) i)
210 return; /* no space for EA magic */
211
212 eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
213 f->i_extra_isize);
214
215 if (ext2fs_swab32(*eaf) != EXT2_EXT_ATTR_MAGIC)
216 return; /* it seems no magic here */
217
218 eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
219 f->i_extra_isize);
220 *eat = ext2fs_swab32(*eaf);
221
222 /* convert EA(s) */
223 ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
224 bufsize - sizeof(struct ext2_inode) -
225 t->i_extra_isize - sizeof(__u32), 0);
226
227}
228
229void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
230 struct ext2_inode *f, int hostorder)
231{
232 ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
233 (struct ext2_inode_large *) f, hostorder,
234 sizeof(struct ext2_inode));
235}
236
237#endif
diff --git a/e2fsprogs/ext2fs/test_io.c b/e2fsprogs/ext2fs/test_io.c
new file mode 100644
index 000000000..6a3b248e9
--- /dev/null
+++ b/e2fsprogs/ext2fs/test_io.c
@@ -0,0 +1,382 @@
1/*
2 * test_io.c --- This is the Test I/O interface.
3 *
4 * Copyright (C) 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fs.h"
28
29/*
30 * For checking structure magic numbers...
31 */
32
33#define EXT2_CHECK_MAGIC(struct, code) \
34 if ((struct)->magic != (code)) return (code)
35
36struct test_private_data {
37 int magic;
38 io_channel real;
39 int flags;
40 FILE *outfile;
41 unsigned long block;
42 int read_abort_count, write_abort_count;
43 void (*read_blk)(unsigned long block, int count, errcode_t err);
44 void (*write_blk)(unsigned long block, int count, errcode_t err);
45 void (*set_blksize)(int blksize, errcode_t err);
46 void (*write_byte)(unsigned long block, int count, errcode_t err);
47};
48
49static errcode_t test_open(const char *name, int flags, io_channel *channel);
50static errcode_t test_close(io_channel channel);
51static errcode_t test_set_blksize(io_channel channel, int blksize);
52static errcode_t test_read_blk(io_channel channel, unsigned long block,
53 int count, void *data);
54static errcode_t test_write_blk(io_channel channel, unsigned long block,
55 int count, const void *data);
56static errcode_t test_flush(io_channel channel);
57static errcode_t test_write_byte(io_channel channel, unsigned long offset,
58 int count, const void *buf);
59static errcode_t test_set_option(io_channel channel, const char *option,
60 const char *arg);
61
62static struct struct_io_manager struct_test_manager = {
63 EXT2_ET_MAGIC_IO_MANAGER,
64 "Test I/O Manager",
65 test_open,
66 test_close,
67 test_set_blksize,
68 test_read_blk,
69 test_write_blk,
70 test_flush,
71 test_write_byte,
72 test_set_option
73};
74
75io_manager test_io_manager = &struct_test_manager;
76
77/*
78 * These global variable can be set by the test program as
79 * necessary *before* calling test_open
80 */
81io_manager test_io_backing_manager = 0;
82void (*test_io_cb_read_blk)
83 (unsigned long block, int count, errcode_t err) = 0;
84void (*test_io_cb_write_blk)
85 (unsigned long block, int count, errcode_t err) = 0;
86void (*test_io_cb_set_blksize)
87 (int blksize, errcode_t err) = 0;
88void (*test_io_cb_write_byte)
89 (unsigned long block, int count, errcode_t err) = 0;
90
91/*
92 * Test flags
93 */
94#define TEST_FLAG_READ 0x01
95#define TEST_FLAG_WRITE 0x02
96#define TEST_FLAG_SET_BLKSIZE 0x04
97#define TEST_FLAG_FLUSH 0x08
98#define TEST_FLAG_DUMP 0x10
99#define TEST_FLAG_SET_OPTION 0x20
100
101static void test_dump_block(io_channel channel,
102 struct test_private_data *data,
103 unsigned long block, const void *buf)
104{
105 const unsigned char *cp;
106 FILE *f = data->outfile;
107 int i;
108 unsigned long cksum = 0;
109
110 for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
111 cksum += *cp;
112 }
113 fprintf(f, "Contents of block %lu, checksum %08lu: \n", block, cksum);
114 for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
115 if ((i % 16) == 0)
116 fprintf(f, "%04x: ", i);
117 fprintf(f, "%02x%c", *cp, ((i % 16) == 15) ? '\n' : ' ');
118 }
119}
120
121static void test_abort(io_channel channel, unsigned long block)
122{
123 struct test_private_data *data;
124 FILE *f;
125
126 data = (struct test_private_data *) channel->private_data;
127 f = data->outfile;
128 test_flush(channel);
129
130 fprintf(f, "Aborting due to I/O to block %lu\n", block);
131 fflush(f);
132 abort();
133}
134
135static errcode_t test_open(const char *name, int flags, io_channel *channel)
136{
137 io_channel io = NULL;
138 struct test_private_data *data = NULL;
139 errcode_t retval;
140 char *value;
141
142 if (name == 0)
143 return EXT2_ET_BAD_DEVICE_NAME;
144 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
145 if (retval)
146 return retval;
147 memset(io, 0, sizeof(struct struct_io_channel));
148 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
149 retval = ext2fs_get_mem(sizeof(struct test_private_data), &data);
150 if (retval) {
151 retval = EXT2_ET_NO_MEMORY;
152 goto cleanup;
153 }
154 io->manager = test_io_manager;
155 retval = ext2fs_get_mem(strlen(name)+1, &io->name);
156 if (retval)
157 goto cleanup;
158
159 strcpy(io->name, name);
160 io->private_data = data;
161 io->block_size = 1024;
162 io->read_error = 0;
163 io->write_error = 0;
164 io->refcount = 1;
165
166 memset(data, 0, sizeof(struct test_private_data));
167 data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL;
168 if (test_io_backing_manager) {
169 retval = test_io_backing_manager->open(name, flags,
170 &data->real);
171 if (retval)
172 goto cleanup;
173 } else
174 data->real = 0;
175 data->read_blk = test_io_cb_read_blk;
176 data->write_blk = test_io_cb_write_blk;
177 data->set_blksize = test_io_cb_set_blksize;
178 data->write_byte = test_io_cb_write_byte;
179
180 data->outfile = NULL;
181 if ((value = getenv("TEST_IO_LOGFILE")) != NULL)
182 data->outfile = fopen(value, "w");
183 if (!data->outfile)
184 data->outfile = stderr;
185
186 data->flags = 0;
187 if ((value = getenv("TEST_IO_FLAGS")) != NULL)
188 data->flags = strtoul(value, NULL, 0);
189
190 data->block = 0;
191 if ((value = getenv("TEST_IO_BLOCK")) != NULL)
192 data->block = strtoul(value, NULL, 0);
193
194 data->read_abort_count = 0;
195 if ((value = getenv("TEST_IO_READ_ABORT")) != NULL)
196 data->read_abort_count = strtoul(value, NULL, 0);
197
198 data->write_abort_count = 0;
199 if ((value = getenv("TEST_IO_WRITE_ABORT")) != NULL)
200 data->write_abort_count = strtoul(value, NULL, 0);
201
202 *channel = io;
203 return 0;
204
205cleanup:
206 if (io)
207 ext2fs_free_mem(&io);
208 if (data)
209 ext2fs_free_mem(&data);
210 return retval;
211}
212
213static errcode_t test_close(io_channel channel)
214{
215 struct test_private_data *data;
216 errcode_t retval = 0;
217
218 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
219 data = (struct test_private_data *) channel->private_data;
220 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
221
222 if (--channel->refcount > 0)
223 return 0;
224
225 if (data->real)
226 retval = io_channel_close(data->real);
227
228 if (data->outfile && data->outfile != stderr)
229 fclose(data->outfile);
230
231 ext2fs_free_mem(&channel->private_data);
232 if (channel->name)
233 ext2fs_free_mem(&channel->name);
234 ext2fs_free_mem(&channel);
235 return retval;
236}
237
238static errcode_t test_set_blksize(io_channel channel, int blksize)
239{
240 struct test_private_data *data;
241 errcode_t retval = 0;
242
243 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
244 data = (struct test_private_data *) channel->private_data;
245 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
246
247 if (data->real)
248 retval = io_channel_set_blksize(data->real, blksize);
249 if (data->set_blksize)
250 data->set_blksize(blksize, retval);
251 if (data->flags & TEST_FLAG_SET_BLKSIZE)
252 fprintf(data->outfile,
253 "Test_io: set_blksize(%d) returned %s\n",
254 blksize, retval ? error_message(retval) : "OK");
255 channel->block_size = blksize;
256 return retval;
257}
258
259
260static errcode_t test_read_blk(io_channel channel, unsigned long block,
261 int count, void *buf)
262{
263 struct test_private_data *data;
264 errcode_t retval = 0;
265
266 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
267 data = (struct test_private_data *) channel->private_data;
268 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
269
270 if (data->real)
271 retval = io_channel_read_blk(data->real, block, count, buf);
272 if (data->read_blk)
273 data->read_blk(block, count, retval);
274 if (data->flags & TEST_FLAG_READ)
275 fprintf(data->outfile,
276 "Test_io: read_blk(%lu, %d) returned %s\n",
277 block, count, retval ? error_message(retval) : "OK");
278 if (data->block && data->block == block) {
279 if (data->flags & TEST_FLAG_DUMP)
280 test_dump_block(channel, data, block, buf);
281 if (--data->read_abort_count == 0)
282 test_abort(channel, block);
283 }
284 return retval;
285}
286
287static errcode_t test_write_blk(io_channel channel, unsigned long block,
288 int count, const void *buf)
289{
290 struct test_private_data *data;
291 errcode_t retval = 0;
292
293 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
294 data = (struct test_private_data *) channel->private_data;
295 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
296
297 if (data->real)
298 retval = io_channel_write_blk(data->real, block, count, buf);
299 if (data->write_blk)
300 data->write_blk(block, count, retval);
301 if (data->flags & TEST_FLAG_WRITE)
302 fprintf(data->outfile,
303 "Test_io: write_blk(%lu, %d) returned %s\n",
304 block, count, retval ? error_message(retval) : "OK");
305 if (data->block && data->block == block) {
306 if (data->flags & TEST_FLAG_DUMP)
307 test_dump_block(channel, data, block, buf);
308 if (--data->write_abort_count == 0)
309 test_abort(channel, block);
310 }
311 return retval;
312}
313
314static errcode_t test_write_byte(io_channel channel, unsigned long offset,
315 int count, const void *buf)
316{
317 struct test_private_data *data;
318 errcode_t retval = 0;
319
320 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
321 data = (struct test_private_data *) channel->private_data;
322 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
323
324 if (data->real && data->real->manager->write_byte)
325 retval = io_channel_write_byte(data->real, offset, count, buf);
326 if (data->write_byte)
327 data->write_byte(offset, count, retval);
328 if (data->flags & TEST_FLAG_WRITE)
329 fprintf(data->outfile,
330 "Test_io: write_byte(%lu, %d) returned %s\n",
331 offset, count, retval ? error_message(retval) : "OK");
332 return retval;
333}
334
335/*
336 * Flush data buffers to disk.
337 */
338static errcode_t test_flush(io_channel channel)
339{
340 struct test_private_data *data;
341 errcode_t retval = 0;
342
343 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
344 data = (struct test_private_data *) channel->private_data;
345 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
346
347 if (data->real)
348 retval = io_channel_flush(data->real);
349
350 if (data->flags & TEST_FLAG_FLUSH)
351 fprintf(data->outfile, "Test_io: flush() returned %s\n",
352 retval ? error_message(retval) : "OK");
353
354 return retval;
355}
356
357static errcode_t test_set_option(io_channel channel, const char *option,
358 const char *arg)
359{
360 struct test_private_data *data;
361 errcode_t retval = 0;
362
363 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
364 data = (struct test_private_data *) channel->private_data;
365 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
366
367
368 if (data->flags & TEST_FLAG_SET_OPTION)
369 fprintf(data->outfile, "Test_io: set_option(%s, %s) ",
370 option, arg);
371 if (data->real && data->real->manager->set_option) {
372 retval = (data->real->manager->set_option)(data->real,
373 option, arg);
374 if (data->flags & TEST_FLAG_SET_OPTION)
375 fprintf(data->outfile, "returned %s\n",
376 retval ? error_message(retval) : "OK");
377 } else {
378 if (data->flags & TEST_FLAG_SET_OPTION)
379 fprintf(data->outfile, "not implemented\n");
380 }
381 return retval;
382}
diff --git a/e2fsprogs/ext2fs/unix_io.c b/e2fsprogs/ext2fs/unix_io.c
new file mode 100644
index 000000000..5bc7a6abe
--- /dev/null
+++ b/e2fsprogs/ext2fs/unix_io.c
@@ -0,0 +1,707 @@
1/*
2 * unix_io.c --- This is the Unix (well, really POSIX) implementation
3 * of the I/O manager.
4 *
5 * Implements a one-block write-through cache.
6 *
7 * Includes support for Windows NT support under Cygwin.
8 *
9 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
10 * 2002 by Theodore Ts'o.
11 *
12 * %Begin-Header%
13 * This file may be redistributed under the terms of the GNU Public
14 * License.
15 * %End-Header%
16 */
17
18#include <stdio.h>
19#include <string.h>
20#if HAVE_UNISTD_H
21#include <unistd.h>
22#endif
23#if HAVE_ERRNO_H
24#include <errno.h>
25#endif
26#include <fcntl.h>
27#include <time.h>
28#ifdef __linux__
29#include <sys/utsname.h>
30#endif
31#if HAVE_SYS_STAT_H
32#include <sys/stat.h>
33#endif
34#if HAVE_SYS_TYPES_H
35#include <sys/types.h>
36#endif
37#if HAVE_SYS_RESOURCE_H
38#include <sys/resource.h>
39#endif
40
41#include "ext2_fs.h"
42#include "ext2fs.h"
43
44/*
45 * For checking structure magic numbers...
46 */
47
48#define EXT2_CHECK_MAGIC(struct, code) \
49 if ((struct)->magic != (code)) return (code)
50
51struct unix_cache {
52 char *buf;
53 unsigned long block;
54 int access_time;
55 unsigned dirty:1;
56 unsigned in_use:1;
57};
58
59#define CACHE_SIZE 8
60#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */
61#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */
62
63struct unix_private_data {
64 int magic;
65 int dev;
66 int flags;
67 int access_time;
68 ext2_loff_t offset;
69 struct unix_cache cache[CACHE_SIZE];
70};
71
72static errcode_t unix_open(const char *name, int flags, io_channel *channel);
73static errcode_t unix_close(io_channel channel);
74static errcode_t unix_set_blksize(io_channel channel, int blksize);
75static errcode_t unix_read_blk(io_channel channel, unsigned long block,
76 int count, void *data);
77static errcode_t unix_write_blk(io_channel channel, unsigned long block,
78 int count, const void *data);
79static errcode_t unix_flush(io_channel channel);
80static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
81 int size, const void *data);
82static errcode_t unix_set_option(io_channel channel, const char *option,
83 const char *arg);
84
85static void reuse_cache(io_channel channel, struct unix_private_data *data,
86 struct unix_cache *cache, unsigned long block);
87
88/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
89 * does not know buffered block devices - everything is raw. */
90#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
91#define NEED_BOUNCE_BUFFER
92#else
93#undef NEED_BOUNCE_BUFFER
94#endif
95
96static struct struct_io_manager struct_unix_manager = {
97 EXT2_ET_MAGIC_IO_MANAGER,
98 "Unix I/O Manager",
99 unix_open,
100 unix_close,
101 unix_set_blksize,
102 unix_read_blk,
103 unix_write_blk,
104 unix_flush,
105#ifdef NEED_BOUNCE_BUFFER
106 0,
107#else
108 unix_write_byte,
109#endif
110 unix_set_option
111};
112
113io_manager unix_io_manager = &struct_unix_manager;
114
115/*
116 * Here are the raw I/O functions
117 */
118#ifndef NEED_BOUNCE_BUFFER
119static errcode_t raw_read_blk(io_channel channel,
120 struct unix_private_data *data,
121 unsigned long block,
122 int count, void *buf)
123{
124 errcode_t retval;
125 ssize_t size;
126 ext2_loff_t location;
127 int actual = 0;
128
129 size = (count < 0) ? -count : count * channel->block_size;
130 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
131 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
132 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
133 goto error_out;
134 }
135 actual = read(data->dev, buf, size);
136 if (actual != size) {
137 if (actual < 0)
138 actual = 0;
139 retval = EXT2_ET_SHORT_READ;
140 goto error_out;
141 }
142 return 0;
143
144error_out:
145 memset((char *) buf+actual, 0, size-actual);
146 if (channel->read_error)
147 retval = (channel->read_error)(channel, block, count, buf,
148 size, actual, retval);
149 return retval;
150}
151#else /* NEED_BOUNCE_BUFFER */
152/*
153 * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
154 */
155static errcode_t raw_read_blk(io_channel channel,
156 struct unix_private_data *data,
157 unsigned long block,
158 int count, void *buf)
159{
160 errcode_t retval;
161 size_t size, alignsize, fragment;
162 ext2_loff_t location;
163 int total = 0, actual;
164#define BLOCKALIGN 512
165 char sector[BLOCKALIGN];
166
167 size = (count < 0) ? -count : count * channel->block_size;
168 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
169#ifdef DEBUG
170 printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
171 count, size, block, channel->block_size, location);
172#endif
173 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
174 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
175 goto error_out;
176 }
177 fragment = size % BLOCKALIGN;
178 alignsize = size - fragment;
179 if (alignsize) {
180 actual = read(data->dev, buf, alignsize);
181 if (actual != alignsize)
182 goto short_read;
183 }
184 if (fragment) {
185 actual = read(data->dev, sector, BLOCKALIGN);
186 if (actual != BLOCKALIGN)
187 goto short_read;
188 memcpy(buf+alignsize, sector, fragment);
189 }
190 return 0;
191
192short_read:
193 if (actual>0)
194 total += actual;
195 retval = EXT2_ET_SHORT_READ;
196
197error_out:
198 memset((char *) buf+total, 0, size-actual);
199 if (channel->read_error)
200 retval = (channel->read_error)(channel, block, count, buf,
201 size, actual, retval);
202 return retval;
203}
204#endif
205
206static errcode_t raw_write_blk(io_channel channel,
207 struct unix_private_data *data,
208 unsigned long block,
209 int count, const void *buf)
210{
211 ssize_t size;
212 ext2_loff_t location;
213 int actual = 0;
214 errcode_t retval;
215
216 if (count == 1)
217 size = channel->block_size;
218 else {
219 if (count < 0)
220 size = -count;
221 else
222 size = count * channel->block_size;
223 }
224
225 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
226 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
227 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
228 goto error_out;
229 }
230
231 actual = write(data->dev, buf, size);
232 if (actual != size) {
233 retval = EXT2_ET_SHORT_WRITE;
234 goto error_out;
235 }
236 return 0;
237
238error_out:
239 if (channel->write_error)
240 retval = (channel->write_error)(channel, block, count, buf,
241 size, actual, retval);
242 return retval;
243}
244
245
246/*
247 * Here we implement the cache functions
248 */
249
250/* Allocate the cache buffers */
251static errcode_t alloc_cache(io_channel channel,
252 struct unix_private_data *data)
253{
254 errcode_t retval;
255 struct unix_cache *cache;
256 int i;
257
258 data->access_time = 0;
259 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
260 cache->block = 0;
261 cache->access_time = 0;
262 cache->dirty = 0;
263 cache->in_use = 0;
264 if ((retval = ext2fs_get_mem(channel->block_size,
265 &cache->buf)))
266 return retval;
267 }
268 return 0;
269}
270
271/* Free the cache buffers */
272static void free_cache(struct unix_private_data *data)
273{
274 struct unix_cache *cache;
275 int i;
276
277 data->access_time = 0;
278 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
279 cache->block = 0;
280 cache->access_time = 0;
281 cache->dirty = 0;
282 cache->in_use = 0;
283 if (cache->buf)
284 ext2fs_free_mem(&cache->buf);
285 cache->buf = 0;
286 }
287}
288
289#ifndef NO_IO_CACHE
290/*
291 * Try to find a block in the cache. If the block is not found, and
292 * eldest is a non-zero pointer, then fill in eldest with the cache
293 * entry to that should be reused.
294 */
295static struct unix_cache *find_cached_block(struct unix_private_data *data,
296 unsigned long block,
297 struct unix_cache **eldest)
298{
299 struct unix_cache *cache, *unused_cache, *oldest_cache;
300 int i;
301
302 unused_cache = oldest_cache = 0;
303 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
304 if (!cache->in_use) {
305 if (!unused_cache)
306 unused_cache = cache;
307 continue;
308 }
309 if (cache->block == block) {
310 cache->access_time = ++data->access_time;
311 return cache;
312 }
313 if (!oldest_cache ||
314 (cache->access_time < oldest_cache->access_time))
315 oldest_cache = cache;
316 }
317 if (eldest)
318 *eldest = (unused_cache) ? unused_cache : oldest_cache;
319 return 0;
320}
321
322/*
323 * Reuse a particular cache entry for another block.
324 */
325static void reuse_cache(io_channel channel, struct unix_private_data *data,
326 struct unix_cache *cache, unsigned long block)
327{
328 if (cache->dirty && cache->in_use)
329 raw_write_blk(channel, data, cache->block, 1, cache->buf);
330
331 cache->in_use = 1;
332 cache->dirty = 0;
333 cache->block = block;
334 cache->access_time = ++data->access_time;
335}
336
337/*
338 * Flush all of the blocks in the cache
339 */
340static errcode_t flush_cached_blocks(io_channel channel,
341 struct unix_private_data *data,
342 int invalidate)
343
344{
345 struct unix_cache *cache;
346 errcode_t retval, retval2;
347 int i;
348
349 retval2 = 0;
350 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
351 if (!cache->in_use)
352 continue;
353
354 if (invalidate)
355 cache->in_use = 0;
356
357 if (!cache->dirty)
358 continue;
359
360 retval = raw_write_blk(channel, data,
361 cache->block, 1, cache->buf);
362 if (retval)
363 retval2 = retval;
364 else
365 cache->dirty = 0;
366 }
367 return retval2;
368}
369#endif /* NO_IO_CACHE */
370
371static errcode_t unix_open(const char *name, int flags, io_channel *channel)
372{
373 io_channel io = NULL;
374 struct unix_private_data *data = NULL;
375 errcode_t retval;
376 int open_flags;
377 struct stat st;
378#ifdef __linux__
379 struct utsname ut;
380#endif
381
382 if (name == 0)
383 return EXT2_ET_BAD_DEVICE_NAME;
384 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
385 if (retval)
386 return retval;
387 memset(io, 0, sizeof(struct struct_io_channel));
388 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
389 retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
390 if (retval)
391 goto cleanup;
392
393 io->manager = unix_io_manager;
394 retval = ext2fs_get_mem(strlen(name)+1, &io->name);
395 if (retval)
396 goto cleanup;
397
398 strcpy(io->name, name);
399 io->private_data = data;
400 io->block_size = 1024;
401 io->read_error = 0;
402 io->write_error = 0;
403 io->refcount = 1;
404
405 memset(data, 0, sizeof(struct unix_private_data));
406 data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
407
408 if ((retval = alloc_cache(io, data)))
409 goto cleanup;
410
411 open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
412#ifdef CONFIG_LFS
413 data->dev = open64(io->name, open_flags);
414#else
415 data->dev = open(io->name, open_flags);
416#endif
417 if (data->dev < 0) {
418 retval = errno;
419 goto cleanup;
420 }
421
422#ifdef __linux__
423#undef RLIM_INFINITY
424#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
425#define RLIM_INFINITY ((unsigned long)(~0UL>>1))
426#else
427#define RLIM_INFINITY (~0UL)
428#endif
429 /*
430 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
431 * block devices are wrongly getting hit by the filesize
432 * limit. This workaround isn't perfect, since it won't work
433 * if glibc wasn't built against 2.2 header files. (Sigh.)
434 *
435 */
436 if ((flags & IO_FLAG_RW) &&
437 (uname(&ut) == 0) &&
438 ((ut.release[0] == '2') && (ut.release[1] == '.') &&
439 (ut.release[2] == '4') && (ut.release[3] == '.') &&
440 (ut.release[4] == '1') && (ut.release[5] >= '0') &&
441 (ut.release[5] < '8')) &&
442 (fstat(data->dev, &st) == 0) &&
443 (S_ISBLK(st.st_mode))) {
444 struct rlimit rlim;
445
446 rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
447 setrlimit(RLIMIT_FSIZE, &rlim);
448 getrlimit(RLIMIT_FSIZE, &rlim);
449 if (((unsigned long) rlim.rlim_cur) <
450 ((unsigned long) rlim.rlim_max)) {
451 rlim.rlim_cur = rlim.rlim_max;
452 setrlimit(RLIMIT_FSIZE, &rlim);
453 }
454 }
455#endif
456 *channel = io;
457 return 0;
458
459cleanup:
460 if (data) {
461 free_cache(data);
462 ext2fs_free_mem(&data);
463 }
464 if (io)
465 ext2fs_free_mem(&io);
466 return retval;
467}
468
469static errcode_t unix_close(io_channel channel)
470{
471 struct unix_private_data *data;
472 errcode_t retval = 0;
473
474 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
475 data = (struct unix_private_data *) channel->private_data;
476 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
477
478 if (--channel->refcount > 0)
479 return 0;
480
481#ifndef NO_IO_CACHE
482 retval = flush_cached_blocks(channel, data, 0);
483#endif
484
485 if (close(data->dev) < 0)
486 retval = errno;
487 free_cache(data);
488
489 ext2fs_free_mem(&channel->private_data);
490 if (channel->name)
491 ext2fs_free_mem(&channel->name);
492 ext2fs_free_mem(&channel);
493 return retval;
494}
495
496static errcode_t unix_set_blksize(io_channel channel, int blksize)
497{
498 struct unix_private_data *data;
499 errcode_t retval;
500
501 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
502 data = (struct unix_private_data *) channel->private_data;
503 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
504
505 if (channel->block_size != blksize) {
506#ifndef NO_IO_CACHE
507 if ((retval = flush_cached_blocks(channel, data, 0)))
508 return retval;
509#endif
510
511 channel->block_size = blksize;
512 free_cache(data);
513 if ((retval = alloc_cache(channel, data)))
514 return retval;
515 }
516 return 0;
517}
518
519
520static errcode_t unix_read_blk(io_channel channel, unsigned long block,
521 int count, void *buf)
522{
523 struct unix_private_data *data;
524 struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
525 errcode_t retval;
526 char *cp;
527 int i, j;
528
529 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
530 data = (struct unix_private_data *) channel->private_data;
531 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
532
533#ifdef NO_IO_CACHE
534 return raw_read_blk(channel, data, block, count, buf);
535#else
536 /*
537 * If we're doing an odd-sized read or a very large read,
538 * flush out the cache and then do a direct read.
539 */
540 if (count < 0 || count > WRITE_DIRECT_SIZE) {
541 if ((retval = flush_cached_blocks(channel, data, 0)))
542 return retval;
543 return raw_read_blk(channel, data, block, count, buf);
544 }
545
546 cp = buf;
547 while (count > 0) {
548 /* If it's in the cache, use it! */
549 if ((cache = find_cached_block(data, block, &reuse[0]))) {
550#ifdef DEBUG
551 printf("Using cached block %d\n", block);
552#endif
553 memcpy(cp, cache->buf, channel->block_size);
554 count--;
555 block++;
556 cp += channel->block_size;
557 continue;
558 }
559 /*
560 * Find the number of uncached blocks so we can do a
561 * single read request
562 */
563 for (i=1; i < count; i++)
564 if (find_cached_block(data, block+i, &reuse[i]))
565 break;
566#ifdef DEBUG
567 printf("Reading %d blocks starting at %d\n", i, block);
568#endif
569 if ((retval = raw_read_blk(channel, data, block, i, cp)))
570 return retval;
571
572 /* Save the results in the cache */
573 for (j=0; j < i; j++) {
574 count--;
575 cache = reuse[j];
576 reuse_cache(channel, data, cache, block++);
577 memcpy(cache->buf, cp, channel->block_size);
578 cp += channel->block_size;
579 }
580 }
581 return 0;
582#endif /* NO_IO_CACHE */
583}
584
585static errcode_t unix_write_blk(io_channel channel, unsigned long block,
586 int count, const void *buf)
587{
588 struct unix_private_data *data;
589 struct unix_cache *cache, *reuse;
590 errcode_t retval = 0;
591 const char *cp;
592 int writethrough;
593
594 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
595 data = (struct unix_private_data *) channel->private_data;
596 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
597
598#ifdef NO_IO_CACHE
599 return raw_write_blk(channel, data, block, count, buf);
600#else
601 /*
602 * If we're doing an odd-sized write or a very large write,
603 * flush out the cache completely and then do a direct write.
604 */
605 if (count < 0 || count > WRITE_DIRECT_SIZE) {
606 if ((retval = flush_cached_blocks(channel, data, 1)))
607 return retval;
608 return raw_write_blk(channel, data, block, count, buf);
609 }
610
611 /*
612 * For a moderate-sized multi-block write, first force a write
613 * if we're in write-through cache mode, and then fill the
614 * cache with the blocks.
615 */
616 writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
617 if (writethrough)
618 retval = raw_write_blk(channel, data, block, count, buf);
619
620 cp = buf;
621 while (count > 0) {
622 cache = find_cached_block(data, block, &reuse);
623 if (!cache) {
624 cache = reuse;
625 reuse_cache(channel, data, cache, block);
626 }
627 memcpy(cache->buf, cp, channel->block_size);
628 cache->dirty = !writethrough;
629 count--;
630 block++;
631 cp += channel->block_size;
632 }
633 return retval;
634#endif /* NO_IO_CACHE */
635}
636
637static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
638 int size, const void *buf)
639{
640 struct unix_private_data *data;
641 errcode_t retval = 0;
642 ssize_t actual;
643
644 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
645 data = (struct unix_private_data *) channel->private_data;
646 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
647
648#ifndef NO_IO_CACHE
649 /*
650 * Flush out the cache completely
651 */
652 if ((retval = flush_cached_blocks(channel, data, 1)))
653 return retval;
654#endif
655
656 if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
657 return errno;
658
659 actual = write(data->dev, buf, size);
660 if (actual != size)
661 return EXT2_ET_SHORT_WRITE;
662
663 return 0;
664}
665
666/*
667 * Flush data buffers to disk.
668 */
669static errcode_t unix_flush(io_channel channel)
670{
671 struct unix_private_data *data;
672 errcode_t retval = 0;
673
674 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
675 data = (struct unix_private_data *) channel->private_data;
676 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
677
678#ifndef NO_IO_CACHE
679 retval = flush_cached_blocks(channel, data, 0);
680#endif
681 fsync(data->dev);
682 return retval;
683}
684
685static errcode_t unix_set_option(io_channel channel, const char *option,
686 const char *arg)
687{
688 struct unix_private_data *data;
689 unsigned long tmp;
690 char *end;
691
692 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
693 data = (struct unix_private_data *) channel->private_data;
694 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
695
696 if (!strcmp(option, "offset")) {
697 if (!arg)
698 return EXT2_ET_INVALID_ARGUMENT;
699
700 tmp = strtoul(arg, &end, 0);
701 if (*end)
702 return EXT2_ET_INVALID_ARGUMENT;
703 data->offset = tmp;
704 return 0;
705 }
706 return EXT2_ET_INVALID_ARGUMENT;
707}
diff --git a/e2fsprogs/ext2fs/unlink.c b/e2fsprogs/ext2fs/unlink.c
new file mode 100644
index 000000000..e7b2182d2
--- /dev/null
+++ b/e2fsprogs/ext2fs/unlink.c
@@ -0,0 +1,99 @@
1/*
2 * unlink.c --- delete links in a ext2fs directory
3 *
4 * Copyright (C) 1993, 1994, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21struct link_struct {
22 const char *name;
23 int namelen;
24 ext2_ino_t inode;
25 int flags;
26 struct ext2_dir_entry *prev;
27 int done;
28};
29
30#ifdef __TURBOC__
31 #pragma argsused
32#endif
33static int unlink_proc(struct ext2_dir_entry *dirent,
34 int offset EXT2FS_ATTR((unused)),
35 int blocksize EXT2FS_ATTR((unused)),
36 char *buf EXT2FS_ATTR((unused)),
37 void *priv_data)
38{
39 struct link_struct *ls = (struct link_struct *) priv_data;
40 struct ext2_dir_entry *prev;
41
42 prev = ls->prev;
43 ls->prev = dirent;
44
45 if (ls->name) {
46 if ((dirent->name_len & 0xFF) != ls->namelen)
47 return 0;
48 if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF))
49 return 0;
50 }
51 if (ls->inode) {
52 if (dirent->inode != ls->inode)
53 return 0;
54 } else {
55 if (!dirent->inode)
56 return 0;
57 }
58
59 if (prev)
60 prev->rec_len += dirent->rec_len;
61 else
62 dirent->inode = 0;
63 ls->done++;
64 return DIRENT_ABORT|DIRENT_CHANGED;
65}
66
67#ifdef __TURBOC__
68 #pragma argsused
69#endif
70errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir,
71 const char *name, ext2_ino_t ino,
72 int flags EXT2FS_ATTR((unused)))
73{
74 errcode_t retval;
75 struct link_struct ls;
76
77 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
78
79 if (!name && !ino)
80 return EXT2_ET_INVALID_ARGUMENT;
81
82 if (!(fs->flags & EXT2_FLAG_RW))
83 return EXT2_ET_RO_FILSYS;
84
85 ls.name = name;
86 ls.namelen = name ? strlen(name) : 0;
87 ls.inode = ino;
88 ls.flags = 0;
89 ls.done = 0;
90 ls.prev = 0;
91
92 retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
93 0, unlink_proc, &ls);
94 if (retval)
95 return retval;
96
97 return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
98}
99
diff --git a/e2fsprogs/ext2fs/valid_blk.c b/e2fsprogs/ext2fs/valid_blk.c
new file mode 100644
index 000000000..29ff27a7c
--- /dev/null
+++ b/e2fsprogs/ext2fs/valid_blk.c
@@ -0,0 +1,56 @@
1/*
2 * valid_blk.c --- does the inode have valid blocks?
3 *
4 * Copyright 1997 by Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
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
23/*
24 * This function returns 1 if the inode's block entries actually
25 * contain block entries.
26 */
27int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
28{
29 /*
30 * Only directories, regular files, and some symbolic links
31 * have valid block entries.
32 */
33 if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) &&
34 !LINUX_S_ISLNK(inode->i_mode))
35 return 0;
36
37 /*
38 * If the symbolic link is a "fast symlink", then the symlink
39 * target is stored in the block entries.
40 */
41 if (LINUX_S_ISLNK (inode->i_mode)) {
42 if (inode->i_file_acl == 0) {
43 /* With no EA block, we can rely on i_blocks */
44 if (inode->i_blocks == 0)
45 return 0;
46 } else {
47 /* With an EA block, life gets more tricky */
48 if (inode->i_size >= EXT2_N_BLOCKS*4)
49 return 1; /* definitely using i_block[] */
50 if (inode->i_size > 4 && inode->i_block[1] == 0)
51 return 1; /* definitely using i_block[] */
52 return 0; /* Probably a fast symlink */
53 }
54 }
55 return 1;
56}
diff --git a/e2fsprogs/ext2fs/version.c b/e2fsprogs/ext2fs/version.c
new file mode 100644
index 000000000..f7026af32
--- /dev/null
+++ b/e2fsprogs/ext2fs/version.c
@@ -0,0 +1,52 @@
1/*
2 * version.c --- Return the version of the ext2 library
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#if HAVE_UNISTD_H
13#include <unistd.h>
14#endif
15#include <string.h>
16#include <stdio.h>
17#include <ctype.h>
18
19#include "ext2_fs.h"
20#include "ext2fs.h"
21
22//#include "../../version.h"
23
24static const char *lib_version = E2FSPROGS_VERSION;
25static const char *lib_date = E2FSPROGS_DATE;
26
27int ext2fs_parse_version_string(const char *ver_string)
28{
29 const char *cp;
30 int version = 0;
31
32 for (cp = ver_string; *cp; cp++) {
33 if (*cp == '.')
34 continue;
35 if (!isdigit(*cp))
36 break;
37 version = (version * 10) + (*cp - '0');
38 }
39 return version;
40}
41
42
43int ext2fs_get_library_version(const char **ver_string,
44 const char **date_string)
45{
46 if (ver_string)
47 *ver_string = lib_version;
48 if (date_string)
49 *date_string = lib_date;
50
51 return ext2fs_parse_version_string(lib_version);
52}
diff --git a/e2fsprogs/ext2fs/write_bb_file.c b/e2fsprogs/ext2fs/write_bb_file.c
new file mode 100644
index 000000000..269b576b2
--- /dev/null
+++ b/e2fsprogs/ext2fs/write_bb_file.c
@@ -0,0 +1,34 @@
1/*
2 * write_bb_file.c --- write a list of bad blocks to a FILE *
3 *
4 * Copyright (C) 1994, 1995 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13
14#include "ext2_fs.h"
15#include "ext2fs.h"
16
17errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
18 unsigned int flags EXT2FS_ATTR((unused)),
19 FILE *f)
20{
21 badblocks_iterate bb_iter;
22 blk_t blk;
23 errcode_t retval;
24
25 retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
26 if (retval)
27 return retval;
28
29 while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
30 fprintf(f, "%d\n", blk);
31 }
32 ext2fs_badblocks_list_iterate_end(bb_iter);
33 return 0;
34}