13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * expand.c --- expand an ext2fs directory 3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 43a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o. 519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * 619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header% 7543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library 8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2. 919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header% 103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 12d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h" 133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h> 143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h> 154cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H 163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h> 174cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif 18f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 19b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h" 203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "ext2fs.h" 2124997f1cd2b3c3ea7a5a2c7fe37013de36a6d8a3Darrick J. Wong#include "ext2fsP.h" 223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct { 243a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o int done; 253a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o int newblocks; 264a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o blk64_t goal; 273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t err; 2881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong ext2_ino_t dir; 293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 31544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic int expand_dir_proc(ext2_filsys fs, 326d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson blk64_t *blocknr, 33544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o e2_blkcnt_t blockcnt, 346d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson blk64_t ref_block EXT2FS_ATTR((unused)), 35544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int ref_offset EXT2FS_ATTR((unused)), 36544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o void *priv_data) 373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 38b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; 396d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson blk64_t new_blk; 403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char *block; 413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 42efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (*blocknr) { 444a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o if (blockcnt >= 0) 454a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o es->goal = *blocknr; 463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 484a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o if (blockcnt && 494a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1))) 504a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o new_blk = es->goal+1; 514a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o else { 524a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o es->goal &= ~EXT2FS_CLUSTER_MASK(fs); 534a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk); 544a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o if (retval) { 554a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o es->err = retval; 564a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o return BLOCK_ABORT; 574a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o } 58b2e6c86d61fccc39956c0cb8a8333f42d1569e8dTheodore Ts'o es->newblocks++; 59230272c15a71edfd53bc805adf560d0386dddff3Darrick J. Wong ext2fs_block_alloc_stats2(fs, new_blk, +1); 603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (blockcnt > 0) { 623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_dir_block(fs, 0, 0, &block); 633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->done = 1; 6881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong retval = ext2fs_write_dir_block4(fs, new_blk, block, 0, 6981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong es->dir); 7008c8e319e3e11e30eb8c0b65809d434e807a4456Darrick J. Wong ext2fs_free_mem(&block); 7108c8e319e3e11e30eb8c0b65809d434e807a4456Darrick J. Wong } else 7208c8e319e3e11e30eb8c0b65809d434e807a4456Darrick J. Wong retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL); 734a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o if (blockcnt >= 0) 744a2a9b70c89891a146bcb9cee3f29572ca2e1370Theodore Ts'o es->goal = new_blk; 753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *blocknr = new_blk; 803a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o 813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (es->done) 823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return (BLOCK_CHANGED | BLOCK_ABORT); 833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o else 843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_CHANGED; 853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 8731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oerrcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) 883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct expand_dir_struct es; 913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 92efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 93f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 94f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!(fs->flags & EXT2_FLAG_RW)) 963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return EXT2_ET_RO_FILSYS; 973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 9889270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o if (!fs->block_map) 9989270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o return EXT2_ET_NO_BLOCK_BITMAP; 10089270b5531516cf80498ad67809c1f09ce476568Theodore Ts'o 1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_check_directory(fs, dir); 1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 104efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 1057b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong retval = ext2fs_read_inode(fs, dir, &inode); 1067b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong if (retval) 1077b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong return retval; 1087b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong 1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es.done = 0; 1103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es.err = 0; 1117b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong es.goal = ext2fs_find_inode_goal(fs, dir, &inode, 0); 1123a5f8eaa9741f6f14520ddd263a996e2764dd437Theodore Ts'o es.newblocks = 0; 11381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong es.dir = dir; 114efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 1156d8b37fa7661484ca50a4951cffbf531ab1bccbbValerie Aurora Henson retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND, 11636a43d675ef61d0f5d5b2ad62d2e670c408d14acTheodore Ts'o 0, expand_dir_proc, &es); 11746bd6bdfc8c2e79336267f639b7963bea4487c42Zheng Liu if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE) 11846bd6bdfc8c2e79336267f639b7963bea4487c42Zheng Liu return ext2fs_inline_data_expand(fs, dir); 1193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (es.err) 1213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return es.err; 1223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!es.done) 1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return EXT2_ET_EXPAND_DIR_ERR; 1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Update the size and block count fields in the inode. 1273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_read_inode(fs, dir, &inode); 1293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 1303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 131efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 1323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_size += fs->blocksize; 1331ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); 1343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_write_inode(fs, dir, &inode); 1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 1403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 141