expanddir.c revision d1154eb460efe588eaed3d439c1caaca149fa362
1/* 2 * expand.c --- expand an ext2fs directory 3 * 4 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Library 8 * General Public License, version 2. 9 * %End-Header% 10 */ 11 12#include "config.h" 13#include <stdio.h> 14#include <string.h> 15#if HAVE_UNISTD_H 16#include <unistd.h> 17#endif 18 19#include "ext2_fs.h" 20#include "ext2fs.h" 21 22struct expand_dir_struct { 23 int done; 24 int newblocks; 25 blk64_t goal; 26 errcode_t err; 27}; 28 29static int expand_dir_proc(ext2_filsys fs, 30 blk64_t *blocknr, 31 e2_blkcnt_t blockcnt, 32 blk64_t ref_block EXT2FS_ATTR((unused)), 33 int ref_offset EXT2FS_ATTR((unused)), 34 void *priv_data) 35{ 36 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 37 blk64_t new_blk; 38 char *block; 39 errcode_t retval; 40 41 if (*blocknr) { 42 if (blockcnt >= 0) 43 es->goal = *blocknr; 44 return 0; 45 } 46 if (blockcnt && 47 (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1))) 48 new_blk = es->goal+1; 49 else { 50 es->goal &= ~EXT2FS_CLUSTER_MASK(fs); 51 retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk); 52 if (retval) { 53 es->err = retval; 54 return BLOCK_ABORT; 55 } 56 es->newblocks++; 57 } 58 if (blockcnt > 0) { 59 retval = ext2fs_new_dir_block(fs, 0, 0, &block); 60 if (retval) { 61 es->err = retval; 62 return BLOCK_ABORT; 63 } 64 es->done = 1; 65 retval = ext2fs_write_dir_block(fs, new_blk, block); 66 } else { 67 retval = ext2fs_get_mem(fs->blocksize, &block); 68 if (retval) { 69 es->err = retval; 70 return BLOCK_ABORT; 71 } 72 memset(block, 0, fs->blocksize); 73 retval = io_channel_write_blk64(fs->io, new_blk, 1, block); 74 } 75 if (blockcnt >= 0) 76 es->goal = new_blk; 77 if (retval) { 78 es->err = retval; 79 return BLOCK_ABORT; 80 } 81 ext2fs_free_mem(&block); 82 *blocknr = new_blk; 83 ext2fs_block_alloc_stats2(fs, new_blk, +1); 84 85 if (es->done) 86 return (BLOCK_CHANGED | BLOCK_ABORT); 87 else 88 return BLOCK_CHANGED; 89} 90 91errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) 92{ 93 errcode_t retval; 94 struct expand_dir_struct es; 95 struct ext2_inode inode; 96 97 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 98 99 if (!(fs->flags & EXT2_FLAG_RW)) 100 return EXT2_ET_RO_FILSYS; 101 102 if (!fs->block_map) 103 return EXT2_ET_NO_BLOCK_BITMAP; 104 105 retval = ext2fs_check_directory(fs, dir); 106 if (retval) 107 return retval; 108 109 es.done = 0; 110 es.err = 0; 111 es.goal = 0; 112 es.newblocks = 0; 113 114 retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND, 115 0, expand_dir_proc, &es); 116 117 if (es.err) 118 return es.err; 119 if (!es.done) 120 return EXT2_ET_EXPAND_DIR_ERR; 121 122 /* 123 * Update the size and block count fields in the inode. 124 */ 125 retval = ext2fs_read_inode(fs, dir, &inode); 126 if (retval) 127 return retval; 128 129 inode.i_size += fs->blocksize; 130 ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); 131 132 retval = ext2fs_write_inode(fs, dir, &inode); 133 if (retval) 134 return retval; 135 136 return 0; 137} 138