diff options
Diffstat (limited to 'e2fsprogs/ext2fs/expanddir.c')
-rw-r--r-- | e2fsprogs/ext2fs/expanddir.c | 126 |
1 files changed, 126 insertions, 0 deletions
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 | } | ||