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