1/* vi: set sw=4 ts=4: */ 2/* 3 * expand.c --- expand an ext2fs directory 4 * 5 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o. 6 * 7 * %Begin-Header% 8 * This file may be redistributed under the terms of the GNU Public 9 * License. 10 * %End-Header% 11 */ 12 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 errcode_t err; 26}; 27 28static int expand_dir_proc(ext2_filsys fs, 29 blk_t *blocknr, 30 e2_blkcnt_t blockcnt, 31 blk_t ref_block EXT2FS_ATTR((unused)), 32 int ref_offset EXT2FS_ATTR((unused)), 33 void *priv_data) 34{ 35 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 36 blk_t new_blk; 37 static blk_t last_blk = 0; 38 char *block; 39 errcode_t retval; 40 41 if (*blocknr) { 42 last_blk = *blocknr; 43 return 0; 44 } 45 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); 46 if (retval) { 47 es->err = retval; 48 return BLOCK_ABORT; 49 } 50 if (blockcnt > 0) { 51 retval = ext2fs_new_dir_block(fs, 0, 0, &block); 52 if (retval) { 53 es->err = retval; 54 return BLOCK_ABORT; 55 } 56 es->done = 1; 57 retval = ext2fs_write_dir_block(fs, new_blk, block); 58 } else { 59 retval = ext2fs_get_mem(fs->blocksize, &block); 60 if (retval) { 61 es->err = retval; 62 return BLOCK_ABORT; 63 } 64 memset(block, 0, fs->blocksize); 65 retval = io_channel_write_blk(fs->io, new_blk, 1, block); 66 } 67 if (retval) { 68 es->err = retval; 69 return BLOCK_ABORT; 70 } 71 ext2fs_free_mem(&block); 72 *blocknr = new_blk; 73 ext2fs_block_alloc_stats(fs, new_blk, +1); 74 es->newblocks++; 75 76 if (es->done) 77 return (BLOCK_CHANGED | BLOCK_ABORT); 78 else 79 return BLOCK_CHANGED; 80} 81 82errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) 83{ 84 errcode_t retval; 85 struct expand_dir_struct es; 86 struct ext2_inode inode; 87 88 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 89 90 if (!(fs->flags & EXT2_FLAG_RW)) 91 return EXT2_ET_RO_FILSYS; 92 93 if (!fs->block_map) 94 return EXT2_ET_NO_BLOCK_BITMAP; 95 96 retval = ext2fs_check_directory(fs, dir); 97 if (retval) 98 return retval; 99 100 es.done = 0; 101 es.err = 0; 102 es.newblocks = 0; 103 104 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND, 105 0, expand_dir_proc, &es); 106 107 if (es.err) 108 return es.err; 109 if (!es.done) 110 return EXT2_ET_EXPAND_DIR_ERR; 111 112 /* 113 * Update the size and block count fields in the inode. 114 */ 115 retval = ext2fs_read_inode(fs, dir, &inode); 116 if (retval) 117 return retval; 118 119 inode.i_size += fs->blocksize; 120 inode.i_blocks += (fs->blocksize / 512) * es.newblocks; 121 122 retval = ext2fs_write_inode(fs, dir, &inode); 123 if (retval) 124 return retval; 125 126 return 0; 127} 128