expanddir.c revision 81683c6a32045cf04d76a024e6f1753535b97c22
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"
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct {
233a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	int		done;
243a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	int		newblocks;
254a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	blk64_t		goal;
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	err;
2781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	ext2_ino_t	dir;
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
30544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic int expand_dir_proc(ext2_filsys	fs,
316d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson			   blk64_t	*blocknr,
32544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   e2_blkcnt_t	blockcnt,
336d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson			   blk64_t	ref_block EXT2FS_ATTR((unused)),
34544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   int		ref_offset EXT2FS_ATTR((unused)),
35544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			   void		*priv_data)
363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
37b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o	struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
386d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson	blk64_t	new_blk;
393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		*block;
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
41efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*blocknr) {
434a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		if (blockcnt >= 0)
444a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o			es->goal = *blocknr;
453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
474a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	if (blockcnt &&
484a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	    (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1)))
494a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		new_blk = es->goal+1;
504a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	else {
514a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		es->goal &= ~EXT2FS_CLUSTER_MASK(fs);
524a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk);
534a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		if (retval) {
544a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o			es->err = retval;
554a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o			return BLOCK_ABORT;
564a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		}
57b2e6c86d61fccc39956c0cb8a8333f42d1569e8dTheodore Ts'o		es->newblocks++;
583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (blockcnt > 0) {
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_new_dir_block(fs, 0, 0, &block);
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			es->err = retval;
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->done = 1;
6681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
6781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong						 es->dir);
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	} else {
69c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		retval = ext2fs_get_mem(fs->blocksize, &block);
707b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		if (retval) {
717b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			es->err = retval;
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset(block, 0, fs->blocksize);
7524a117abd0340d247befbf7687ffb70547fdf218Valerie Aurora Henson		retval = io_channel_write_blk64(fs->io, new_blk, 1, block);
76efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	}
774a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	if (blockcnt >= 0)
784a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o		es->goal = new_blk;
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
83c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&block);
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*blocknr = new_blk;
8548f23054bb8ad0506c0baa9f06ba182acc2aa88bValerie Aurora Henson	ext2fs_block_alloc_stats2(fs, new_blk, +1);
863a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es->done)
883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return (BLOCK_CHANGED | BLOCK_ABORT);
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_CHANGED;
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
9331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oerrcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct expand_dir_struct es;
973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
98efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
99f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
100f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!(fs->flags & EXT2_FLAG_RW))
1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_RO_FILSYS;
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
10489270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o	if (!fs->block_map)
10589270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o		return EXT2_ET_NO_BLOCK_BITMAP;
10689270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_check_directory(fs, dir);
1083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
110efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.done = 0;
1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.err = 0;
1134a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o	es.goal = 0;
1143a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o	es.newblocks = 0;
11581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	es.dir = dir;
116efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1176d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
11836a43d675ef61d0f5d5b2ad62d2e670c408d14acTheodore Ts'o				       0, expand_dir_proc, &es);
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