expanddir.c revision 6d8b37fa7661484ca50a4951cffbf531ab1bccbb
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * expand.c --- expand an ext2fs directory
3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
43a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999  Theodore Ts'o.
519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
7543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
144cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
164cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
17f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
18b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "ext2fs.h"
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct {
223a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	int		done;
233a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	int		newblocks;
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	err;
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
27544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic int expand_dir_proc(ext2_filsys	fs,
286d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson			   blk64_t	*blocknr,
29544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   e2_blkcnt_t	blockcnt,
306d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson			   blk64_t	ref_block EXT2FS_ATTR((unused)),
31544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   int		ref_offset EXT2FS_ATTR((unused)),
32544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   void		*priv_data)
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
34b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o	struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
356d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson	blk64_t	new_blk;
366d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson	static blk64_t	last_blk = 0;
373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		*block;
383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
39efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*blocknr) {
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		last_blk = *blocknr;
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
446d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson	retval = ext2fs_new_block2(fs, last_blk, 0, &new_blk);
453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (blockcnt > 0) {
503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_new_dir_block(fs, 0, 0, &block);
513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			es->err = retval;
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->done = 1;
5689270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o		retval = ext2fs_write_dir_block(fs, new_blk, block);
573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	} else {
58c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		retval = ext2fs_get_mem(fs->blocksize, &block);
597b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		if (retval) {
607b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			es->err = retval;
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset(block, 0, fs->blocksize);
6424a117abd0340d247befbf7687ffb70547fdf218Valerie Aurora Henson		retval = io_channel_write_blk64(fs->io, new_blk, 1, block);
65efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	}
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
70c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&block);
713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*blocknr = new_blk;
7248f23054bb8ad0506c0baa9f06ba182acc2aa88bValerie Aurora Henson	ext2fs_block_alloc_stats2(fs, new_blk, +1);
733a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	es->newblocks++;
743a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es->done)
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return (BLOCK_CHANGED | BLOCK_ABORT);
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_CHANGED;
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oerrcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct expand_dir_struct es;
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
86efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
87f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
88f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!(fs->flags & EXT2_FLAG_RW))
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_RO_FILSYS;
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
9289270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o	if (!fs->block_map)
9389270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o		return EXT2_ET_NO_BLOCK_BITMAP;
9489270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_check_directory(fs, dir);
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
98efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.done = 0;
1003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.err = 0;
1013a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	es.newblocks = 0;
102efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1036d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
10436a43d675ef61d0f5d5b2ad62d2e670c408d14acTheodore Ts'o				       0, expand_dir_proc, &es);
1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es.err)
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return es.err;
1083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!es.done)
1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_EXPAND_DIR_ERR;
1103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Update the size and block count fields in the inode.
1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_read_inode(fs, dir, &inode);
1153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
1163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
117efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size += fs->blocksize;
1191ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o	ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_write_inode(fs, dir, &inode);
1223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
127