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
12d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h"
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
154cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
174cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
18f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
19b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "ext2fs.h"
2124997f1cd2b3c3ea7a5a2c7fe37013de36a6d8a3Darrick J. Wong#include "ext2fsP.h"
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct {
243a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	int		done;
253a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	int		newblocks;
264a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	blk64_t		goal;
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	err;
2881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	ext2_ino_t	dir;
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
31544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic int expand_dir_proc(ext2_filsys	fs,
326d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson			   blk64_t	*blocknr,
33544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   e2_blkcnt_t	blockcnt,
346d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson			   blk64_t	ref_block EXT2FS_ATTR((unused)),
35544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   int		ref_offset EXT2FS_ATTR((unused)),
36544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   void		*priv_data)
373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
38b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o	struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
396d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson	blk64_t	new_blk;
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		*block;
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
42efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*blocknr) {
444a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		if (blockcnt >= 0)
454a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o			es->goal = *blocknr;
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
484a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	if (blockcnt &&
494a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	    (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1)))
504a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		new_blk = es->goal+1;
514a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	else {
524a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		es->goal &= ~EXT2FS_CLUSTER_MASK(fs);
534a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk);
544a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		if (retval) {
554a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o			es->err = retval;
564a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o			return BLOCK_ABORT;
574a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		}
58b2e6c86d61fccc39956c0cb8a8333f42d1569e8dTheodore Ts'o		es->newblocks++;
59230272c15a71edfd53bc805adf560d0386dddff3Darrick J. Wong		ext2fs_block_alloc_stats2(fs, new_blk, +1);
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (blockcnt > 0) {
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_new_dir_block(fs, 0, 0, &block);
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			es->err = retval;
653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->done = 1;
6881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
6981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong						 es->dir);
7008c8e319e3e11e30eb8c0b65809d434e807a4456Darrick J. Wong		ext2fs_free_mem(&block);
7108c8e319e3e11e30eb8c0b65809d434e807a4456Darrick J. Wong	} else
7208c8e319e3e11e30eb8c0b65809d434e807a4456Darrick J. Wong		retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL);
734a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	if (blockcnt >= 0)
744a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		es->goal = new_blk;
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*blocknr = new_blk;
803a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es->done)
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return (BLOCK_CHANGED | BLOCK_ABORT);
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_CHANGED;
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oerrcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct expand_dir_struct es;
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
92efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
93f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
94f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!(fs->flags & EXT2_FLAG_RW))
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_RO_FILSYS;
973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
9889270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o	if (!fs->block_map)
9989270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o		return EXT2_ET_NO_BLOCK_BITMAP;
10089270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_check_directory(fs, dir);
1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
104efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1057b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong	retval = ext2fs_read_inode(fs, dir, &inode);
1067b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong	if (retval)
1077b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong		return retval;
1087b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong
1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.done = 0;
1103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.err = 0;
1117b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong	es.goal = ext2fs_find_inode_goal(fs, dir, &inode, 0);
1123a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	es.newblocks = 0;
11381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	es.dir = dir;
114efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1156d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
11636a43d675ef61d0f5d5b2ad62d2e670c408d14acTheodore Ts'o				       0, expand_dir_proc, &es);
11746bd6bdfc8c2e79336267f639b7963bea4487c42Zheng Liu	if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE)
11846bd6bdfc8c2e79336267f639b7963bea4487c42Zheng Liu		return ext2fs_inline_data_expand(fs, dir);
1193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es.err)
1213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return es.err;
1223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!es.done)
1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_EXPAND_DIR_ERR;
1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Update the size and block count fields in the inode.
1273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_read_inode(fs, dir, &inode);
1293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
1303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
131efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size += fs->blocksize;
1331ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o	ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
1343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_write_inode(fs, dir, &inode);
1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
1403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
141