expanddir.c revision 5be8dc2143c7b3b21a9b8fb56797dd855ee87560
1/*
2 * expand.c --- expand an ext2fs directory
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 <linux/ext2_fs.h>
19
20#include "ext2fs.h"
21
22struct expand_dir_struct {
23	int	done;
24	errcode_t	err;
25};
26
27static int expand_dir_proc(ext2_filsys fs,
28			   blk_t	*blocknr,
29			   int	blockcnt,
30			   void	*private)
31{
32	struct expand_dir_struct *es = (struct expand_dir_struct *) private;
33	blk_t	new_blk;
34	static blk_t	last_blk = 0;
35	char		*block;
36	errcode_t	retval;
37	int		group;
38
39	if (*blocknr) {
40		last_blk = *blocknr;
41		return 0;
42	}
43	retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
44	if (retval) {
45		es->err = retval;
46		return BLOCK_ABORT;
47	}
48	if (blockcnt > 0) {
49		retval = ext2fs_new_dir_block(fs, 0, 0, &block);
50		if (retval) {
51			es->err = retval;
52			return BLOCK_ABORT;
53		}
54		es->done = 1;
55		retval = ext2fs_write_dir_block(fs, new_blk, block);
56	} else {
57		retval = ext2fs_get_mem(fs->blocksize, (void **) &block);
58		if (retval) {
59			es->err = retval;
60			return BLOCK_ABORT;
61		}
62		memset(block, 0, fs->blocksize);
63		retval = io_channel_write_blk(fs->io, new_blk, 1, block);
64	}
65	if (retval) {
66		es->err = retval;
67		return BLOCK_ABORT;
68	}
69	ext2fs_free_mem((void **) &block);
70	*blocknr = new_blk;
71	ext2fs_mark_block_bitmap(fs->block_map, new_blk);
72	ext2fs_mark_bb_dirty(fs);
73	group = ext2fs_group_of_blk(fs, new_blk);
74	fs->group_desc[group].bg_free_blocks_count--;
75	fs->super->s_free_blocks_count--;
76	ext2fs_mark_super_dirty(fs);
77	if (es->done)
78		return (BLOCK_CHANGED | BLOCK_ABORT);
79	else
80		return BLOCK_CHANGED;
81}
82
83errcode_t ext2fs_expand_dir(ext2_filsys fs, ino_t dir)
84{
85	errcode_t	retval;
86	struct expand_dir_struct es;
87	struct ext2_inode	inode;
88
89	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
90
91	if (!(fs->flags & EXT2_FLAG_RW))
92		return EXT2_ET_RO_FILSYS;
93
94	if (!fs->block_map)
95		return EXT2_ET_NO_BLOCK_BITMAP;
96
97	retval = ext2fs_check_directory(fs, dir);
98	if (retval)
99		return retval;
100
101	es.done = 0;
102	es.err = 0;
103
104	retval = ext2fs_block_iterate(fs, dir, BLOCK_FLAG_APPEND,
105				      0, expand_dir_proc, &es);
106
107	if (es.err)
108		return es.err;
109	if (!es.done)
110		return EXT2_ET_EXPAND_DIR_ERR;
111
112	/*
113	 * Update the size and block count fields in the inode.
114	 */
115	retval = ext2fs_read_inode(fs, dir, &inode);
116	if (retval)
117		return retval;
118
119	inode.i_size += fs->blocksize;
120	inode.i_blocks += fs->blocksize / 512;
121
122	retval = ext2fs_write_inode(fs, dir, &inode);
123	if (retval)
124		return retval;
125
126	return 0;
127}
128