diff options
author | Mike Frysinger <vapier@gentoo.org> | 2005-05-09 22:10:42 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2005-05-09 22:10:42 +0000 |
commit | 1fd98e039d146dcff02a5350f509cabca65fd29c (patch) | |
tree | 1564707d41a6271bb44cf3fa5b88b9cc70fedd35 | |
parent | b32011943a0764872ca1ea17f13b53176ace8e69 (diff) | |
download | busybox-w32-1fd98e039d146dcff02a5350f509cabca65fd29c.tar.gz busybox-w32-1fd98e039d146dcff02a5350f509cabca65fd29c.tar.bz2 busybox-w32-1fd98e039d146dcff02a5350f509cabca65fd29c.zip |
import ext2fs lib to prep for new e2fsprogs
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 | */ | ||
35 | errcode_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 | */ | ||
76 | errcode_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 | */ | ||
106 | errcode_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 | |||
139 | fail: | ||
140 | if (buf) | ||
141 | ext2fs_free_mem(&buf); | ||
142 | return retval; | ||
143 | } | ||
144 | |||
145 | errcode_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 | |||
30 | int 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 | |||
18 | void 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 | |||
35 | void 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 | |||
40 | void 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 | |||
30 | errcode_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 | |||
105 | errcode_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 | */ | ||
32 | static 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 | */ | ||
62 | errcode_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 | */ | ||
70 | errcode_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 | */ | ||
79 | errcode_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 | |||
90 | errcode_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 | */ | ||
107 | errcode_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 | |||
153 | errcode_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 | */ | ||
162 | int 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 | */ | ||
197 | int 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 | |||
205 | int 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 | */ | ||
214 | int 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 | |||
231 | void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk) | ||
232 | { | ||
233 | ext2fs_u32_list_del(bb, blk); | ||
234 | } | ||
235 | |||
236 | errcode_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 | |||
255 | errcode_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 | |||
263 | int 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 | |||
283 | int 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 | |||
290 | void 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 | |||
299 | void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter) | ||
300 | { | ||
301 | ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter); | ||
302 | } | ||
303 | |||
304 | |||
305 | int 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 | |||
318 | int 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 | |||
324 | int 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 | |||
29 | errcode_t badblocks_list_create(badblocks_list *ret, int size) | ||
30 | { | ||
31 | return ext2fs_badblocks_list_create(ret, size); | ||
32 | } | ||
33 | |||
34 | void badblocks_list_free(badblocks_list bb) | ||
35 | { | ||
36 | ext2fs_badblocks_list_free(bb); | ||
37 | } | ||
38 | |||
39 | errcode_t badblocks_list_add(badblocks_list bb, blk_t blk) | ||
40 | { | ||
41 | return ext2fs_badblocks_list_add(bb, blk); | ||
42 | } | ||
43 | |||
44 | int badblocks_list_test(badblocks_list bb, blk_t blk) | ||
45 | { | ||
46 | return ext2fs_badblocks_list_test(bb, blk); | ||
47 | } | ||
48 | |||
49 | errcode_t badblocks_list_iterate_begin(badblocks_list bb, | ||
50 | badblocks_iterate *ret) | ||
51 | { | ||
52 | return ext2fs_badblocks_list_iterate_begin(bb, ret); | ||
53 | } | ||
54 | |||
55 | int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk) | ||
56 | { | ||
57 | return ext2fs_badblocks_list_iterate(iter, blk); | ||
58 | } | ||
59 | |||
60 | void 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 | |||
33 | struct 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 | |||
44 | static 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); | ||
48 | static 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 | */ | ||
57 | errcode_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 | |||
137 | cleanup: | ||
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 | ||
152 | static 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 | ||
209 | static 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 | |||
30 | static 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 | |||
75 | errcode_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 | |||
84 | errcode_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 | |||
101 | void 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 | |||
111 | errcode_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 | |||
140 | errcode_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 | |||
170 | errcode_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 | |||
183 | errcode_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 | |||
196 | void 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 | |||
205 | void 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 | |||
33 | int 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 | |||
45 | int 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 | |||
57 | int 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 | |||
69 | void 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 | |||
80 | void 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 | |||
17 | extern int ext2fs_set_bit(int nr,void * addr); | ||
18 | extern int ext2fs_clear_bit(int nr, void * addr); | ||
19 | extern int ext2fs_test_bit(int nr, const void * addr); | ||
20 | extern __u16 ext2fs_swab16(__u16 val); | ||
21 | extern __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 */ | ||
48 | extern const char *ext2fs_block_string; | ||
49 | extern const char *ext2fs_inode_string; | ||
50 | extern const char *ext2fs_mark_string; | ||
51 | extern const char *ext2fs_unmark_string; | ||
52 | extern const char *ext2fs_test_string; | ||
53 | extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg, | ||
54 | const char *description); | ||
55 | extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap, | ||
56 | int code, unsigned long arg); | ||
57 | |||
58 | extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block); | ||
59 | extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap, | ||
60 | blk_t block); | ||
61 | extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block); | ||
62 | |||
63 | extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode); | ||
64 | extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||
65 | ext2_ino_t inode); | ||
66 | extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode); | ||
67 | |||
68 | extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap, | ||
69 | blk_t block); | ||
70 | extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap, | ||
71 | blk_t block); | ||
72 | extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap, | ||
73 | blk_t block); | ||
74 | |||
75 | extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||
76 | ext2_ino_t inode); | ||
77 | extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||
78 | ext2_ino_t inode); | ||
79 | extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap, | ||
80 | ext2_ino_t inode); | ||
81 | extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap); | ||
82 | extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap); | ||
83 | extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap); | ||
84 | extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap); | ||
85 | |||
86 | extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||
87 | blk_t block, int num); | ||
88 | extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||
89 | blk_t block, int num); | ||
90 | extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||
91 | blk_t block, int num); | ||
92 | extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||
93 | blk_t block, int num); | ||
94 | extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||
95 | blk_t block, int num); | ||
96 | extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap, | ||
97 | blk_t block, int num); | ||
98 | extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map); | ||
99 | |||
100 | /* These two routines moved to gen_bitmap.c */ | ||
101 | extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap, | ||
102 | __u32 bitno); | ||
103 | extern 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 | */ | ||
151 | struct __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 | |||
21 | struct 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 | |||
39 | static 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 | |||
113 | static 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 | |||
189 | static 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 | |||
266 | errcode_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 | |||
374 | abort_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 | |||
398 | struct 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 | ||
409 | static 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 | |||
419 | errcode_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 | |||
27 | extern 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 | |||
34 | static _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 | |||
97 | static _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 | |||
117 | static _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 | |||
137 | errcode_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); | ||
259 | done: | ||
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 | |||
24 | struct 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 | |||
35 | static 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 | |||
90 | errcode_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 | |||
12 | struct 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 | |||
26 | typedef struct ext2_block_relocation_table *ext2_brel; | ||
27 | |||
28 | struct 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 | |||
76 | errcode_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 | |||
29 | static errcode_t bma_put(ext2_brel brel, blk_t old, | ||
30 | struct ext2_block_relocate_entry *ent); | ||
31 | static errcode_t bma_get(ext2_brel brel, blk_t old, | ||
32 | struct ext2_block_relocate_entry *ent); | ||
33 | static errcode_t bma_start_iter(ext2_brel brel); | ||
34 | static errcode_t bma_next(ext2_brel brel, blk_t *old, | ||
35 | struct ext2_block_relocate_entry *ent); | ||
36 | static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new); | ||
37 | static errcode_t bma_delete(ext2_brel brel, blk_t old); | ||
38 | static errcode_t bma_free(ext2_brel brel); | ||
39 | |||
40 | struct brel_ma { | ||
41 | __u32 magic; | ||
42 | blk_t max_block; | ||
43 | struct ext2_block_relocate_entry *entries; | ||
44 | }; | ||
45 | |||
46 | errcode_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 | |||
98 | errout: | ||
99 | bma_free(brel); | ||
100 | return retval; | ||
101 | } | ||
102 | |||
103 | static 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 | |||
115 | static 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 | |||
129 | static errcode_t bma_start_iter(ext2_brel brel) | ||
130 | { | ||
131 | brel->current = 0; | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static 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 | |||
152 | static 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 | |||
166 | static 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 | |||
179 | static 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 | */ | ||
32 | errcode_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 | |||
22 | static 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 | |||
35 | int 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 | |||
48 | int 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 | */ | ||
128 | static 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 | */ | ||
172 | void 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 | |||
186 | static 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 | |||
206 | errcode_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 | |||
335 | write_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); | ||
351 | errout: | ||
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 | |||
362 | errcode_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 | |||
29 | errcode_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 | |||
51 | errcode_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 | |||
23 | static 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 | */ | ||
30 | errcode_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 | */ | ||
57 | static 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; | ||
101 | cleanup: | ||
102 | if (dblist) | ||
103 | ext2fs_free_mem(&dblist); | ||
104 | return retval; | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * Initialize a directory block list | ||
109 | */ | ||
110 | errcode_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 | */ | ||
131 | errcode_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 | */ | ||
155 | errcode_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 | */ | ||
188 | errcode_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 | |||
206 | void 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 | */ | ||
220 | errcode_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 | |||
241 | static 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 | |||
257 | int 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 | |||
23 | static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info, | ||
24 | void *priv_data); | ||
25 | |||
26 | errcode_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 | |||
65 | static 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 | */ | ||
32 | static 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 | |||
47 | errcode_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 | |||
90 | struct 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 | |||
99 | static 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 | |||
109 | extern 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 | */ | ||
134 | int 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 | } | ||
187 | next: | ||
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 | |||
22 | errcode_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 | |||
66 | errcode_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 | |||
73 | errcode_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 | |||
125 | errcode_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 | |||
33 | static 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 | */ | ||
70 | static 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 */ | ||
119 | static 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 | |||
132 | static 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 | */ | ||
172 | errcode_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 | */ | ||
38 | unsigned long _dio_error; | ||
39 | unsigned long _dio_hw_error; | ||
40 | |||
41 | /* | ||
42 | * Array of all opened partitions | ||
43 | */ | ||
44 | static PARTITION **partitions = NULL; | ||
45 | static unsigned short npart = 0; /* Number of mapped partitions */ | ||
46 | static PARTITION *active = NULL; | ||
47 | |||
48 | /* | ||
49 | * I/O Manager routine prototypes | ||
50 | */ | ||
51 | static errcode_t dos_open(const char *dev, int flags, io_channel *channel); | ||
52 | static errcode_t dos_close(io_channel channel); | ||
53 | static errcode_t dos_set_blksize(io_channel channel, int blksize); | ||
54 | static errcode_t dos_read_blk(io_channel channel, unsigned long block, | ||
55 | int count, void *buf); | ||
56 | static errcode_t dos_write_blk(io_channel channel, unsigned long block, | ||
57 | int count, const void *buf); | ||
58 | static errcode_t dos_flush(io_channel channel); | ||
59 | |||
60 | static 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 | }; | ||
70 | io_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 | */ | ||
86 | static 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 | */ | ||
109 | static 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 | */ | ||
145 | static 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 | */ | ||
176 | static 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 | |||
353 | static 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 | |||
363 | static errcode_t dos_set_blksize(io_channel channel, int blksize) | ||
364 | { | ||
365 | channel->block_size = blksize; | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static 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 | |||
407 | static 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 | ||
450 | static 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 | */ | ||
25 | typedef 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 | */ | ||
36 | typedef 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 | ||
56 | typedef 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 | */ | ||
98 | extern unsigned long _dio_error; | ||
99 | |||
100 | /* | ||
101 | * This one contains last hardware error (if _dio_error == ERR_HARDWARE) | ||
102 | */ | ||
103 | extern 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 | */ | ||
151 | int 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 | |||
22 | errcode_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; | ||
91 | errout: | ||
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 | |||
16 | struct 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 | |||
21 | struct expand_dir_struct { | ||
22 | int done; | ||
23 | int newblocks; | ||
24 | errcode_t err; | ||
25 | }; | ||
26 | |||
27 | static 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 | |||
81 | errcode_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 | ||
106 | extern const struct error_table et_ext2_error_table; | ||
107 | extern void initialize_ext2_error_table(void); | ||
108 | |||
109 | /* For compatibility with Heimdal */ | ||
110 | extern 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 | |||
16 | struct 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 | |||
24 | struct 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 | ||
58 | extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int); | ||
59 | extern int ext2_set_ext_attr(struct inode *, const char *, char *, size_t, int); | ||
60 | extern void ext2_ext_attr_free_inode(struct inode *inode); | ||
61 | extern void ext2_ext_attr_put_super(struct super_block *sb); | ||
62 | extern int ext2_ext_attr_init(void); | ||
63 | extern 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 | */ | ||
116 | struct 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 | |||
124 | struct 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 | */ | ||
138 | struct 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 | */ | ||
162 | struct 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 | |||
176 | struct ext2_dx_entry { | ||
177 | __u32 hash; | ||
178 | __u32 block; | ||
179 | }; | ||
180 | |||
181 | struct 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 | */ | ||
253 | struct 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 | */ | ||
310 | struct 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 | */ | ||
439 | struct 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 | |||
598 | struct 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 | */ | ||
611 | struct 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) | ||
19 | typedef long long ext2_loff_t; | ||
20 | #else | ||
21 | typedef long ext2_loff_t; | ||
22 | #endif | ||
23 | |||
24 | /* llseek.c */ | ||
25 | ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int); | ||
26 | |||
27 | typedef struct struct_io_manager *io_manager; | ||
28 | typedef struct struct_io_channel *io_channel; | ||
29 | |||
30 | #define CHANNEL_FLAGS_WRITETHROUGH 0x01 | ||
31 | |||
32 | struct 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 | |||
58 | struct 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 */ | ||
89 | extern errcode_t io_channel_set_options(io_channel channel, | ||
90 | const char *options); | ||
91 | extern errcode_t io_channel_write_byte(io_channel channel, | ||
92 | unsigned long offset, | ||
93 | int count, const void *data); | ||
94 | |||
95 | /* unix_io.c */ | ||
96 | extern io_manager unix_io_manager; | ||
97 | |||
98 | /* test_io.c */ | ||
99 | extern io_manager test_io_manager, test_io_backing_manager; | ||
100 | extern void (*test_io_cb_read_blk) | ||
101 | (unsigned long block, int count, errcode_t err); | ||
102 | extern void (*test_io_cb_write_blk) | ||
103 | (unsigned long block, int count, errcode_t err); | ||
104 | extern 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 | ||
22 | extern "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 | |||
72 | typedef __u32 ext2_ino_t; | ||
73 | typedef __u32 blk_t; | ||
74 | typedef __u32 dgrp_t; | ||
75 | typedef __u32 ext2_off_t; | ||
76 | typedef __s64 e2_blkcnt_t; | ||
77 | typedef __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 | |||
98 | typedef struct struct_ext2_filsys *ext2_filsys; | ||
99 | |||
100 | struct 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 | |||
115 | typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap; | ||
116 | typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap; | ||
117 | typedef 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 | |||
130 | typedef struct ext2_struct_u32_list *ext2_badblocks_list; | ||
131 | typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate; | ||
132 | |||
133 | typedef struct ext2_struct_u32_list *ext2_u32_list; | ||
134 | typedef struct ext2_struct_u32_iterate *ext2_u32_iterate; | ||
135 | |||
136 | /* old */ | ||
137 | typedef struct ext2_struct_u32_list *badblocks_list; | ||
138 | typedef 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 | */ | ||
145 | struct ext2_db_entry { | ||
146 | ext2_ino_t ino; | ||
147 | blk_t blk; | ||
148 | int blockcnt; | ||
149 | }; | ||
150 | |||
151 | typedef 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 | |||
167 | typedef 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 | |||
204 | struct 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 | */ | ||
332 | typedef 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 | |||
400 | typedef 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 */ | ||
464 | extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode, | ||
465 | ext2fs_inode_bitmap map, ext2_ino_t *ret); | ||
466 | extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, | ||
467 | ext2fs_block_bitmap map, blk_t *ret); | ||
468 | extern 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); | ||
472 | extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, | ||
473 | char *block_buf, blk_t *ret); | ||
474 | |||
475 | /* alloc_sb.c */ | ||
476 | extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, | ||
477 | dgrp_t group, | ||
478 | ext2fs_block_bitmap bmap); | ||
479 | |||
480 | /* alloc_stats.c */ | ||
481 | void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse); | ||
482 | void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino, | ||
483 | int inuse, int isdir); | ||
484 | void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse); | ||
485 | |||
486 | /* alloc_tables.c */ | ||
487 | extern errcode_t ext2fs_allocate_tables(ext2_filsys fs); | ||
488 | extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, | ||
489 | ext2fs_block_bitmap bmap); | ||
490 | |||
491 | /* badblocks.c */ | ||
492 | extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size); | ||
493 | extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk); | ||
494 | extern int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk); | ||
495 | extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk); | ||
496 | extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb, | ||
497 | ext2_u32_iterate *ret); | ||
498 | extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk); | ||
499 | extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter); | ||
500 | extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest); | ||
501 | extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2); | ||
502 | |||
503 | extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, | ||
504 | int size); | ||
505 | extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, | ||
506 | blk_t blk); | ||
507 | extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb, | ||
508 | blk_t blk); | ||
509 | extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk); | ||
510 | extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk); | ||
511 | extern errcode_t | ||
512 | ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb, | ||
513 | ext2_badblocks_iterate *ret); | ||
514 | extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, | ||
515 | blk_t *blk); | ||
516 | extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter); | ||
517 | extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, | ||
518 | ext2_badblocks_list *dest); | ||
519 | extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1, | ||
520 | ext2_badblocks_list bb2); | ||
521 | extern int ext2fs_u32_list_count(ext2_u32_list bb); | ||
522 | |||
523 | /* bb_compat */ | ||
524 | extern errcode_t badblocks_list_create(badblocks_list *ret, int size); | ||
525 | extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk); | ||
526 | extern int badblocks_list_test(badblocks_list bb, blk_t blk); | ||
527 | extern errcode_t badblocks_list_iterate_begin(badblocks_list bb, | ||
528 | badblocks_iterate *ret); | ||
529 | extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk); | ||
530 | extern void badblocks_list_iterate_end(badblocks_iterate iter); | ||
531 | extern void badblocks_list_free(badblocks_list bb); | ||
532 | |||
533 | /* bb_inode.c */ | ||
534 | extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs, | ||
535 | ext2_badblocks_list bb_list); | ||
536 | |||
537 | /* bitmaps.c */ | ||
538 | extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs); | ||
539 | extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs); | ||
540 | extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs); | ||
541 | extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs); | ||
542 | extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start, | ||
543 | __u32 end, | ||
544 | __u32 real_end, | ||
545 | const char *descr, | ||
546 | ext2fs_generic_bitmap *ret); | ||
547 | extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, | ||
548 | const char *descr, | ||
549 | ext2fs_block_bitmap *ret); | ||
550 | extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, | ||
551 | const char *descr, | ||
552 | ext2fs_inode_bitmap *ret); | ||
553 | extern errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap, | ||
554 | ext2_ino_t end, ext2_ino_t *oend); | ||
555 | extern errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap, | ||
556 | blk_t end, blk_t *oend); | ||
557 | extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap); | ||
558 | extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap); | ||
559 | extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs); | ||
560 | extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs); | ||
561 | |||
562 | /* block.c */ | ||
563 | extern 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); | ||
572 | errcode_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 */ | ||
585 | extern 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 */ | ||
593 | extern 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 */ | ||
600 | extern errcode_t ext2fs_check_desc(ext2_filsys fs); | ||
601 | |||
602 | /* closefs.c */ | ||
603 | extern errcode_t ext2fs_close(ext2_filsys fs); | ||
604 | extern errcode_t ext2fs_flush(ext2_filsys fs); | ||
605 | extern int ext2fs_bg_has_super(ext2_filsys fs, int group_block); | ||
606 | extern 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); | ||
612 | extern void ext2fs_update_dynamic_rev(ext2_filsys fs); | ||
613 | |||
614 | /* cmp_bitmaps.c */ | ||
615 | extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1, | ||
616 | ext2fs_block_bitmap bm2); | ||
617 | extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1, | ||
618 | ext2fs_inode_bitmap bm2); | ||
619 | |||
620 | /* dblist.c */ | ||
621 | |||
622 | extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs); | ||
623 | extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist); | ||
624 | extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, | ||
625 | blk_t blk, int blockcnt); | ||
626 | extern void ext2fs_dblist_sort(ext2_dblist dblist, | ||
627 | EXT2_QSORT_TYPE (*sortfunc)(const void *, | ||
628 | const void *)); | ||
629 | extern 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); | ||
633 | extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, | ||
634 | blk_t blk, int blockcnt); | ||
635 | extern errcode_t ext2fs_copy_dblist(ext2_dblist src, | ||
636 | ext2_dblist *dest); | ||
637 | extern int ext2fs_dblist_count(ext2_dblist dblist); | ||
638 | |||
639 | /* dblist_dir.c */ | ||
640 | extern 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 */ | ||
654 | extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, | ||
655 | void *buf); | ||
656 | extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block, | ||
657 | void *buf, int flags); | ||
658 | extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, | ||
659 | void *buf); | ||
660 | extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block, | ||
661 | void *buf, int flags); | ||
662 | |||
663 | /* dirhash.c */ | ||
664 | extern 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 */ | ||
671 | extern 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); | ||
681 | extern 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 */ | ||
695 | extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest); | ||
696 | |||
697 | /* expanddir.c */ | ||
698 | extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir); | ||
699 | |||
700 | /* ext_attr.c */ | ||
701 | extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf); | ||
702 | extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, | ||
703 | void *buf); | ||
704 | extern 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 */ | ||
709 | extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, | ||
710 | struct ext2_inode *inode, | ||
711 | int flags, ext2_file_t *ret); | ||
712 | extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino, | ||
713 | int flags, ext2_file_t *ret); | ||
714 | extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file); | ||
715 | extern errcode_t ext2fs_file_close(ext2_file_t file); | ||
716 | extern errcode_t ext2fs_file_flush(ext2_file_t file); | ||
717 | extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf, | ||
718 | unsigned int wanted, unsigned int *got); | ||
719 | extern errcode_t ext2fs_file_write(ext2_file_t file, const void *buf, | ||
720 | unsigned int nbytes, unsigned int *written); | ||
721 | extern errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset, | ||
722 | int whence, __u64 *ret_pos); | ||
723 | extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, | ||
724 | int whence, ext2_off_t *ret_pos); | ||
725 | errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size); | ||
726 | extern ext2_off_t ext2fs_file_get_size(ext2_file_t file); | ||
727 | extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size); | ||
728 | |||
729 | /* finddev.c */ | ||
730 | extern char *ext2fs_find_block_device(dev_t device); | ||
731 | |||
732 | /* flushb.c */ | ||
733 | extern errcode_t ext2fs_sync_device(int fd, int flushb); | ||
734 | |||
735 | /* freefs.c */ | ||
736 | extern void ext2fs_free(ext2_filsys fs); | ||
737 | extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap); | ||
738 | extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap); | ||
739 | extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap); | ||
740 | extern void ext2fs_free_dblist(ext2_dblist dblist); | ||
741 | extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb); | ||
742 | extern void ext2fs_u32_list_free(ext2_u32_list bb); | ||
743 | |||
744 | /* getsize.c */ | ||
745 | extern errcode_t ext2fs_get_device_size(const char *file, int blocksize, | ||
746 | blk_t *retblocks); | ||
747 | |||
748 | /* getsectsize.c */ | ||
749 | errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize); | ||
750 | |||
751 | /* imager.c */ | ||
752 | extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags); | ||
753 | extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags); | ||
754 | extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags); | ||
755 | extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags); | ||
756 | extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags); | ||
757 | extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags); | ||
758 | |||
759 | /* ind_block.c */ | ||
760 | errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf); | ||
761 | errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf); | ||
762 | |||
763 | /* initialize.c */ | ||
764 | extern 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 */ | ||
769 | extern void ext2fs_free_icount(ext2_icount_t icount); | ||
770 | extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, | ||
771 | unsigned int size, | ||
772 | ext2_icount_t hint, ext2_icount_t *ret); | ||
773 | extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, | ||
774 | unsigned int size, | ||
775 | ext2_icount_t *ret); | ||
776 | extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, | ||
777 | __u16 *ret); | ||
778 | extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, | ||
779 | __u16 *ret); | ||
780 | extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, | ||
781 | __u16 *ret); | ||
782 | extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, | ||
783 | __u16 count); | ||
784 | extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount); | ||
785 | errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *); | ||
786 | |||
787 | /* inode.c */ | ||
788 | extern errcode_t ext2fs_flush_icache(ext2_filsys fs); | ||
789 | extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, | ||
790 | ext2_ino_t *ino, | ||
791 | struct ext2_inode *inode, | ||
792 | int bufsize); | ||
793 | extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, | ||
794 | ext2_inode_scan *ret_scan); | ||
795 | extern void ext2fs_close_inode_scan(ext2_inode_scan scan); | ||
796 | extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, | ||
797 | struct ext2_inode *inode); | ||
798 | extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, | ||
799 | int group); | ||
800 | extern 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); | ||
807 | extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, | ||
808 | int clear_flags); | ||
809 | extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, | ||
810 | struct ext2_inode * inode, | ||
811 | int bufsize); | ||
812 | extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, | ||
813 | struct ext2_inode * inode); | ||
814 | extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, | ||
815 | struct ext2_inode * inode, | ||
816 | int bufsize); | ||
817 | extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, | ||
818 | struct ext2_inode * inode); | ||
819 | extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, | ||
820 | struct ext2_inode * inode); | ||
821 | extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks); | ||
822 | extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino); | ||
823 | |||
824 | /* inode_io.c */ | ||
825 | extern io_manager inode_io_manager; | ||
826 | extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino, | ||
827 | char **name); | ||
828 | extern 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 */ | ||
833 | extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags); | ||
834 | extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags, | ||
835 | char *mtpt, int mtlen); | ||
836 | |||
837 | /* namei.c */ | ||
838 | extern errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name, | ||
839 | int namelen, char *buf, ext2_ino_t *inode); | ||
840 | extern errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, | ||
841 | const char *name, ext2_ino_t *inode); | ||
842 | errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, | ||
843 | const char *name, ext2_ino_t *inode); | ||
844 | extern 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 */ | ||
848 | int ext2fs_native_flag(void); | ||
849 | |||
850 | /* newdir.c */ | ||
851 | extern 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 */ | ||
855 | extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, | ||
856 | const char *name); | ||
857 | |||
858 | /* mkjournal.c */ | ||
859 | extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, | ||
860 | __u32 size, int flags, | ||
861 | char **ret_jsb); | ||
862 | extern errcode_t ext2fs_add_journal_device(ext2_filsys fs, | ||
863 | ext2_filsys journal_dev); | ||
864 | extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, | ||
865 | int flags); | ||
866 | |||
867 | /* openfs.c */ | ||
868 | extern errcode_t ext2fs_open(const char *name, int flags, int superblock, | ||
869 | unsigned int block_size, io_manager manager, | ||
870 | ext2_filsys *ret_fs); | ||
871 | extern 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); | ||
875 | extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, | ||
876 | dgrp_t i); | ||
877 | errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io); | ||
878 | errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io); | ||
879 | errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io); | ||
880 | |||
881 | /* get_pathname.c */ | ||
882 | extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino, | ||
883 | char **name); | ||
884 | |||
885 | /* link.c */ | ||
886 | errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, | ||
887 | ext2_ino_t ino, int flags); | ||
888 | errcode_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 */ | ||
892 | extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs, | ||
893 | ext2_badblocks_list *bb_list); | ||
894 | |||
895 | /* read_bb_file.c */ | ||
896 | extern 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)); | ||
903 | extern 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 */ | ||
909 | extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs); | ||
910 | |||
911 | /* rs_bitmap.c */ | ||
912 | extern errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, | ||
913 | __u32 new_real_end, | ||
914 | ext2fs_generic_bitmap bmap); | ||
915 | extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end, | ||
916 | ext2fs_inode_bitmap bmap); | ||
917 | extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end, | ||
918 | ext2fs_block_bitmap bmap); | ||
919 | extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, | ||
920 | ext2fs_generic_bitmap *dest); | ||
921 | |||
922 | /* swapfs.c */ | ||
923 | extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, | ||
924 | int has_header); | ||
925 | extern void ext2fs_swap_super(struct ext2_super_block * super); | ||
926 | extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp); | ||
927 | extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t, | ||
928 | struct ext2_inode_large *f, int hostorder, | ||
929 | int bufsize); | ||
930 | extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t, | ||
931 | struct ext2_inode *f, int hostorder); | ||
932 | |||
933 | /* valid_blk.c */ | ||
934 | extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode); | ||
935 | |||
936 | /* version.c */ | ||
937 | extern int ext2fs_parse_version_string(const char *ver_string); | ||
938 | extern int ext2fs_get_library_version(const char **ver_string, | ||
939 | const char **date_string); | ||
940 | |||
941 | /* write_bb_file.c */ | ||
942 | extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list, | ||
943 | unsigned int flags, | ||
944 | FILE *f); | ||
945 | |||
946 | |||
947 | /* inline functions */ | ||
948 | extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr); | ||
949 | extern errcode_t ext2fs_free_mem(void *ptr); | ||
950 | extern errcode_t ext2fs_resize_mem(unsigned long old_size, | ||
951 | unsigned long size, void *ptr); | ||
952 | extern void ext2fs_mark_super_dirty(ext2_filsys fs); | ||
953 | extern void ext2fs_mark_changed(ext2_filsys fs); | ||
954 | extern int ext2fs_test_changed(ext2_filsys fs); | ||
955 | extern void ext2fs_mark_valid(ext2_filsys fs); | ||
956 | extern void ext2fs_unmark_valid(ext2_filsys fs); | ||
957 | extern int ext2fs_test_valid(ext2_filsys fs); | ||
958 | extern void ext2fs_mark_ib_dirty(ext2_filsys fs); | ||
959 | extern void ext2fs_mark_bb_dirty(ext2_filsys fs); | ||
960 | extern int ext2fs_test_ib_dirty(ext2_filsys fs); | ||
961 | extern int ext2fs_test_bb_dirty(ext2_filsys fs); | ||
962 | extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk); | ||
963 | extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino); | ||
964 | extern 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 | */ | ||
17 | struct ext2_struct_u32_list { | ||
18 | int magic; | ||
19 | int num; | ||
20 | int size; | ||
21 | __u32 *list; | ||
22 | int badblocks_flags; | ||
23 | }; | ||
24 | |||
25 | struct 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 | */ | ||
35 | struct 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 | */ | ||
47 | struct 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 | */ | ||
65 | struct 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 | |||
74 | struct ext2_inode_cache_ent { | ||
75 | ext2_ino_t ino; | ||
76 | struct ext2_inode inode; | ||
77 | }; | ||
78 | |||
79 | /* Function prototypes */ | ||
80 | |||
81 | extern 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 | |||
26 | errcode_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 | |||
41 | errcode_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 | */ | ||
69 | errcode_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 | |||
101 | errout: | ||
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 | |||
21 | struct 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 | |||
35 | errcode_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 | |||
75 | fail: | ||
76 | if (file->buf) | ||
77 | ext2fs_free_mem(&file->buf); | ||
78 | ext2fs_free_mem(&file); | ||
79 | return retval; | ||
80 | } | ||
81 | |||
82 | errcode_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 | */ | ||
91 | ext2_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 | */ | ||
102 | errcode_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 | */ | ||
140 | static 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 | ||
165 | static 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 | |||
192 | errcode_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 | |||
208 | errcode_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 | |||
243 | fail: | ||
244 | if (got) | ||
245 | *got = count; | ||
246 | return retval; | ||
247 | } | ||
248 | |||
249 | |||
250 | errcode_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 | |||
290 | fail: | ||
291 | if (written) | ||
292 | *written = count; | ||
293 | return retval; | ||
294 | } | ||
295 | |||
296 | errcode_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 | |||
316 | errcode_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 | */ | ||
333 | errcode_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 | */ | ||
344 | ext2_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 | */ | ||
360 | errcode_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 | |||
37 | struct dir_list { | ||
38 | char *name; | ||
39 | struct dir_list *next; | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * This function adds an entry to the directory list | ||
44 | */ | ||
45 | static 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 | */ | ||
65 | static 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 | |||
77 | static 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 | } | ||
115 | success: | ||
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 | */ | ||
125 | char *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 | ||
165 | int 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 | */ | ||
52 | errcode_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 | |||
20 | static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache); | ||
21 | |||
22 | void 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 | |||
61 | void 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 | |||
78 | void 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 | |||
87 | void 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 | */ | ||
99 | static 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 | */ | ||
114 | void 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 | |||
125 | void 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 | */ | ||
134 | void 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 | |||
30 | int 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 | |||
40 | int 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 | |||
30 | struct 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 | ||
40 | static 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 | |||
68 | static 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 | |||
134 | cleanup: | ||
135 | if (gp.name) | ||
136 | ext2fs_free_mem(&gp.name); | ||
137 | return retval; | ||
138 | } | ||
139 | |||
140 | errcode_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 | */ | ||
36 | errcode_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 | |||
65 | errcode_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 | |||
120 | static 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 | */ | ||
134 | errcode_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 | ||
271 | int 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 | |||
40 | struct ext2_icount_el { | ||
41 | ext2_ino_t ino; | ||
42 | __u16 count; | ||
43 | }; | ||
44 | |||
45 | struct 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 | |||
56 | void 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 | |||
71 | errcode_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 | |||
146 | errout: | ||
147 | ext2fs_free_icount(icount); | ||
148 | return(retval); | ||
149 | } | ||
150 | |||
151 | errcode_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 | */ | ||
162 | static 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 | */ | ||
209 | static 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 | |||
274 | errcode_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 | |||
297 | errcode_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 | |||
324 | errcode_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 | |||
389 | errcode_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 | |||
432 | errcode_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 | |||
477 | ext2_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 | ||
37 | typedef int ssize_t; | ||
38 | #endif | ||
39 | |||
40 | /* | ||
41 | * This function returns 1 if the specified block is all zeros | ||
42 | */ | ||
43 | static 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 | |||
61 | errcode_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 | |||
124 | errout: | ||
125 | free(buf); | ||
126 | return retval; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Read in the inode table and stuff it into place | ||
131 | */ | ||
132 | errcode_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 | |||
175 | errout: | ||
176 | free(buf); | ||
177 | return retval; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Write out superblock and group descriptors | ||
182 | */ | ||
183 | errcode_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 | |||
225 | errout: | ||
226 | free(buf); | ||
227 | return retval; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Read the superblock and group descriptors and overwrite them. | ||
232 | */ | ||
233 | errcode_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 | |||
268 | errout: | ||
269 | free(buf); | ||
270 | return retval; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Write the block/inode bitmaps. | ||
275 | */ | ||
276 | errcode_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; | ||
333 | errout: | ||
334 | return (retval); | ||
335 | } | ||
336 | |||
337 | |||
338 | /* | ||
339 | * Read the block/inode bitmaps. | ||
340 | */ | ||
341 | errcode_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; | ||
383 | errout: | ||
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 | |||
22 | errcode_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 | |||
47 | errcode_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 | */ | ||
66 | static 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 | |||
92 | errcode_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 | |||
203 | retry: | ||
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; | ||
384 | cleanup: | ||
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 | |||
31 | struct 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 | */ | ||
59 | errcode_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 | |||
73 | static 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 | |||
105 | errcode_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 | |||
171 | void 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 | |||
184 | void 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 | |||
198 | int 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 | */ | ||
216 | static 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 | |||
233 | errcode_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 | */ | ||
248 | static 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 | */ | ||
306 | static 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 | */ | ||
367 | static 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 | |||
381 | errcode_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 | |||
485 | errcode_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 | */ | ||
495 | errcode_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 | |||
594 | errcode_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 | |||
601 | errcode_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; | ||
706 | errout: | ||
707 | if (w_inode && w_inode != &temp_inode) | ||
708 | free(w_inode); | ||
709 | return retval; | ||
710 | } | ||
711 | |||
712 | errcode_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 | */ | ||
723 | errcode_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 | |||
749 | errcode_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 | |||
772 | errcode_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 | |||
33 | struct 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 | |||
46 | static struct inode_private_data *top_intern; | ||
47 | static int ino_unique = 0; | ||
48 | |||
49 | static errcode_t inode_open(const char *name, int flags, io_channel *channel); | ||
50 | static errcode_t inode_close(io_channel channel); | ||
51 | static errcode_t inode_set_blksize(io_channel channel, int blksize); | ||
52 | static errcode_t inode_read_blk(io_channel channel, unsigned long block, | ||
53 | int count, void *data); | ||
54 | static errcode_t inode_write_blk(io_channel channel, unsigned long block, | ||
55 | int count, const void *data); | ||
56 | static errcode_t inode_flush(io_channel channel); | ||
57 | static errcode_t inode_write_byte(io_channel channel, unsigned long offset, | ||
58 | int size, const void *data); | ||
59 | |||
60 | static 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 | |||
72 | io_manager inode_io_manager = &struct_inode_manager; | ||
73 | |||
74 | errcode_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 | |||
100 | errcode_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 | |||
107 | static 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 | |||
157 | cleanup: | ||
158 | if (data) { | ||
159 | ext2fs_free_mem(&data); | ||
160 | } | ||
161 | if (io) | ||
162 | ext2fs_free_mem(&io); | ||
163 | return retval; | ||
164 | } | ||
165 | |||
166 | static 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 | |||
187 | static 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 | |||
200 | static 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 | |||
220 | static 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 | |||
240 | static 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 | */ | ||
260 | static 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 | |||
22 | errcode_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 | |||
59 | errcode_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 | |||
12 | struct ext2_inode_reference { | ||
13 | blk_t block; | ||
14 | __u16 offset; | ||
15 | }; | ||
16 | |||
17 | struct ext2_inode_relocate_entry { | ||
18 | ext2_ino_t new; | ||
19 | ext2_ino_t orig; | ||
20 | __u16 flags; | ||
21 | __u16 max_refs; | ||
22 | }; | ||
23 | |||
24 | typedef struct ext2_inode_relocation_table *ext2_irel; | ||
25 | |||
26 | struct 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 | |||
100 | errcode_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 | |||
26 | static errcode_t ima_put(ext2_irel irel, ext2_ino_t old, | ||
27 | struct ext2_inode_relocate_entry *ent); | ||
28 | static errcode_t ima_get(ext2_irel irel, ext2_ino_t old, | ||
29 | struct ext2_inode_relocate_entry *ent); | ||
30 | static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old, | ||
31 | struct ext2_inode_relocate_entry *ent); | ||
32 | static errcode_t ima_start_iter(ext2_irel irel); | ||
33 | static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old, | ||
34 | struct ext2_inode_relocate_entry *ent); | ||
35 | static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino, | ||
36 | struct ext2_inode_reference *ref); | ||
37 | static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino); | ||
38 | static errcode_t ima_next_ref(ext2_irel irel, struct ext2_inode_reference *ref); | ||
39 | static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new); | ||
40 | static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old); | ||
41 | static 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 | */ | ||
47 | struct inode_reference_entry { | ||
48 | __u16 num; | ||
49 | struct ext2_inode_reference *refs; | ||
50 | }; | ||
51 | |||
52 | struct 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 | |||
62 | errcode_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 | |||
131 | errout: | ||
132 | ima_free(irel); | ||
133 | return retval; | ||
134 | } | ||
135 | |||
136 | static 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 | |||
176 | static 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 | |||
190 | static 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 | |||
207 | static errcode_t ima_start_iter(ext2_irel irel) | ||
208 | { | ||
209 | irel->current = 0; | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static 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 | |||
230 | static 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 | |||
266 | static 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 | |||
280 | static 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 | |||
301 | static 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 | |||
324 | static 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 | |||
344 | static 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 | */ | ||
43 | static 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, "/")) { | ||
147 | is_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; | ||
159 | errout: | ||
160 | endmntent (f); | ||
161 | return retval; | ||
162 | } | ||
163 | |||
164 | static 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 | |||
196 | static 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 | */ | ||
236 | static 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 | ||
289 | errcode_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 | */ | ||
317 | errcode_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 | ||
323 | int 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 | |||
21 | typedef unsigned int tid_t; | ||
22 | typedef struct journal_s journal_t; | ||
23 | |||
24 | struct buffer_head; | ||
25 | struct inode; | ||
26 | |||
27 | struct 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 | */ | ||
23 | typedef 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 | */ | ||
34 | typedef 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 | */ | ||
50 | typedef 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 | |||
4 | typedef 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 | ||
47 | extern 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 | |||
68 | extern 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__ | ||
77 | typedef struct handle_s handle_t; /* Atomic operation type */ | ||
78 | typedef 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 | */ | ||
104 | typedef 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 | */ | ||
115 | typedef 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 | */ | ||
125 | typedef 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 | */ | ||
142 | typedef 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) \ | ||
212 | do { \ | ||
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) | ||
222 | void 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 | |||
239 | enum 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 */ | ||
249 | static inline int buffer_jbd(struct buffer_head *bh) | ||
250 | { | ||
251 | return __buffer_state(bh, JBD); | ||
252 | } | ||
253 | |||
254 | static inline struct buffer_head *jh2bh(struct journal_head *jh) | ||
255 | { | ||
256 | return jh->b_bh; | ||
257 | } | ||
258 | |||
259 | static inline struct journal_head *bh2jh(struct buffer_head *bh) | ||
260 | { | ||
261 | return bh->b_private; | ||
262 | } | ||
263 | |||
264 | struct 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 | |||
279 | struct 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 | |||
317 | struct 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 | |||
423 | struct 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 */ | ||
568 | extern void __journal_unfile_buffer(struct journal_head *); | ||
569 | extern void journal_unfile_buffer(struct journal_head *); | ||
570 | extern void __journal_refile_buffer(struct journal_head *); | ||
571 | extern void journal_refile_buffer(struct journal_head *); | ||
572 | extern void __journal_file_buffer(struct journal_head *, transaction_t *, int); | ||
573 | extern void __journal_free_buffer(struct journal_head *bh); | ||
574 | extern void journal_file_buffer(struct journal_head *, transaction_t *, int); | ||
575 | extern void __journal_clean_data_list(transaction_t *transaction); | ||
576 | |||
577 | /* Log buffer allocation */ | ||
578 | extern struct journal_head * journal_get_descriptor_buffer(journal_t *); | ||
579 | extern unsigned long journal_next_log_block(journal_t *); | ||
580 | |||
581 | /* Commit management */ | ||
582 | extern void journal_commit_transaction(journal_t *); | ||
583 | |||
584 | /* Checkpoint list management */ | ||
585 | int __journal_clean_checkpoint_list(journal_t *journal); | ||
586 | extern void journal_remove_checkpoint(struct journal_head *); | ||
587 | extern void __journal_remove_checkpoint(struct journal_head *); | ||
588 | extern void journal_insert_checkpoint(struct journal_head *, transaction_t *); | ||
589 | extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *); | ||
590 | |||
591 | /* Buffer IO */ | ||
592 | extern int | ||
593 | journal_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 */ | ||
599 | extern 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 | |||
615 | static inline void lock_journal(journal_t *journal) | ||
616 | { | ||
617 | down(&journal->j_sem); | ||
618 | } | ||
619 | |||
620 | /* This returns zero if we acquired the semaphore */ | ||
621 | static inline int try_lock_journal(journal_t * journal) | ||
622 | { | ||
623 | return down_trylock(&journal->j_sem); | ||
624 | } | ||
625 | |||
626 | static inline void unlock_journal(journal_t * journal) | ||
627 | { | ||
628 | up(&journal->j_sem); | ||
629 | } | ||
630 | |||
631 | |||
632 | static 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 | |||
643 | extern handle_t *journal_start(journal_t *, int nblocks); | ||
644 | extern handle_t *journal_try_start(journal_t *, int nblocks); | ||
645 | extern int journal_restart (handle_t *, int nblocks); | ||
646 | extern int journal_extend (handle_t *, int nblocks); | ||
647 | extern int journal_get_write_access (handle_t *, struct buffer_head *); | ||
648 | extern int journal_get_create_access (handle_t *, struct buffer_head *); | ||
649 | extern int journal_get_undo_access (handle_t *, struct buffer_head *); | ||
650 | extern int journal_dirty_data (handle_t *, | ||
651 | struct buffer_head *, int async); | ||
652 | extern int journal_dirty_metadata (handle_t *, struct buffer_head *); | ||
653 | extern void journal_release_buffer (handle_t *, struct buffer_head *); | ||
654 | extern void journal_forget (handle_t *, struct buffer_head *); | ||
655 | extern void journal_sync_buffer (struct buffer_head *); | ||
656 | extern int journal_flushpage(journal_t *, struct page *, unsigned long); | ||
657 | extern int journal_try_to_free_buffers(journal_t *, struct page *, int); | ||
658 | extern int journal_stop(handle_t *); | ||
659 | extern int journal_flush (journal_t *); | ||
660 | |||
661 | extern void journal_lock_updates (journal_t *); | ||
662 | extern void journal_unlock_updates (journal_t *); | ||
663 | |||
664 | extern journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev, | ||
665 | int start, int len, int bsize); | ||
666 | extern journal_t * journal_init_inode (struct inode *); | ||
667 | extern int journal_update_format (journal_t *); | ||
668 | extern int journal_check_used_features | ||
669 | (journal_t *, unsigned long, unsigned long, unsigned long); | ||
670 | extern int journal_check_available_features | ||
671 | (journal_t *, unsigned long, unsigned long, unsigned long); | ||
672 | extern int journal_set_features | ||
673 | (journal_t *, unsigned long, unsigned long, unsigned long); | ||
674 | extern int journal_create (journal_t *); | ||
675 | extern int journal_load (journal_t *journal); | ||
676 | extern void journal_destroy (journal_t *); | ||
677 | extern int journal_recover (journal_t *journal); | ||
678 | extern int journal_wipe (journal_t *, int); | ||
679 | extern int journal_skip_recovery (journal_t *); | ||
680 | extern void journal_update_superblock (journal_t *, int); | ||
681 | extern void __journal_abort (journal_t *); | ||
682 | extern void journal_abort (journal_t *, int); | ||
683 | extern int journal_errno (journal_t *); | ||
684 | extern void journal_ack_err (journal_t *); | ||
685 | extern int journal_clear_err (journal_t *); | ||
686 | extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr); | ||
687 | extern int journal_force_commit(journal_t *journal); | ||
688 | |||
689 | /* | ||
690 | * journal_head management | ||
691 | */ | ||
692 | extern struct journal_head | ||
693 | *journal_add_journal_head(struct buffer_head *bh); | ||
694 | extern void journal_remove_journal_head(struct buffer_head *bh); | ||
695 | extern void __journal_remove_journal_head(struct buffer_head *bh); | ||
696 | extern void journal_unlock_journal_head(struct journal_head *jh); | ||
697 | |||
698 | /* Primary revoke support */ | ||
699 | #define JOURNAL_REVOKE_DEFAULT_HASH 256 | ||
700 | extern int journal_init_revoke(journal_t *, int); | ||
701 | extern void journal_destroy_revoke_caches(void); | ||
702 | extern int journal_init_revoke_caches(void); | ||
703 | |||
704 | extern void journal_destroy_revoke(journal_t *); | ||
705 | extern int journal_revoke (handle_t *, | ||
706 | unsigned long, struct buffer_head *); | ||
707 | extern int journal_cancel_revoke(handle_t *, struct journal_head *); | ||
708 | extern void journal_write_revoke_records(journal_t *, transaction_t *); | ||
709 | |||
710 | /* Recovery revoke support */ | ||
711 | extern int journal_set_revoke(journal_t *, unsigned long, tid_t); | ||
712 | extern int journal_test_revoke(journal_t *, unsigned long, tid_t); | ||
713 | extern void journal_clear_revoke(journal_t *); | ||
714 | extern 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 | |||
722 | extern int log_space_left (journal_t *); /* Called with journal locked */ | ||
723 | extern tid_t log_start_commit (journal_t *, transaction_t *); | ||
724 | extern void log_wait_commit (journal_t *, tid_t); | ||
725 | extern int log_do_checkpoint (journal_t *, int); | ||
726 | |||
727 | extern void log_wait_for_space(journal_t *, int nblocks); | ||
728 | extern void __journal_drop_transaction(journal_t *, transaction_t *); | ||
729 | extern int cleanup_journal_tail(journal_t *); | ||
730 | |||
731 | /* Reduce journal memory usage by flushing */ | ||
732 | extern void shrink_journal_memory(void); | ||
733 | |||
734 | /* Debugging code only: */ | ||
735 | |||
736 | #define jbd_ENOSYS() \ | ||
737 | do { \ | ||
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 | |||
753 | static inline int is_journal_aborted(journal_t *journal) | ||
754 | { | ||
755 | return journal->j_flags & JFS_ABORT; | ||
756 | } | ||
757 | |||
758 | static 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 | |||
765 | static 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 | |||
780 | extern int journal_recover (journal_t *journal); | ||
781 | extern int journal_skip_recovery (journal_t *); | ||
782 | |||
783 | /* Primary revoke support */ | ||
784 | extern int journal_init_revoke(journal_t *, int); | ||
785 | extern void journal_destroy_revoke_caches(void); | ||
786 | extern int journal_init_revoke_caches(void); | ||
787 | |||
788 | /* Recovery revoke support */ | ||
789 | extern int journal_set_revoke(journal_t *, unsigned long, tid_t); | ||
790 | extern int journal_test_revoke(journal_t *, unsigned long, tid_t); | ||
791 | extern void journal_clear_revoke(journal_t *); | ||
792 | extern void journal_brelse_array(struct buffer_head *b[], int n); | ||
793 | |||
794 | extern 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 | |||
800 | static inline int tid_gt(tid_t x, tid_t y) | ||
801 | { | ||
802 | int difference = (x - y); | ||
803 | return (difference > 0); | ||
804 | } | ||
805 | |||
806 | static inline int tid_geq(tid_t x, tid_t y) | ||
807 | { | ||
808 | int difference = (x - y); | ||
809 | return (difference >= 0); | ||
810 | } | ||
811 | |||
812 | extern 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 | |||
830 | extern int jbd_blocks_per_page(struct inode *inode); | ||
831 | |||
832 | #ifdef __KERNEL__ | ||
833 | |||
834 | extern 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' */ | ||
860 | static 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 */ | ||
866 | static 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 */ | ||
872 | static 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 | |||
14 | struct 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 | */ | ||
37 | static __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 | */ | ||
50 | static __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 | */ | ||
58 | static __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 | */ | ||
70 | static __inline__ void __list_del(struct list_head * prev, | ||
71 | struct list_head * next) | ||
72 | { | ||
73 | next->prev = prev; | ||
74 | prev->next = next; | ||
75 | } | ||
76 | |||
77 | static __inline__ void list_del(struct list_head *entry) | ||
78 | { | ||
79 | __list_del(entry->prev, entry->next); | ||
80 | } | ||
81 | |||
82 | static __inline__ int list_empty(struct list_head *head) | ||
83 | { | ||
84 | return head->next == head; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Splice in "list" into "head" | ||
89 | */ | ||
90 | static __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 | |||
21 | struct 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 | |||
30 | static 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 | ||
97 | errcode_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 | ||
39 | extern 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__ | ||
59 | static int _llseek (unsigned int, unsigned long, | ||
60 | unsigned long, ext2_loff_t *, unsigned int); | ||
61 | |||
62 | static _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 | |||
67 | static 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 | |||
87 | ext2_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 | |||
119 | ext2_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 | |||
21 | struct 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 | ||
31 | static 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 | |||
49 | errcode_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 | |||
33 | errcode_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 | |||
135 | cleanup: | ||
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 | */ | ||
44 | errcode_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 | */ | ||
92 | static 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; | ||
132 | errout: | ||
133 | ext2fs_free_mem(&buf); | ||
134 | return retval; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Helper function for creating the journal using direct I/O routines | ||
139 | */ | ||
140 | struct mkjournal_struct { | ||
141 | int num_blocks; | ||
142 | int newblocks; | ||
143 | char *buf; | ||
144 | errcode_t err; | ||
145 | }; | ||
146 | |||
147 | static 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 | */ | ||
195 | static 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 | |||
245 | errout: | ||
246 | ext2fs_free_mem(&buf); | ||
247 | return retval; | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * This function adds a journal device to a filesystem | ||
252 | */ | ||
253 | errcode_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 | */ | ||
315 | errcode_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; | ||
386 | errout: | ||
387 | close(fd); | ||
388 | return retval; | ||
389 | } | ||
390 | |||
391 | #ifdef DEBUG | ||
392 | main(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 | |||
23 | static 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 | |||
27 | static 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 | */ | ||
75 | static 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 | |||
113 | static 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 | |||
150 | errcode_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 | |||
169 | errcode_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 | |||
188 | errcode_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 | |||
17 | int 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 | */ | ||
28 | errcode_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 | |||
32 | blk_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 | |||
62 | errcode_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 | */ | ||
81 | errcode_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; | ||
289 | cleanup: | ||
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 | */ | ||
299 | errcode_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 | |||
309 | errcode_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 | |||
317 | errcode_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 | |||
29 | struct 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 | ||
40 | static 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 | */ | ||
64 | errcode_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 | */ | ||
32 | errcode_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 | |||
74 | static 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 | */ | ||
89 | errcode_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 | */ | ||
26 | static 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 | */ | ||
61 | errcode_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 | |||
199 | out_dindir: | ||
200 | if (dindir_dirty) { | ||
201 | retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf); | ||
202 | if (!retval) | ||
203 | retval = retval2; | ||
204 | } | ||
205 | out_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 | } | ||
216 | out_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 | |||
29 | errcode_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 | |||
73 | errcode_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 | |||
90 | errcode_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 | ||
44 | static 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 | |||
54 | errcode_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 | |||
96 | errcode_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 | |||
148 | static 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 | |||
247 | cleanup: | ||
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 | |||
261 | errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs) | ||
262 | { | ||
263 | return read_bitmaps(fs, 1, 0); | ||
264 | } | ||
265 | |||
266 | errcode_t ext2fs_read_block_bitmap(ext2_filsys fs) | ||
267 | { | ||
268 | return read_bitmaps(fs, 0, 1); | ||
269 | } | ||
270 | |||
271 | errcode_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 | |||
282 | errcode_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 | |||
18 | static 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 | |||
31 | int 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 | */ | ||
51 | unsigned 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 | ||
24 | void 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 | |||
73 | void 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 | |||
83 | void 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 | |||
122 | void 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 | |||
229 | void 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 | |||
36 | struct 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 | |||
49 | static errcode_t test_open(const char *name, int flags, io_channel *channel); | ||
50 | static errcode_t test_close(io_channel channel); | ||
51 | static errcode_t test_set_blksize(io_channel channel, int blksize); | ||
52 | static errcode_t test_read_blk(io_channel channel, unsigned long block, | ||
53 | int count, void *data); | ||
54 | static errcode_t test_write_blk(io_channel channel, unsigned long block, | ||
55 | int count, const void *data); | ||
56 | static errcode_t test_flush(io_channel channel); | ||
57 | static errcode_t test_write_byte(io_channel channel, unsigned long offset, | ||
58 | int count, const void *buf); | ||
59 | static errcode_t test_set_option(io_channel channel, const char *option, | ||
60 | const char *arg); | ||
61 | |||
62 | static 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 | |||
75 | io_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 | */ | ||
81 | io_manager test_io_backing_manager = 0; | ||
82 | void (*test_io_cb_read_blk) | ||
83 | (unsigned long block, int count, errcode_t err) = 0; | ||
84 | void (*test_io_cb_write_blk) | ||
85 | (unsigned long block, int count, errcode_t err) = 0; | ||
86 | void (*test_io_cb_set_blksize) | ||
87 | (int blksize, errcode_t err) = 0; | ||
88 | void (*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 | |||
101 | static 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 | |||
121 | static 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 | |||
135 | static 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 | |||
205 | cleanup: | ||
206 | if (io) | ||
207 | ext2fs_free_mem(&io); | ||
208 | if (data) | ||
209 | ext2fs_free_mem(&data); | ||
210 | return retval; | ||
211 | } | ||
212 | |||
213 | static 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 | |||
238 | static 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 | |||
260 | static 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 | |||
287 | static 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 | |||
314 | static 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 | */ | ||
338 | static 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 | |||
357 | static 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 | |||
51 | struct 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 | |||
63 | struct 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 | |||
72 | static errcode_t unix_open(const char *name, int flags, io_channel *channel); | ||
73 | static errcode_t unix_close(io_channel channel); | ||
74 | static errcode_t unix_set_blksize(io_channel channel, int blksize); | ||
75 | static errcode_t unix_read_blk(io_channel channel, unsigned long block, | ||
76 | int count, void *data); | ||
77 | static errcode_t unix_write_blk(io_channel channel, unsigned long block, | ||
78 | int count, const void *data); | ||
79 | static errcode_t unix_flush(io_channel channel); | ||
80 | static errcode_t unix_write_byte(io_channel channel, unsigned long offset, | ||
81 | int size, const void *data); | ||
82 | static errcode_t unix_set_option(io_channel channel, const char *option, | ||
83 | const char *arg); | ||
84 | |||
85 | static 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 | |||
96 | static 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 | |||
113 | io_manager unix_io_manager = &struct_unix_manager; | ||
114 | |||
115 | /* | ||
116 | * Here are the raw I/O functions | ||
117 | */ | ||
118 | #ifndef NEED_BOUNCE_BUFFER | ||
119 | static 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 | |||
144 | error_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 | */ | ||
155 | static 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 | |||
192 | short_read: | ||
193 | if (actual>0) | ||
194 | total += actual; | ||
195 | retval = EXT2_ET_SHORT_READ; | ||
196 | |||
197 | error_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 | |||
206 | static 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 | |||
238 | error_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 */ | ||
251 | static 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 */ | ||
272 | static 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 | */ | ||
295 | static 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 | */ | ||
325 | static 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 | */ | ||
340 | static 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 | |||
371 | static 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 | |||
459 | cleanup: | ||
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 | |||
469 | static 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 | |||
496 | static 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 | |||
520 | static 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 | |||
585 | static 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 | |||
637 | static 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 | */ | ||
669 | static 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 | |||
685 | static 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 | |||
21 | struct 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 | ||
33 | static 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 | ||
70 | errcode_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 | */ | ||
27 | int 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 | |||
24 | static const char *lib_version = E2FSPROGS_VERSION; | ||
25 | static const char *lib_date = E2FSPROGS_DATE; | ||
26 | |||
27 | int 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 | |||
43 | int 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 | |||
17 | errcode_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 | } | ||