lsdel.c revision 544349270e4c74a6feb971123884a8cf5052a7ee
1f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/* 2e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o * lsdel.c --- routines to try to help a user recover a deleted file. 3f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * 4e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 5e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o * Theodore Ts'o. This file may be redistributed under the terms of 6e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o * the GNU Public License. 7f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */ 8f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 9f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <stdio.h> 10f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <unistd.h> 11f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <stdlib.h> 12f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <ctype.h> 13f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <string.h> 14f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <time.h> 1550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#ifdef HAVE_ERRNO_H 1650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#include <errno.h> 1750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o#endif 18f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h> 19f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/stat.h> 20f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 21f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include "debugfs.h" 22f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 23f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostruct deleted_info { 24b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o ext2_ino_t ino; 25b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o unsigned short mode; 26b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o unsigned short uid; 27b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o __u64 size; 28b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o time_t dtime; 29b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int num_blocks; 30b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o int free_blocks; 31f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o}; 32f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 33f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostruct lsdel_struct { 34b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o ext2_ino_t inode; 35f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int num_blocks; 36f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int free_blocks; 37f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int bad_blocks; 38f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o}; 39f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 4050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'ostatic int deleted_info_compare(const void *a, const void *b) 41f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 4250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o const struct deleted_info *arg1, *arg2; 43f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 4450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o arg1 = (const struct deleted_info *) a; 4550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o arg2 = (const struct deleted_info *) b; 46f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 47f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return arg1->dtime - arg2->dtime; 48f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 49f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 5050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'ostatic int lsdel_proc(ext2_filsys fs, 5150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o blk_t *block_nr, 52544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int blockcnt EXT2FS_ATTR((unused)), 5350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o void *private) 54f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 55f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct lsdel_struct *lsd = (struct lsdel_struct *) private; 56f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 57f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o lsd->num_blocks++; 58f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 59f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (*block_nr < fs->super->s_first_data_block || 60f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o *block_nr >= fs->super->s_blocks_count) { 61f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o lsd->bad_blocks++; 62f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return BLOCK_ABORT; 63f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 64f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 65f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (!ext2fs_test_block_bitmap(fs->block_map,*block_nr)) 66f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o lsd->free_blocks++; 67f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 68f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return 0; 69f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 70f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 71f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ovoid do_lsdel(int argc, char **argv) 72f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 73f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct lsdel_struct lsd; 74f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct deleted_info *delarray; 75f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int num_delarray, max_delarray; 76f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2_inode_scan scan = 0; 77b044c2e02af46c54206f0f6e29896ab32681a7dbTheodore Ts'o ext2_ino_t ino; 78f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct ext2_inode inode; 79f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o errcode_t retval; 80f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o char *block_buf; 81f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int i; 82e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o long secs = 0; 83e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o char *tmp; 84e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o time_t now = time(0); 857380ac903316c0fe91ed6706eb4d84249a9b348dTheodore Ts'o FILE *out; 86f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 87e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (common_args_process(argc, argv, 1, 2, "ls_deleted_inodes", 88e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o "[secs]", 0)) 89f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 90e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (argc > 1) { 91e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o secs = strtol(argv[1],&tmp,0); 92e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if (*tmp) { 93e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o com_err(argv[0], 0, "Bad time - %s",argv[1]); 94e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o return; 95e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o } 96f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 97f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 98f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o max_delarray = 100; 99f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o num_delarray = 0; 100f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray = malloc(max_delarray * sizeof(struct deleted_info)); 101f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (!delarray) { 102f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o com_err("ls_deleted_inodes", ENOMEM, 103f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o "while allocating deleted information storage"); 104f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o exit(1); 105f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 106f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 107fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o block_buf = malloc(current_fs->blocksize * 3); 108f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (!block_buf) { 109f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o com_err("ls_deleted_inodes", ENOMEM, "while allocating block buffer"); 110f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o goto error_out; 111f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 112f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 113fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o retval = ext2fs_open_inode_scan(current_fs, 0, &scan); 114f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (retval) { 115f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o com_err("ls_deleted_inodes", retval, 116f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o "while opening inode scan"); 117f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o goto error_out; 118f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 119f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 1203e025efc0fb0de0f62be3421aa61c75eedf0d913Theodore Ts'o do { 1213e025efc0fb0de0f62be3421aa61c75eedf0d913Theodore Ts'o retval = ext2fs_get_next_inode(scan, &ino, &inode); 1223e025efc0fb0de0f62be3421aa61c75eedf0d913Theodore Ts'o } while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE); 123f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (retval) { 124f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o com_err("ls_deleted_inodes", retval, 125f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o "while starting inode scan"); 126f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o goto error_out; 127f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 128f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 129f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o while (ino) { 130e1018eeaa3285cd0ca26986d929194c1b577d211Theodore Ts'o if ((inode.i_dtime == 0) || 131544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o (secs && ((unsigned) abs(now - secs) > inode.i_dtime))) 132f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o goto next; 133f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 134f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o lsd.inode = ino; 135f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o lsd.num_blocks = 0; 136f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o lsd.free_blocks = 0; 137f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o lsd.bad_blocks = 0; 138f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 139fc6d9d519aef67735918bf02c0fa8c9222008f76Theodore Ts'o retval = ext2fs_block_iterate(current_fs, ino, 0, block_buf, 140f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o lsdel_proc, &lsd); 141f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (retval) { 142f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o com_err("ls_deleted_inodes", retval, 14389e25cfdbf206d6840dc92385ee839dd850294dbAndreas Dilger "while calling ext2fs_block_iterate"); 144f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o goto next; 145f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 146f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (lsd.free_blocks && !lsd.bad_blocks) { 147f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (num_delarray >= max_delarray) { 148f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o max_delarray += 50; 149f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray = realloc(delarray, 150f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o max_delarray * sizeof(struct deleted_info)); 151f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (!delarray) { 152f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o com_err("ls_deleted_inodes", 153f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ENOMEM, 154f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o "while reallocating array"); 155f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o exit(1); 156f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 157f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 158f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 159f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray[num_delarray].ino = ino; 160f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray[num_delarray].mode = inode.i_mode; 161f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray[num_delarray].uid = inode.i_uid; 162f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray[num_delarray].size = inode.i_size; 16336a43d675ef61d0f5d5b2ad62d2e670c408d14acTheodore Ts'o if (!LINUX_S_ISDIR(inode.i_mode)) 16436a43d675ef61d0f5d5b2ad62d2e670c408d14acTheodore Ts'o delarray[num_delarray].size |= 16536a43d675ef61d0f5d5b2ad62d2e670c408d14acTheodore Ts'o ((__u64) inode.i_size_high << 32); 166f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray[num_delarray].dtime = inode.i_dtime; 167f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray[num_delarray].num_blocks = lsd.num_blocks; 168f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray[num_delarray].free_blocks = lsd.free_blocks; 169f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o num_delarray++; 170f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 171f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 172f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o next: 1733e025efc0fb0de0f62be3421aa61c75eedf0d913Theodore Ts'o do { 174ee753091cf6df32010c5f3ab37bf1326eef18d08Theodore Ts'o retval = ext2fs_get_next_inode(scan, &ino, &inode); 1753e025efc0fb0de0f62be3421aa61c75eedf0d913Theodore Ts'o } while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE); 176f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (retval) { 177f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o com_err("ls_deleted_inodes", retval, 178f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o "while doing inode scan"); 179f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o goto error_out; 180f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 181f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 182f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 1837380ac903316c0fe91ed6706eb4d84249a9b348dTheodore Ts'o out = open_pager(); 1847380ac903316c0fe91ed6706eb4d84249a9b348dTheodore Ts'o 1857380ac903316c0fe91ed6706eb4d84249a9b348dTheodore Ts'o fprintf(out, " Inode Owner Mode Size Blocks Time deleted\n"); 186f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 187f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o qsort(delarray, num_delarray, sizeof(struct deleted_info), 188f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o deleted_info_compare); 189f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 190f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o for (i = 0; i < num_delarray; i++) { 1917380ac903316c0fe91ed6706eb4d84249a9b348dTheodore Ts'o fprintf(out, "%6u %6d %6o %6llu %4d/%4d %s", delarray[i].ino, 192f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray[i].uid, delarray[i].mode, delarray[i].size, 193f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o delarray[i].free_blocks, delarray[i].num_blocks, 19421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o time_to_string(delarray[i].dtime)); 195f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o } 1967380ac903316c0fe91ed6706eb4d84249a9b348dTheodore Ts'o fprintf(out, "%d deleted inodes found.\n", num_delarray); 1977380ac903316c0fe91ed6706eb4d84249a9b348dTheodore Ts'o close_pager(out); 198f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 199f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'oerror_out: 200f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o free(block_buf); 201f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o free(delarray); 202f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (scan) 203f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o ext2fs_close_inode_scan(scan); 204f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return; 205f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 206f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 207f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 208f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 209