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 #include "ext2fsP.h" 22 23 struct expand_dir_struct { 24 int done; 25 int newblocks; 26 blk64_t goal; 27 errcode_t err; 28 ext2_ino_t dir; 29 }; 30 31 static int expand_dir_proc(ext2_filsys fs, 32 blk64_t *blocknr, 33 e2_blkcnt_t blockcnt, 34 blk64_t ref_block EXT2FS_ATTR((unused)), 35 int ref_offset EXT2FS_ATTR((unused)), 36 void *priv_data) 37 { 38 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 39 blk64_t new_blk; 40 char *block; 41 errcode_t retval; 42 43 if (*blocknr) { 44 if (blockcnt >= 0) 45 es->goal = *blocknr; 46 return 0; 47 } 48 if (blockcnt && 49 (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1))) 50 new_blk = es->goal+1; 51 else { 52 es->goal &= ~EXT2FS_CLUSTER_MASK(fs); 53 retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk); 54 if (retval) { 55 es->err = retval; 56 return BLOCK_ABORT; 57 } 58 es->newblocks++; 59 ext2fs_block_alloc_stats2(fs, new_blk, +1); 60 } 61 if (blockcnt > 0) { 62 retval = ext2fs_new_dir_block(fs, 0, 0, &block); 63 if (retval) { 64 es->err = retval; 65 return BLOCK_ABORT; 66 } 67 es->done = 1; 68 retval = ext2fs_write_dir_block4(fs, new_blk, block, 0, 69 es->dir); 70 ext2fs_free_mem(&block); 71 } else 72 retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL); 73 if (blockcnt >= 0) 74 es->goal = new_blk; 75 if (retval) { 76 es->err = retval; 77 return BLOCK_ABORT; 78 } 79 *blocknr = new_blk; 80 81 if (es->done) 82 return (BLOCK_CHANGED | BLOCK_ABORT); 83 else 84 return BLOCK_CHANGED; 85 } 86 87 errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) 88 { 89 errcode_t retval; 90 struct expand_dir_struct es; 91 struct ext2_inode inode; 92 93 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 94 95 if (!(fs->flags & EXT2_FLAG_RW)) 96 return EXT2_ET_RO_FILSYS; 97 98 if (!fs->block_map) 99 return EXT2_ET_NO_BLOCK_BITMAP; 100 101 retval = ext2fs_check_directory(fs, dir); 102 if (retval) 103 return retval; 104 105 retval = ext2fs_read_inode(fs, dir, &inode); 106 if (retval) 107 return retval; 108 109 es.done = 0; 110 es.err = 0; 111 es.goal = ext2fs_find_inode_goal(fs, dir, &inode, 0); 112 es.newblocks = 0; 113 es.dir = dir; 114 115 retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND, 116 0, expand_dir_proc, &es); 117 if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE) 118 return ext2fs_inline_data_expand(fs, dir); 119 120 if (es.err) 121 return es.err; 122 if (!es.done) 123 return EXT2_ET_EXPAND_DIR_ERR; 124 125 /* 126 * Update the size and block count fields in the inode. 127 */ 128 retval = ext2fs_read_inode(fs, dir, &inode); 129 if (retval) 130 return retval; 131 132 inode.i_size += fs->blocksize; 133 ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); 134 135 retval = ext2fs_write_inode(fs, dir, &inode); 136 if (retval) 137 return retval; 138 139 return 0; 140 } 141