pass3.c revision 21c84b71e205b5ab13f14343da5645dcc985856d
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * pass3.c -- pass #3 of e2fsck: Check for directory connectivity 33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. 521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * 621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %Begin-Header% 721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * This file may be redistributed under the terms of the GNU Public 821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * License. 921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %End-Header% 103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass #3 assures that all directories are connected to the 123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * filesystem tree, using the following algorithm: 133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * First, the root directory is checked to make sure it exists; if 153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * not, e2fsck will offer to create a new one. It is then marked as 163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * "done". 173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Then, pass3 interates over all directory inodes; for each directory 193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * it attempts to trace up the filesystem tree, using dirinfo.parent 203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * until it reaches a directory which has been marked "done". If it 213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * can not do so, then the directory must be disconnected, and e2fsck 223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * will offer to reconnect it to /lost+found. While it is chasing 233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * parent pointers up the filesystem tree, if pass3 sees a directory 243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * twice, then it has detected a filesystem loop, and it will again 253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * offer to reconnect the directory to /lost+found in to break the 263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * filesystem loop. 273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 3 also contains the subroutine, reconnect_file() to reconnect 293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * inodes to /lost+found; this subroutine is also used by pass 4. 303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * reconnect_file() calls get_lost_and_found(), which is responsible 313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * for creating /lost+found if it does not exist. 323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 3 frees the following data structures: 343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The dirinfo directory information cache. 353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#ifdef HAVE_ERRNO_H 3850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#include <errno.h> 3950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#endif 403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "et/com_err.h" 413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "e2fsck.h" 4321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "problem.h" 443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostatic void check_root(ext2_filsys fs); 4621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostatic void check_directory(ext2_filsys fs, struct dir_info *dir, 4721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o struct problem_context *pctx); 483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic ino_t get_lost_and_found(ext2_filsys fs); 493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent); 50f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic errcode_t adjust_inode_count(ext2_filsys fs, ino_t ino, int adj); 513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t expand_directory(ext2_filsys fs, ino_t dir); 523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic ino_t lost_and_found = 0; 543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int bad_lost_and_found = 0; 553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 56f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic ext2fs_inode_bitmap inode_loop_detect; 57f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic ext2fs_inode_bitmap inode_done_map; 583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ovoid pass3(ext2_filsys fs) 603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int i; 623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct resource_track rtrack; 6421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o struct problem_context pctx; 6521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o struct dir_info *dir; 663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o init_resource_track(&rtrack); 683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#ifdef MTRACE 703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o mtrace_print("Pass 3"); 713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!preen) 743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o printf("Pass 3: Checking directory connectivity\n"); 753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Allocate some bitmaps to do loop detection. 783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 79f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o retval = ext2fs_allocate_inode_bitmap(fs, 80f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o "inode loop detection bitmap", 81f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o &inode_loop_detect); 823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_allocate_inode_bitmap", retval, 843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "while allocating inode_loop_detect"); 853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fatal_error(0); 863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 87f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o retval = ext2fs_allocate_inode_bitmap(fs, "inode done bitmap", 88f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o &inode_done_map); 893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_allocate_inode_bitmap", retval, 913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "while allocating inode_done_map"); 923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fatal_error(0); 933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (tflag) { 953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o printf("Peak memory: "); 963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o print_resource_track(&global_rtrack); 973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 9921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o check_root(fs); 100f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO); 1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 10221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o clear_problem_context(&pctx); 10321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o for (i=0; (dir = dir_info_iter(&i)) != 0;) { 10421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (ext2fs_test_inode_bitmap(inode_dir_map, dir->ino)) 10521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o check_directory(fs, dir, &pctx); 1063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 10821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o free_dir_info(fs); 110f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_free_inode_bitmap(inode_loop_detect); 111f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_free_inode_bitmap(inode_done_map); 1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (tflag > 1) { 1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o printf("Pass 3: "); 1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o print_resource_track(&rtrack); 1153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 1173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 1193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This makes sure the root inode is present; if not, we ask if the 1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * user wants us to create it. Not creating it is a fatal error. 1213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 12221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostatic void check_root(ext2_filsys fs) 1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t blk; 1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 1273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char * block; 1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 12921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (ext2fs_test_inode_bitmap(inode_used_map, EXT2_ROOT_INO)) { 1303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 1313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * If the root inode is a directory, die here. The 1323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * user must have answered 'no' in pass1 when we 1333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * offered to clear it. 1343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 13521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (!(ext2fs_test_inode_bitmap(inode_dir_map, EXT2_ROOT_INO))) 1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fatal_error("Root inode not directory"); 1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return; 1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 14021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (!fix_problem(fs, PR_3_NO_ROOT_INODE, 0)) 1413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fatal_error("Cannot proceed without a root inode."); 1423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o read_bitmaps(fs); 1443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 1463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * First, find a free block 1473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_block(fs, 0, block_found_map, &blk); 1493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 1503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_new_block", retval, 1513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "while trying to create root directory"); 1523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fatal_error(0); 1533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 154f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_block_bitmap(block_found_map, blk); 155f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_block_bitmap(fs->block_map, blk); 1563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_mark_bb_dirty(fs); 1573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 1593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Now let's create the actual data block for the inode 1603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 1623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o &block); 1633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 1643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_new_dir_block", retval, 1653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "while creating new root directory"); 1663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fatal_error(0); 1673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 16950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o retval = ext2fs_write_dir_block(fs, blk, block); 1703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 17150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o com_err("ext2fs_write_dir_block", retval, 1723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "while writing the root directory block"); 1733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fatal_error(0); 1743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o free(block); 1763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 1783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Set up the inode structure 1793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(&inode, 0, sizeof(inode)); 1813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_mode = 040755; 1823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_size = fs->blocksize; 1833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_atime = inode.i_ctime = inode.i_mtime = time(0); 1843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_links_count = 2; 1853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_blocks = fs->blocksize / 512; 1863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_block[0] = blk; 1873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 1893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Write out the inode. 1903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode); 1923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 1933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_write_inode", retval, 1943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "While trying to create /lost+found"); 1953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fatal_error(0); 1963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 1993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Miscellaneous bookkeeping... 2003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 20121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o add_dir_info(fs, EXT2_ROOT_INO, EXT2_ROOT_INO); 20221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o ext2fs_icount_store(inode_count, EXT2_ROOT_INO, 2); 20321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o ext2fs_icount_store(inode_link_info, EXT2_ROOT_INO, 2); 2043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 205f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(inode_used_map, EXT2_ROOT_INO); 206f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(inode_dir_map, EXT2_ROOT_INO); 207f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO); 2083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_mark_ib_dirty(fs); 2093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 2103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 2123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This subroutine is responsible for making sure that a particular 2133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory is connected to the root; if it isn't we trace it up as 2143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * far as we can go, and then offer to connect the resulting parent to 2153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * the lost+found. We have to do loop detection; if we ever discover 2163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * a loop, we treat that as a disconnected directory and offer to 2173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * reparent it to lost+found. 2183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 21921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostatic void check_directory(ext2_filsys fs, struct dir_info *dir, 22021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o struct problem_context *pctx) 2213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 22221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o struct dir_info *p = dir; 2233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 224f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_clear_inode_bitmap(inode_loop_detect); 2253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o while (p) { 2263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * If we find a parent which we've already checked, 2283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * then stop; we know it's either already connected to 2293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * the directory tree, or it isn't but the user has 2303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * already told us he doesn't want us to reconnect the 2313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * disconnected subtree. 2323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 233f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (ext2fs_test_inode_bitmap(inode_done_map, p->ino)) 2343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto check_dot_dot; 2353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Mark this inode as being "done"; by the time we 2373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * return from this function, the inode we either be 2383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * verified as being connected to the directory tree, 2393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * or we will have offered to reconnect this to 2403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * lost+found. 2413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 242f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(inode_done_map, p->ino); 2433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * If this directory doesn't have a parent, or we've 2453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * seen the parent once already, then offer to 2463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * reparent it to lost+found 2473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 2483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!p->parent || 249f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o (ext2fs_test_inode_bitmap(inode_loop_detect, 2503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o p->parent))) 2513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o break; 252f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(inode_loop_detect, 2533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o p->parent); 2543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o p = get_dir_info(p->parent); 2553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 2563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * If we've reached here, we've hit a detached directory 2583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * inode; offer to reconnect it to lost+found. 2593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 26021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->ino = p->ino; 26121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (fix_problem(fs, PR_3_UNCONNECTED_DIR, pctx)) { 2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (reconnect_file(fs, p->ino)) 2633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_unmark_valid(fs); 2643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o else { 2653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o p->parent = lost_and_found; 2663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fix_dotdot(fs, p, lost_and_found); 2673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 26821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 2693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 2713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure that .. and the parent directory are the same; 2723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * offer to fix it if not. 2733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 2743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocheck_dot_dot: 2753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (dir->parent != dir->dotdot) { 27621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->ino = dir->ino; 27721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->ino2 = dir->dotdot; 27821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx->dir = dir->parent; 27921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (fix_problem(fs, PR_3_BAD_DOT_DOT, pctx)) 2803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fix_dotdot(fs, dir, dir->parent); 2813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 2823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 2833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 2843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 2853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine gets the lost_and_found inode, making it a directory 2863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * if necessary 2873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oino_t get_lost_and_found(ext2_filsys fs) 2893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 2903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ino_t ino; 2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t blk; 2923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 2933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char * block; 29521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o const char name[] = "lost+found"; 2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 29721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, 29821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o sizeof(name)-1, 0, &ino); 2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!retval) 3003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return ino; 3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval != ENOENT) 3023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o printf("Error while trying to find /lost+found: %s", 3033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o error_message(retval)); 30421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (!fix_problem(fs, PR_3_NO_LF_DIR, 0)) 3053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Read the inode and block bitmaps in; we'll be messing with 3093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * them. 3103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o read_bitmaps(fs); 3123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * First, find a free block 3153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_block(fs, 0, block_found_map, &blk); 3173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 3183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_new_block", retval, 3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "while trying to create /lost+found directory"); 3203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 322f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_block_bitmap(block_found_map, blk); 323f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_block_bitmap(fs->block_map, blk); 3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_mark_bb_dirty(fs); 3253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Next find a free inode. 3283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040755, inode_used_map, 3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o &ino); 3313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 3323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_new_inode", retval, 3333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "while trying to create /lost+found directory"); 3343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 336f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(inode_used_map, ino); 337f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(inode_dir_map, ino); 338f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_inode_bitmap(fs->inode_map, ino); 3393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_mark_ib_dirty(fs); 3403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Now let's create the actual data block for the inode 3433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); 3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_new_dir_block", retval, 3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "while creating new directory block"); 3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 35150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o retval = ext2fs_write_dir_block(fs, blk, block); 35250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o free(block); 3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 35450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o com_err("ext2fs_write_dir_block", retval, 3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "while writing the directory block for /lost+found"); 3563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Set up the inode structure 3613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(&inode, 0, sizeof(inode)); 3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_mode = 040755; 3643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_size = fs->blocksize; 3653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_atime = inode.i_ctime = inode.i_mtime = time(0); 3663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_links_count = 2; 3673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_blocks = fs->blocksize / 512; 3683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_block[0] = blk; 3693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Next, write out the inode. 3723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_write_inode(fs, ino, &inode); 3743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 3753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_write_inode", retval, 3763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "While trying to create /lost+found"); 3773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Finally, create the directory link 3813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, 0); 3833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o com_err("ext2fs_link", retval, "While creating /lost+found"); 3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Miscellaneous bookkeeping that needs to be kept straight. 3903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 39121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o add_dir_info(fs, ino, EXT2_ROOT_INO); 3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o adjust_inode_count(fs, EXT2_ROOT_INO, +1); 39321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o ext2fs_icount_store(inode_count, ino, 2); 39421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o ext2fs_icount_store(inode_link_info, ino, 2); 3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 396f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("/lost+found created; inode #%lu\n", ino); 3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return ino; 3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This routine will connect a file to lost+found 4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oint reconnect_file(ext2_filsys fs, ino_t inode) 4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 4073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char name[80]; 4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (bad_lost_and_found) { 4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o printf("Bad or nonexistent /lost+found. Cannot reconnect.\n"); 4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!lost_and_found) { 4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o lost_and_found = get_lost_and_found(fs); 4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!lost_and_found) { 4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o printf("Bad or nonexistent /lost+found. Cannot reconnect.\n"); 4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o bad_lost_and_found++; 4183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 422f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o sprintf(name, "#%lu", inode); 4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_link(fs, lost_and_found, name, inode, 0); 4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval == EXT2_ET_DIR_NO_SPACE) { 42521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (!fix_problem(fs, PR_3_EXPAND_LF_DIR, 0)) 4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 4273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = expand_directory(fs, lost_and_found); 4283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o printf("Could not expand /lost+found: %s\n", 4303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o error_message(retval)); 4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 4323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_link(fs, lost_and_found, name, inode, 0); 4343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 436f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("Could not reconnect %lu: %s\n", inode, 4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o error_message(retval)); 4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o adjust_inode_count(fs, inode, +1); 4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Utility routine to adjust the inode counts on an inode. 4483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 449f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic errcode_t adjust_inode_count(ext2_filsys fs, ino_t ino, int adj) 4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!ino) 4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_read_inode(fs, ino, &inode); 4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 462f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj, 4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_links_count); 4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_links_count += adj; 46721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (adj == 1) { 46821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o ext2fs_icount_increment(inode_count, ino, 0); 46921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o ext2fs_icount_increment(inode_link_info, ino, 0); 47021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } else { 47121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o ext2fs_icount_decrement(inode_count, ino, 0); 47221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o ext2fs_icount_decrement(inode_link_info, ino, 0); 47321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 47421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_write_inode(fs, ino, &inode); 4773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 4793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 4843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Fix parent --- this routine fixes up the parent of a directory. 4853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct fix_dotdot_struct { 4873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2_filsys fs; 4883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ino_t parent; 4893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int done; 4903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int fix_dotdot_proc(struct ext2_dir_entry *dirent, 4933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int offset, 4943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int blocksize, 4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char *buf, 4963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o void *private) 4973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) private; 4993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (dirent->name_len != 2) 5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (strncmp(dirent->name, "..", 2)) 5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = adjust_inode_count(fp->fs, dirent->inode, -1); 5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 50850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o printf("Error while adjusting inode count on inode %u\n", 5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode); 5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = adjust_inode_count(fp->fs, fp->parent, 1); 5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 512f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("Error while adjusting inode count on inode %lu\n", 5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp->parent); 5143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = fp->parent; 5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp->done++; 5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return DIRENT_ABORT | DIRENT_CHANGED; 5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent) 5223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 5243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct fix_dotdot_struct fp; 5253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp.fs = fs; 5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp.parent = parent; 5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o fp.done = 0; 5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 531f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent); 5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 5333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY, 5353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 0, fix_dotdot_proc, &fp); 5363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval || !fp.done) { 537f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("Couldn't fix parent of inode %lu: %s\n\n", 5383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dir->ino, retval ? error_message(retval) : 5393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "Couldn't find parent direntory entry"); 5403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_unmark_valid(fs); 5413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dir->dotdot = parent; 5433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return; 5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 5483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * These routines are responsible for expanding a /lost+found if it is 5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * too small. 5503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 5513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct expand_dir_struct { 5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int done; 5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t err; 5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int expand_dir_proc(ext2_filsys fs, 5583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t *blocknr, 5593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int blockcnt, 5603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o void *private) 5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct expand_dir_struct *es = (struct expand_dir_struct *) private; 5633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o blk_t new_blk; 5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o static blk_t last_blk = 0; 5653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char *block; 5663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 5673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (*blocknr) { 5693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o last_blk = *blocknr; 5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_block(fs, last_blk, block_found_map, &new_blk); 5733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 5743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (blockcnt > 0) { 5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_new_dir_block(fs, 0, 0, &block); 5793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 5803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 5813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->done = 1; 5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } else { 5853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o block = malloc(fs->blocksize); 5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!block) { 5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = ENOMEM; 5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 5893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(block, 0, fs->blocksize); 5913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 59250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o retval = ext2fs_write_dir_block(fs, new_blk, block); 5933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) { 5943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es->err = retval; 5953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_ABORT; 5963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o free(block); 5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *blocknr = new_blk; 599f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_block_bitmap(block_found_map, new_blk); 600f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_mark_block_bitmap(fs->block_map, new_blk); 6013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_mark_bb_dirty(fs); 6023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (es->done) 6033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return (BLOCK_CHANGED | BLOCK_ABORT); 6043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o else 6053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return BLOCK_CHANGED; 6063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t expand_directory(ext2_filsys fs, ino_t dir) 6093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 6103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 6113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct expand_dir_struct es; 6123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 6133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!(fs->flags & EXT2_FLAG_RW)) 6153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return EXT2_ET_RO_FILSYS; 6163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_check_directory(fs, dir); 6183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 6193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 6203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es.done = 0; 6223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o es.err = 0; 6233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_block_iterate(fs, dir, BLOCK_FLAG_APPEND, 6253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 0, expand_dir_proc, &es); 6263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (es.err) 6283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return es.err; 6293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!es.done) 6303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return EXT2_ET_EXPAND_DIR_ERR; 6313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 6333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Update the size and block count fields in the inode. 6343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 6353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_read_inode(fs, dir, &inode); 6363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 6373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 6383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_size += fs->blocksize; 6403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o inode.i_blocks += fs->blocksize / 512; 6413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 642f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o e2fsck_write_inode(fs, dir, &inode, "expand_directory"); 6433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 6453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 6483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 649