1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker * lsdel.c --- routines to try to help a user recover a deleted file.
3*6a54128fSAndroid Build Coastguard Worker *
4*6a54128fSAndroid Build Coastguard Worker * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
5*6a54128fSAndroid Build Coastguard Worker * Theodore Ts'o. This file may be redistributed under the terms of
6*6a54128fSAndroid Build Coastguard Worker * the GNU Public License.
7*6a54128fSAndroid Build Coastguard Worker */
8*6a54128fSAndroid Build Coastguard Worker
9*6a54128fSAndroid Build Coastguard Worker #include "config.h"
10*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
11*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
12*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
13*6a54128fSAndroid Build Coastguard Worker #include <ctype.h>
14*6a54128fSAndroid Build Coastguard Worker #include <string.h>
15*6a54128fSAndroid Build Coastguard Worker #include <time.h>
16*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_ERRNO_H
17*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
18*6a54128fSAndroid Build Coastguard Worker #endif
19*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
20*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
21*6a54128fSAndroid Build Coastguard Worker
22*6a54128fSAndroid Build Coastguard Worker #include "debugfs.h"
23*6a54128fSAndroid Build Coastguard Worker
24*6a54128fSAndroid Build Coastguard Worker struct deleted_info {
25*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino;
26*6a54128fSAndroid Build Coastguard Worker unsigned short mode;
27*6a54128fSAndroid Build Coastguard Worker __u32 uid;
28*6a54128fSAndroid Build Coastguard Worker __u64 size;
29*6a54128fSAndroid Build Coastguard Worker time_t dtime;
30*6a54128fSAndroid Build Coastguard Worker e2_blkcnt_t num_blocks;
31*6a54128fSAndroid Build Coastguard Worker e2_blkcnt_t free_blocks;
32*6a54128fSAndroid Build Coastguard Worker };
33*6a54128fSAndroid Build Coastguard Worker
34*6a54128fSAndroid Build Coastguard Worker struct lsdel_struct {
35*6a54128fSAndroid Build Coastguard Worker ext2_ino_t inode;
36*6a54128fSAndroid Build Coastguard Worker e2_blkcnt_t num_blocks;
37*6a54128fSAndroid Build Coastguard Worker e2_blkcnt_t free_blocks;
38*6a54128fSAndroid Build Coastguard Worker e2_blkcnt_t bad_blocks;
39*6a54128fSAndroid Build Coastguard Worker };
40*6a54128fSAndroid Build Coastguard Worker
deleted_info_compare(const void * a,const void * b)41*6a54128fSAndroid Build Coastguard Worker static int deleted_info_compare(const void *a, const void *b)
42*6a54128fSAndroid Build Coastguard Worker {
43*6a54128fSAndroid Build Coastguard Worker const struct deleted_info *arg1, *arg2;
44*6a54128fSAndroid Build Coastguard Worker
45*6a54128fSAndroid Build Coastguard Worker arg1 = (const struct deleted_info *) a;
46*6a54128fSAndroid Build Coastguard Worker arg2 = (const struct deleted_info *) b;
47*6a54128fSAndroid Build Coastguard Worker
48*6a54128fSAndroid Build Coastguard Worker return arg1->dtime - arg2->dtime;
49*6a54128fSAndroid Build Coastguard Worker }
50*6a54128fSAndroid Build Coastguard Worker
lsdel_proc(ext2_filsys fs,blk64_t * block_nr,e2_blkcnt_t blockcnt EXT2FS_ATTR ((unused)),blk64_t ref_block EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * private)51*6a54128fSAndroid Build Coastguard Worker static int lsdel_proc(ext2_filsys fs,
52*6a54128fSAndroid Build Coastguard Worker blk64_t *block_nr,
53*6a54128fSAndroid Build Coastguard Worker e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
54*6a54128fSAndroid Build Coastguard Worker blk64_t ref_block EXT2FS_ATTR((unused)),
55*6a54128fSAndroid Build Coastguard Worker int ref_offset EXT2FS_ATTR((unused)),
56*6a54128fSAndroid Build Coastguard Worker void *private)
57*6a54128fSAndroid Build Coastguard Worker {
58*6a54128fSAndroid Build Coastguard Worker struct lsdel_struct *lsd = (struct lsdel_struct *) private;
59*6a54128fSAndroid Build Coastguard Worker
60*6a54128fSAndroid Build Coastguard Worker lsd->num_blocks++;
61*6a54128fSAndroid Build Coastguard Worker
62*6a54128fSAndroid Build Coastguard Worker if (*block_nr < fs->super->s_first_data_block ||
63*6a54128fSAndroid Build Coastguard Worker *block_nr >= ext2fs_blocks_count(fs->super)) {
64*6a54128fSAndroid Build Coastguard Worker lsd->bad_blocks++;
65*6a54128fSAndroid Build Coastguard Worker return BLOCK_ABORT;
66*6a54128fSAndroid Build Coastguard Worker }
67*6a54128fSAndroid Build Coastguard Worker
68*6a54128fSAndroid Build Coastguard Worker if (!ext2fs_test_block_bitmap2(fs->block_map,*block_nr))
69*6a54128fSAndroid Build Coastguard Worker lsd->free_blocks++;
70*6a54128fSAndroid Build Coastguard Worker
71*6a54128fSAndroid Build Coastguard Worker return 0;
72*6a54128fSAndroid Build Coastguard Worker }
73*6a54128fSAndroid Build Coastguard Worker
do_lsdel(int argc,char ** argv,int sci_idx EXT2FS_ATTR ((unused)),void * infop EXT2FS_ATTR ((unused)))74*6a54128fSAndroid Build Coastguard Worker void do_lsdel(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
75*6a54128fSAndroid Build Coastguard Worker void *infop EXT2FS_ATTR((unused)))
76*6a54128fSAndroid Build Coastguard Worker {
77*6a54128fSAndroid Build Coastguard Worker struct lsdel_struct lsd;
78*6a54128fSAndroid Build Coastguard Worker struct deleted_info *delarray;
79*6a54128fSAndroid Build Coastguard Worker int num_delarray, max_delarray;
80*6a54128fSAndroid Build Coastguard Worker ext2_inode_scan scan = 0;
81*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino;
82*6a54128fSAndroid Build Coastguard Worker struct ext2_inode inode;
83*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
84*6a54128fSAndroid Build Coastguard Worker char *block_buf;
85*6a54128fSAndroid Build Coastguard Worker int i;
86*6a54128fSAndroid Build Coastguard Worker long secs = 0;
87*6a54128fSAndroid Build Coastguard Worker char *tmp;
88*6a54128fSAndroid Build Coastguard Worker time_t now;
89*6a54128fSAndroid Build Coastguard Worker FILE *out;
90*6a54128fSAndroid Build Coastguard Worker
91*6a54128fSAndroid Build Coastguard Worker if (common_args_process(argc, argv, 1, 2, "list_deleted_inodes",
92*6a54128fSAndroid Build Coastguard Worker "[secs]", 0))
93*6a54128fSAndroid Build Coastguard Worker return;
94*6a54128fSAndroid Build Coastguard Worker
95*6a54128fSAndroid Build Coastguard Worker if (argc > 1) {
96*6a54128fSAndroid Build Coastguard Worker secs = strtol(argv[1],&tmp,0);
97*6a54128fSAndroid Build Coastguard Worker if (*tmp) {
98*6a54128fSAndroid Build Coastguard Worker com_err(argv[0], 0, "Bad time - %s",argv[1]);
99*6a54128fSAndroid Build Coastguard Worker return;
100*6a54128fSAndroid Build Coastguard Worker }
101*6a54128fSAndroid Build Coastguard Worker }
102*6a54128fSAndroid Build Coastguard Worker
103*6a54128fSAndroid Build Coastguard Worker now = current_fs->now ? current_fs->now : time(0);
104*6a54128fSAndroid Build Coastguard Worker max_delarray = 100;
105*6a54128fSAndroid Build Coastguard Worker num_delarray = 0;
106*6a54128fSAndroid Build Coastguard Worker delarray = malloc(max_delarray * sizeof(struct deleted_info));
107*6a54128fSAndroid Build Coastguard Worker if (!delarray) {
108*6a54128fSAndroid Build Coastguard Worker com_err("ls_deleted_inodes", ENOMEM,
109*6a54128fSAndroid Build Coastguard Worker "while allocating deleted information storage");
110*6a54128fSAndroid Build Coastguard Worker exit(1);
111*6a54128fSAndroid Build Coastguard Worker }
112*6a54128fSAndroid Build Coastguard Worker
113*6a54128fSAndroid Build Coastguard Worker block_buf = malloc(current_fs->blocksize * 3);
114*6a54128fSAndroid Build Coastguard Worker if (!block_buf) {
115*6a54128fSAndroid Build Coastguard Worker com_err("ls_deleted_inodes", ENOMEM, "while allocating block buffer");
116*6a54128fSAndroid Build Coastguard Worker goto error_out;
117*6a54128fSAndroid Build Coastguard Worker }
118*6a54128fSAndroid Build Coastguard Worker
119*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_open_inode_scan(current_fs, 0, &scan);
120*6a54128fSAndroid Build Coastguard Worker if (retval) {
121*6a54128fSAndroid Build Coastguard Worker com_err("ls_deleted_inodes", retval,
122*6a54128fSAndroid Build Coastguard Worker "while opening inode scan");
123*6a54128fSAndroid Build Coastguard Worker goto error_out;
124*6a54128fSAndroid Build Coastguard Worker }
125*6a54128fSAndroid Build Coastguard Worker
126*6a54128fSAndroid Build Coastguard Worker do {
127*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_next_inode(scan, &ino, &inode);
128*6a54128fSAndroid Build Coastguard Worker } while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
129*6a54128fSAndroid Build Coastguard Worker if (retval) {
130*6a54128fSAndroid Build Coastguard Worker com_err("ls_deleted_inodes", retval,
131*6a54128fSAndroid Build Coastguard Worker "while starting inode scan");
132*6a54128fSAndroid Build Coastguard Worker goto error_out;
133*6a54128fSAndroid Build Coastguard Worker }
134*6a54128fSAndroid Build Coastguard Worker
135*6a54128fSAndroid Build Coastguard Worker while (ino) {
136*6a54128fSAndroid Build Coastguard Worker if ((inode.i_dtime == 0) ||
137*6a54128fSAndroid Build Coastguard Worker (secs && (labs(now - secs) > (long) inode.i_dtime)))
138*6a54128fSAndroid Build Coastguard Worker goto next;
139*6a54128fSAndroid Build Coastguard Worker
140*6a54128fSAndroid Build Coastguard Worker lsd.inode = ino;
141*6a54128fSAndroid Build Coastguard Worker lsd.num_blocks = 0;
142*6a54128fSAndroid Build Coastguard Worker lsd.free_blocks = 0;
143*6a54128fSAndroid Build Coastguard Worker lsd.bad_blocks = 0;
144*6a54128fSAndroid Build Coastguard Worker
145*6a54128fSAndroid Build Coastguard Worker if (ext2fs_inode_has_valid_blocks2(current_fs, &inode)) {
146*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_block_iterate3(current_fs, ino,
147*6a54128fSAndroid Build Coastguard Worker BLOCK_FLAG_READ_ONLY,
148*6a54128fSAndroid Build Coastguard Worker block_buf,
149*6a54128fSAndroid Build Coastguard Worker lsdel_proc, &lsd);
150*6a54128fSAndroid Build Coastguard Worker if (retval) {
151*6a54128fSAndroid Build Coastguard Worker com_err("ls_deleted_inodes", retval,
152*6a54128fSAndroid Build Coastguard Worker "while calling ext2fs_block_iterate2");
153*6a54128fSAndroid Build Coastguard Worker goto next;
154*6a54128fSAndroid Build Coastguard Worker }
155*6a54128fSAndroid Build Coastguard Worker }
156*6a54128fSAndroid Build Coastguard Worker if ((lsd.free_blocks && !lsd.bad_blocks) ||
157*6a54128fSAndroid Build Coastguard Worker inode.i_flags & EXT4_INLINE_DATA_FL) {
158*6a54128fSAndroid Build Coastguard Worker if (num_delarray >= max_delarray) {
159*6a54128fSAndroid Build Coastguard Worker max_delarray += 50;
160*6a54128fSAndroid Build Coastguard Worker delarray = realloc(delarray,
161*6a54128fSAndroid Build Coastguard Worker max_delarray * sizeof(struct deleted_info));
162*6a54128fSAndroid Build Coastguard Worker if (!delarray) {
163*6a54128fSAndroid Build Coastguard Worker com_err("ls_deleted_inodes",
164*6a54128fSAndroid Build Coastguard Worker ENOMEM,
165*6a54128fSAndroid Build Coastguard Worker "while reallocating array");
166*6a54128fSAndroid Build Coastguard Worker exit(1);
167*6a54128fSAndroid Build Coastguard Worker }
168*6a54128fSAndroid Build Coastguard Worker }
169*6a54128fSAndroid Build Coastguard Worker
170*6a54128fSAndroid Build Coastguard Worker delarray[num_delarray].ino = ino;
171*6a54128fSAndroid Build Coastguard Worker delarray[num_delarray].mode = inode.i_mode;
172*6a54128fSAndroid Build Coastguard Worker delarray[num_delarray].uid = inode_uid(inode);
173*6a54128fSAndroid Build Coastguard Worker delarray[num_delarray].size = EXT2_I_SIZE(&inode);
174*6a54128fSAndroid Build Coastguard Worker delarray[num_delarray].dtime = (__s32) inode.i_dtime;
175*6a54128fSAndroid Build Coastguard Worker delarray[num_delarray].num_blocks = lsd.num_blocks;
176*6a54128fSAndroid Build Coastguard Worker delarray[num_delarray].free_blocks = lsd.free_blocks;
177*6a54128fSAndroid Build Coastguard Worker num_delarray++;
178*6a54128fSAndroid Build Coastguard Worker }
179*6a54128fSAndroid Build Coastguard Worker
180*6a54128fSAndroid Build Coastguard Worker next:
181*6a54128fSAndroid Build Coastguard Worker do {
182*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_next_inode(scan, &ino, &inode);
183*6a54128fSAndroid Build Coastguard Worker } while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
184*6a54128fSAndroid Build Coastguard Worker if (retval) {
185*6a54128fSAndroid Build Coastguard Worker com_err("ls_deleted_inodes", retval,
186*6a54128fSAndroid Build Coastguard Worker "while doing inode scan");
187*6a54128fSAndroid Build Coastguard Worker goto error_out;
188*6a54128fSAndroid Build Coastguard Worker }
189*6a54128fSAndroid Build Coastguard Worker }
190*6a54128fSAndroid Build Coastguard Worker
191*6a54128fSAndroid Build Coastguard Worker out = open_pager();
192*6a54128fSAndroid Build Coastguard Worker
193*6a54128fSAndroid Build Coastguard Worker fprintf(out, " Inode Owner Mode Size Blocks Time deleted\n");
194*6a54128fSAndroid Build Coastguard Worker
195*6a54128fSAndroid Build Coastguard Worker qsort(delarray, num_delarray, sizeof(struct deleted_info),
196*6a54128fSAndroid Build Coastguard Worker deleted_info_compare);
197*6a54128fSAndroid Build Coastguard Worker
198*6a54128fSAndroid Build Coastguard Worker for (i = 0; i < num_delarray; i++) {
199*6a54128fSAndroid Build Coastguard Worker fprintf(out, "%6u %6d %6o %6llu %6lld/%6lld %s",
200*6a54128fSAndroid Build Coastguard Worker delarray[i].ino,
201*6a54128fSAndroid Build Coastguard Worker delarray[i].uid, delarray[i].mode,
202*6a54128fSAndroid Build Coastguard Worker (unsigned long long) delarray[i].size,
203*6a54128fSAndroid Build Coastguard Worker (long long) delarray[i].free_blocks,
204*6a54128fSAndroid Build Coastguard Worker (long long) delarray[i].num_blocks,
205*6a54128fSAndroid Build Coastguard Worker time_to_string(delarray[i].dtime));
206*6a54128fSAndroid Build Coastguard Worker }
207*6a54128fSAndroid Build Coastguard Worker fprintf(out, "%d deleted inodes found.\n", num_delarray);
208*6a54128fSAndroid Build Coastguard Worker close_pager(out);
209*6a54128fSAndroid Build Coastguard Worker
210*6a54128fSAndroid Build Coastguard Worker error_out:
211*6a54128fSAndroid Build Coastguard Worker free(block_buf);
212*6a54128fSAndroid Build Coastguard Worker free(delarray);
213*6a54128fSAndroid Build Coastguard Worker if (scan)
214*6a54128fSAndroid Build Coastguard Worker ext2fs_close_inode_scan(scan);
215*6a54128fSAndroid Build Coastguard Worker return;
216*6a54128fSAndroid Build Coastguard Worker }
217*6a54128fSAndroid Build Coastguard Worker
218*6a54128fSAndroid Build Coastguard Worker
219*6a54128fSAndroid Build Coastguard Worker
220