expanddir.c revision 3839e65723771b85975f4263102dd3ceec4523c
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * expand.c --- expand an ext2fs directory
33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * under the terms of the GNU Public License.
63839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
73839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
83839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
93839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdlib.h>
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <linux/fs.h>
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <linux/ext2_fs.h>
143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "ext2fs.h"
163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct {
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	done;
193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	err;
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int expand_dir_proc(ext2_filsys fs,
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   blk_t	*blocknr,
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   int	blockcnt,
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			   void	*private)
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct expand_dir_struct *es = (struct expand_dir_struct *) private;
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blk_t	new_blk;
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	static blk_t	last_blk = 0;
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char		*block;
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int		group;
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*blocknr) {
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		last_blk = *blocknr;
363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (blockcnt > 0) {
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_new_dir_block(fs, 0, 0, &block);
453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval) {
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			es->err = retval;
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->done = 1;
503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	} else {
513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		block = malloc(fs->blocksize);
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (!block) {
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			es->err = ENOMEM;
543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			return BLOCK_ABORT;
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset(block, 0, fs->blocksize);
573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = io_channel_write_blk(fs->io, new_blk, 1, block);
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval) {
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		es->err = retval;
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_ABORT;
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free(block);
643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*blocknr = new_blk;
653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_block_bitmap(fs, fs->block_map, new_blk);
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_bb_dirty(fs);
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	group = ext2fs_group_of_blk(fs, new_blk);
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fs->group_desc[group].bg_free_blocks_count--;
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	fs->super->s_free_blocks_count--;
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	ext2fs_mark_super_dirty(fs);
713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es->done)
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return (BLOCK_CHANGED | BLOCK_ABORT);
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return BLOCK_CHANGED;
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oerrcode_t ext2fs_expand_dir(ext2_filsys fs, ino_t dir)
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct expand_dir_struct es;
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct ext2_inode	inode;
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!(fs->flags & EXT2_FLAG_RW))
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_RO_FILSYS;
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_check_directory(fs, dir);
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.done = 0;
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	es.err = 0;
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_block_iterate(fs, dir, BLOCK_FLAG_APPEND,
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				      0, expand_dir_proc, &es);
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (es.err)
973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return es.err;
983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!es.done)
993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return EXT2_ET_EXPAND_DIR_ERR;
1003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Update the size and block count fields in the inode.
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_read_inode(fs, dir, &inode);
1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
1063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size += fs->blocksize;
1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_blocks += fs->blocksize / 512;
1103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_write_inode(fs, dir, &inode);
1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return retval;
1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
1163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
117