expanddir.c revision 1ca1059fd0126fd2c065f272a566c18f14bab16d
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 Public 8 * License. 9 * %End-Header% 10 */ 11 12#include <stdio.h> 13#include <string.h> 14#if HAVE_UNISTD_H 15#include <unistd.h> 16#endif 17 18#include "ext2_fs.h" 19#include "ext2fs.h" 20 21struct expand_dir_struct { 22 int done; 23 int newblocks; 24 errcode_t err; 25}; 26 27static int expand_dir_proc(ext2_filsys fs, 28 blk_t *blocknr, 29 e2_blkcnt_t blockcnt, 30 blk_t ref_block EXT2FS_ATTR((unused)), 31 int ref_offset EXT2FS_ATTR((unused)), 32 void *priv_data) 33{ 34 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 35 blk_t new_blk; 36 static blk_t last_blk = 0; 37 char *block; 38 errcode_t retval; 39 40 if (*blocknr) { 41 last_blk = *blocknr; 42 return 0; 43 } 44 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); 45 if (retval) { 46 es->err = retval; 47 return BLOCK_ABORT; 48 } 49 if (blockcnt > 0) { 50 retval = ext2fs_new_dir_block(fs, 0, 0, &block); 51 if (retval) { 52 es->err = retval; 53 return BLOCK_ABORT; 54 } 55 es->done = 1; 56 retval = ext2fs_write_dir_block(fs, new_blk, block); 57 } else { 58 retval = ext2fs_get_mem(fs->blocksize, &block); 59 if (retval) { 60 es->err = retval; 61 return BLOCK_ABORT; 62 } 63 memset(block, 0, fs->blocksize); 64 retval = io_channel_write_blk(fs->io, new_blk, 1, block); 65 } 66 if (retval) { 67 es->err = retval; 68 return BLOCK_ABORT; 69 } 70 ext2fs_free_mem(&block); 71 *blocknr = new_blk; 72 ext2fs_block_alloc_stats(fs, new_blk, +1); 73 es->newblocks++; 74 75 if (es->done) 76 return (BLOCK_CHANGED | BLOCK_ABORT); 77 else 78 return BLOCK_CHANGED; 79} 80 81errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) 82{ 83 errcode_t retval; 84 struct expand_dir_struct es; 85 struct ext2_inode inode; 86 87 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 88 89 if (!(fs->flags & EXT2_FLAG_RW)) 90 return EXT2_ET_RO_FILSYS; 91 92 if (!fs->block_map) 93 return EXT2_ET_NO_BLOCK_BITMAP; 94 95 retval = ext2fs_check_directory(fs, dir); 96 if (retval) 97 return retval; 98 99 es.done = 0; 100 es.err = 0; 101 es.newblocks = 0; 102 103 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND, 104 0, expand_dir_proc, &es); 105 106 if (es.err) 107 return es.err; 108 if (!es.done) 109 return EXT2_ET_EXPAND_DIR_ERR; 110 111 /* 112 * Update the size and block count fields in the inode. 113 */ 114 retval = ext2fs_read_inode(fs, dir, &inode); 115 if (retval) 116 return retval; 117 118 inode.i_size += fs->blocksize; 119 ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); 120 121 retval = ext2fs_write_inode(fs, dir, &inode); 122 if (retval) 123 return retval; 124 125 return 0; 126} 127