This source file includes following definitions.
- undelfs_shutdown
- undelfs_get_path
- undelfs_lsdel_proc
- undelfs_loaddel
- undelfs_opendir
- undelfs_readdir
- undelfs_closedir
- undelfs_open
- undelfs_close
- undelfs_dump_read
- undelfs_read
- undelfs_getindex
- undelfs_stat_int
- undelfs_lstat
- undelfs_fstat
- undelfs_chdir
- undelfs_lseek
- undelfs_getid
- undelfs_nothingisopen
- undelfs_free
- undelfs_init
- com_err
- vfs_init_undelfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 #include <config.h>
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <ext2fs/ext2_fs.h>
52 #include <ext2fs/ext2fs.h>
53 #include <ctype.h>
54
55 #include "lib/global.h"
56
57 #include "lib/util.h"
58 #include "lib/widget.h"
59 #include "lib/vfs/xdirentry.h"
60 #include "lib/vfs/utilvfs.h"
61 #include "lib/vfs/vfs.h"
62
63 #include "undelfs.h"
64
65
66
67
68
69
70 #define READDIR_PTR_INIT 0
71
72 #define undelfs_stat undelfs_lstat
73
74
75
76 struct deleted_info
77 {
78 ext2_ino_t ino;
79 unsigned short mode;
80 unsigned short uid;
81 unsigned short gid;
82 unsigned long size;
83 time_t dtime;
84 int num_blocks;
85 int free_blocks;
86 };
87
88 struct lsdel_struct
89 {
90 ext2_ino_t inode;
91 int num_blocks;
92 int free_blocks;
93 int bad_blocks;
94 };
95
96 typedef struct
97 {
98 int f_index;
99 char *buf;
100 int error_code;
101 off_t pos;
102 off_t current;
103 gboolean finished;
104 ext2_ino_t inode;
105 int bytes_read;
106 off_t size;
107
108
109 char *dest_buffer;
110 size_t count;
111 } undelfs_file;
112
113
114
115
116
117
118 static char *ext2_fname;
119 static ext2_filsys fs = NULL;
120 static struct lsdel_struct lsd;
121 static struct deleted_info *delarray;
122 static int num_delarray, max_delarray;
123 static char *block_buf;
124 static const char *undelfserr = N_ ("undelfs: error");
125 static int readdir_ptr;
126 static int undelfs_usage;
127
128 static struct vfs_s_subclass undelfs_subclass;
129 static struct vfs_class *vfs_undelfs_ops = VFS_CLASS (&undelfs_subclass);
130
131
132
133
134
135 static void
136 undelfs_shutdown (void)
137 {
138 if (fs)
139 ext2fs_close (fs);
140 fs = NULL;
141 MC_PTR_FREE (ext2_fname);
142 MC_PTR_FREE (delarray);
143 MC_PTR_FREE (block_buf);
144 }
145
146
147
148 static void
149 undelfs_get_path (const vfs_path_t *vpath, char **fsname, char **file)
150 {
151 const char *p, *dirname;
152
153 dirname = vfs_path_get_last_path_str (vpath);
154
155
156
157
158
159
160 *fsname = NULL;
161
162 if (strncmp (dirname, "undel://", 8) != 0)
163 return;
164
165 dirname += 8;
166
167
168
169 if (*dirname == '\0')
170 return;
171
172 p = dirname + strlen (dirname);
173 #if 0
174
175
176 if (p - dirname > 2 && IS_PATH_SEP (p[-1]) && p[-2] == '.')
177 *(p = p - 2) = 0;
178 #endif
179
180 while (p > dirname)
181 {
182 if (IS_PATH_SEP (*p))
183 {
184 char *tmp;
185
186 *file = g_strdup (p + 1);
187 tmp = g_strndup (dirname, p - dirname);
188 *fsname = g_strconcat ("/dev/", tmp, (char *) NULL);
189 g_free (tmp);
190 return;
191 }
192 p--;
193 }
194 *file = g_strdup ("");
195 *fsname = g_strconcat ("/dev/", dirname, (char *) NULL);
196 }
197
198
199
200 static int
201 undelfs_lsdel_proc (ext2_filsys _fs, blk_t *block_nr, int blockcnt, void *private)
202 {
203 struct lsdel_struct *_lsd = (struct lsdel_struct *) private;
204 (void) blockcnt;
205 _lsd->num_blocks++;
206
207 if (*block_nr < _fs->super->s_first_data_block || *block_nr >= _fs->super->s_blocks_count)
208 {
209 _lsd->bad_blocks++;
210 return BLOCK_ABORT;
211 }
212
213 if (!ext2fs_test_block_bitmap (_fs->block_map, *block_nr))
214 _lsd->free_blocks++;
215
216 return 0;
217 }
218
219
220
221
222
223
224
225 static int
226 undelfs_loaddel (void)
227 {
228 int retval, count;
229 ext2_ino_t ino;
230 struct ext2_inode inode;
231 ext2_inode_scan scan;
232
233 max_delarray = 100;
234 num_delarray = 0;
235 delarray = g_try_malloc (sizeof (struct deleted_info) * max_delarray);
236 if (!delarray)
237 {
238 message (D_ERROR, undelfserr, "%s", _ ("not enough memory"));
239 return 0;
240 }
241 block_buf = g_try_malloc (fs->blocksize * 3);
242 if (!block_buf)
243 {
244 message (D_ERROR, undelfserr, "%s", _ ("while allocating block buffer"));
245 goto free_delarray;
246 }
247 retval = ext2fs_open_inode_scan (fs, 0, &scan);
248 if (retval != 0)
249 {
250 message (D_ERROR, undelfserr, _ ("open_inode_scan: %d"), retval);
251 goto free_block_buf;
252 }
253 retval = ext2fs_get_next_inode (scan, &ino, &inode);
254 if (retval != 0)
255 {
256 message (D_ERROR, undelfserr, _ ("while starting inode scan %d"), retval);
257 goto error_out;
258 }
259 count = 0;
260 while (ino)
261 {
262 if ((count++ % 1024) == 0)
263 vfs_print_message (_ ("undelfs: loading deleted files information %d inodes"), count);
264 if (inode.i_dtime == 0)
265 goto next;
266
267 if (S_ISDIR (inode.i_mode))
268 goto next;
269
270 lsd.inode = ino;
271 lsd.num_blocks = 0;
272 lsd.free_blocks = 0;
273 lsd.bad_blocks = 0;
274
275 retval = ext2fs_block_iterate (fs, ino, 0, block_buf, undelfs_lsdel_proc, &lsd);
276 if (retval)
277 {
278 message (D_ERROR, undelfserr, _ ("while calling ext2_block_iterate %d"), retval);
279 goto next;
280 }
281 if (lsd.free_blocks && !lsd.bad_blocks)
282 {
283 if (num_delarray >= max_delarray)
284 {
285 struct deleted_info *delarray_new =
286 g_try_realloc (delarray, sizeof (struct deleted_info) * (max_delarray + 50));
287 if (!delarray_new)
288 {
289 message (D_ERROR, undelfserr, "%s",
290 _ ("no more memory while reallocating array"));
291 goto error_out;
292 }
293 delarray = delarray_new;
294 max_delarray += 50;
295 }
296
297 delarray[num_delarray].ino = ino;
298 delarray[num_delarray].mode = inode.i_mode;
299 delarray[num_delarray].uid = inode.i_uid;
300 delarray[num_delarray].gid = inode.i_gid;
301 delarray[num_delarray].size = inode.i_size;
302 delarray[num_delarray].dtime = inode.i_dtime;
303 delarray[num_delarray].num_blocks = lsd.num_blocks;
304 delarray[num_delarray].free_blocks = lsd.free_blocks;
305 num_delarray++;
306 }
307
308 next:
309 retval = ext2fs_get_next_inode (scan, &ino, &inode);
310 if (retval)
311 {
312 message (D_ERROR, undelfserr, _ ("while doing inode scan %d"), retval);
313 goto error_out;
314 }
315 }
316 readdir_ptr = READDIR_PTR_INIT;
317 ext2fs_close_inode_scan (scan);
318 return 1;
319
320 error_out:
321 ext2fs_close_inode_scan (scan);
322 free_block_buf:
323 MC_PTR_FREE (block_buf);
324 free_delarray:
325 MC_PTR_FREE (delarray);
326 return 0;
327 }
328
329
330
331 static void *
332 undelfs_opendir (const vfs_path_t *vpath)
333 {
334 char *file, *f = NULL;
335 const char *class_name;
336
337 class_name = vfs_path_get_last_path_vfs (vpath)->name;
338 undelfs_get_path (vpath, &file, &f);
339 if (file == NULL)
340 {
341 g_free (f);
342 return 0;
343 }
344
345
346 g_free (f);
347
348 if (!ext2_fname || strcmp (ext2_fname, file))
349 {
350 undelfs_shutdown ();
351 ext2_fname = file;
352 }
353 else
354 {
355
356 readdir_ptr = READDIR_PTR_INIT;
357 g_free (file);
358 return fs;
359 }
360
361 if (ext2fs_open (ext2_fname, 0, 0, 0, unix_io_manager, &fs))
362 {
363 message (D_ERROR, undelfserr, _ ("Cannot open file %s"), ext2_fname);
364 return 0;
365 }
366 vfs_print_message ("%s", _ ("undelfs: reading inode bitmap..."));
367 if (ext2fs_read_inode_bitmap (fs))
368 {
369 message (D_ERROR, undelfserr, _ ("Cannot load inode bitmap from:\n%s"), ext2_fname);
370 goto quit_opendir;
371 }
372 vfs_print_message ("%s", _ ("undelfs: reading block bitmap..."));
373 if (ext2fs_read_block_bitmap (fs))
374 {
375 message (D_ERROR, undelfserr, _ ("Cannot load block bitmap from:\n%s"), ext2_fname);
376 goto quit_opendir;
377 }
378
379 if (!undelfs_loaddel ())
380 goto quit_opendir;
381 vfs_print_message (_ ("%s: done."), class_name);
382 return fs;
383 quit_opendir:
384 vfs_print_message (_ ("%s: failure"), class_name);
385 ext2fs_close (fs);
386 fs = NULL;
387 return 0;
388 }
389
390
391
392 static struct vfs_dirent *
393 undelfs_readdir (void *vfs_info)
394 {
395 struct vfs_dirent *dirent;
396
397 if (vfs_info != fs)
398 {
399 message (D_ERROR, undelfserr, "%s", _ ("vfs_info is not fs!"));
400 return NULL;
401 }
402 if (readdir_ptr == num_delarray)
403 return NULL;
404 if (readdir_ptr < 0)
405 dirent = vfs_dirent_init (NULL, readdir_ptr == -2 ? "." : "..", 0);
406 else
407 {
408 char dirent_dest[MC_MAXPATHLEN];
409
410 g_snprintf (dirent_dest, MC_MAXPATHLEN, "%ld:%d", (long) delarray[readdir_ptr].ino,
411 delarray[readdir_ptr].num_blocks);
412 dirent = vfs_dirent_init (NULL, dirent_dest, 0);
413 }
414 readdir_ptr++;
415
416 return dirent;
417 }
418
419
420
421 static int
422 undelfs_closedir (void *vfs_info)
423 {
424 (void) vfs_info;
425 return 0;
426 }
427
428
429
430
431 static void *
432 undelfs_open (const vfs_path_t *vpath, int flags, mode_t mode)
433 {
434 char *file, *f = NULL;
435 ext2_ino_t inode, i;
436 undelfs_file *p = NULL;
437 (void) flags;
438 (void) mode;
439
440
441 undelfs_get_path (vpath, &file, &f);
442 if (file == NULL)
443 {
444 g_free (f);
445 return 0;
446 }
447
448 if (!ext2_fname || strcmp (ext2_fname, file))
449 {
450 message (D_ERROR, undelfserr, "%s", _ ("You have to chdir to extract files first"));
451 g_free (file);
452 g_free (f);
453 return 0;
454 }
455 inode = atol (f);
456
457
458 for (i = 0; i < (ext2_ino_t) num_delarray; i++)
459 {
460 if (inode != delarray[i].ino)
461 continue;
462
463
464 p = (undelfs_file *) g_try_malloc (((gsize) sizeof (undelfs_file)));
465 if (!p)
466 {
467 g_free (file);
468 g_free (f);
469 return 0;
470 }
471 p->buf = g_try_malloc (fs->blocksize);
472 if (!p->buf)
473 {
474 g_free (p);
475 g_free (file);
476 g_free (f);
477 return 0;
478 }
479 p->inode = inode;
480 p->finished = FALSE;
481 p->f_index = i;
482 p->error_code = 0;
483 p->pos = 0;
484 p->size = delarray[i].size;
485 }
486 g_free (file);
487 g_free (f);
488 undelfs_usage++;
489 return p;
490 }
491
492
493
494 static int
495 undelfs_close (void *vfs_info)
496 {
497 undelfs_file *p = vfs_info;
498 g_free (p->buf);
499 g_free (p);
500 undelfs_usage--;
501 return 0;
502 }
503
504
505
506 static int
507 undelfs_dump_read (ext2_filsys param_fs, blk_t *blocknr, int blockcnt, void *private)
508 {
509 int copy_count;
510 undelfs_file *p = (undelfs_file *) private;
511
512 if (blockcnt < 0)
513 return 0;
514
515 if (*blocknr)
516 {
517 p->error_code = io_channel_read_blk (param_fs->io, *blocknr, 1, p->buf);
518 if (p->error_code)
519 return BLOCK_ABORT;
520 }
521 else
522 memset (p->buf, 0, param_fs->blocksize);
523
524 if (p->pos + (off_t) p->count < p->current)
525 {
526 p->finished = TRUE;
527 return BLOCK_ABORT;
528 }
529 if (p->pos > p->current + param_fs->blocksize)
530 {
531 p->current += param_fs->blocksize;
532 return 0;
533 }
534
535
536 if (p->pos >= p->current)
537 {
538
539
540 if (p->pos + (off_t) p->count <= p->current + param_fs->blocksize)
541 {
542
543 copy_count = p->count;
544 p->finished = (p->count != 0);
545 }
546 else
547 {
548
549 copy_count = param_fs->blocksize - (p->pos - p->current);
550 }
551 memcpy (p->dest_buffer, p->buf + (p->pos - p->current), copy_count);
552 }
553 else
554 {
555
556 if (p->pos + (off_t) p->count < p->current + param_fs->blocksize)
557 {
558 copy_count = (p->pos + p->count) - p->current;
559 p->finished = (p->count != 0);
560 }
561 else
562 {
563 copy_count = param_fs->blocksize;
564 }
565 memcpy (p->dest_buffer, p->buf, copy_count);
566 }
567 p->dest_buffer += copy_count;
568 p->current += param_fs->blocksize;
569 if (p->finished)
570 {
571 return BLOCK_ABORT;
572 }
573 return 0;
574 }
575
576
577
578 static ssize_t
579 undelfs_read (void *vfs_info, char *buffer, size_t count)
580 {
581 undelfs_file *p = vfs_info;
582 int retval;
583
584 p->dest_buffer = buffer;
585 p->current = 0;
586 p->finished = FALSE;
587 p->count = count;
588
589 if (p->pos + (off_t) p->count > p->size)
590 {
591 p->count = p->size - p->pos;
592 }
593 retval = ext2fs_block_iterate (fs, p->inode, 0, NULL, undelfs_dump_read, p);
594 if (retval)
595 {
596 message (D_ERROR, undelfserr, "%s", _ ("while iterating over blocks"));
597 return -1;
598 }
599 if (p->error_code && !p->finished)
600 return 0;
601 p->pos = p->pos + (p->dest_buffer - buffer);
602 return p->dest_buffer - buffer;
603 }
604
605
606
607 static long
608 undelfs_getindex (char *path)
609 {
610 ext2_ino_t inode = atol (path);
611 int i;
612
613 for (i = 0; i < num_delarray; i++)
614 {
615 if (delarray[i].ino == inode)
616 return i;
617 }
618 return -1;
619 }
620
621
622
623 static int
624 undelfs_stat_int (int inode_index, struct stat *buf)
625 {
626 buf->st_dev = 0;
627 buf->st_ino = delarray[inode_index].ino;
628 buf->st_mode = delarray[inode_index].mode;
629 buf->st_nlink = 1;
630 buf->st_uid = delarray[inode_index].uid;
631 buf->st_gid = delarray[inode_index].gid;
632 buf->st_size = delarray[inode_index].size;
633
634 vfs_zero_stat_times (buf);
635 buf->st_atime = delarray[inode_index].dtime;
636 buf->st_ctime = delarray[inode_index].dtime;
637 buf->st_mtime = delarray[inode_index].dtime;
638
639 return 0;
640 }
641
642
643
644 static int
645 undelfs_lstat (const vfs_path_t *vpath, struct stat *buf)
646 {
647 int inode_index;
648 char *file, *f = NULL;
649
650 undelfs_get_path (vpath, &file, &f);
651 if (file == NULL)
652 {
653 g_free (f);
654 return 0;
655 }
656
657
658
659
660
661
662
663 if (!isdigit (*f))
664 {
665 g_free (file);
666 g_free (f);
667 return -1;
668 }
669
670 if (!ext2_fname || strcmp (ext2_fname, file))
671 {
672 g_free (file);
673 g_free (f);
674 message (D_ERROR, undelfserr, "%s", _ ("You have to chdir to extract files first"));
675 return 0;
676 }
677 inode_index = undelfs_getindex (f);
678 g_free (file);
679 g_free (f);
680
681 if (inode_index == -1)
682 return -1;
683
684 return undelfs_stat_int (inode_index, buf);
685 }
686
687
688
689 static int
690 undelfs_fstat (void *vfs_info, struct stat *buf)
691 {
692 undelfs_file *p = vfs_info;
693
694 return undelfs_stat_int (p->f_index, buf);
695 }
696
697
698
699 static int
700 undelfs_chdir (const vfs_path_t *vpath)
701 {
702 char *file, *f = NULL;
703 int fd;
704
705 undelfs_get_path (vpath, &file, &f);
706 if (file == NULL)
707 {
708 g_free (f);
709 return (-1);
710 }
711
712
713
714
715 fd = open (file, O_RDONLY);
716 if (fd == -1)
717 {
718 message (D_ERROR, undelfserr, _ ("Cannot open file \"%s\""), file);
719 g_free (f);
720 g_free (file);
721 return -1;
722 }
723 close (fd);
724 g_free (f);
725 g_free (file);
726 return 0;
727 }
728
729
730
731
732 static off_t
733 undelfs_lseek (void *vfs_info, off_t offset, int whence)
734 {
735 (void) vfs_info;
736 (void) offset;
737 (void) whence;
738
739 return -1;
740 }
741
742
743
744 static vfsid
745 undelfs_getid (const vfs_path_t *vpath)
746 {
747 char *fname = NULL, *fsname;
748 gboolean ok;
749
750 undelfs_get_path (vpath, &fsname, &fname);
751 ok = fsname != NULL;
752
753 g_free (fname);
754 g_free (fsname);
755
756 return ok ? (vfsid) fs : NULL;
757 }
758
759
760
761 static gboolean
762 undelfs_nothingisopen (vfsid id)
763 {
764 (void) id;
765
766 return (undelfs_usage == 0);
767 }
768
769
770
771 static void
772 undelfs_free (vfsid id)
773 {
774 (void) id;
775
776 undelfs_shutdown ();
777 }
778
779
780
781 #ifdef ENABLE_NLS
782 static int
783 undelfs_init (struct vfs_class *me)
784 {
785 (void) me;
786
787 undelfserr = _ (undelfserr);
788 return 1;
789 }
790 #else
791 # define undelfs_init NULL
792 #endif
793
794
795
796
797
798
799
800
801
802 void
803 com_err (const char *whoami, long err_code, const char *fmt, ...)
804 {
805 va_list ap;
806 char *str;
807
808 va_start (ap, fmt);
809 str = g_strdup_vprintf (fmt, ap);
810 va_end (ap);
811
812 message (D_ERROR, _ ("Ext2lib error"), "%s (%s: %ld)", str, whoami, err_code);
813 g_free (str);
814 }
815
816
817
818 void
819 vfs_init_undelfs (void)
820 {
821
822 memset (&undelfs_subclass, 0, sizeof (undelfs_subclass));
823
824 vfs_init_class (vfs_undelfs_ops, "undelfs", VFSF_UNKNOWN, "undel");
825 vfs_undelfs_ops->init = undelfs_init;
826 vfs_undelfs_ops->open = undelfs_open;
827 vfs_undelfs_ops->close = undelfs_close;
828 vfs_undelfs_ops->read = undelfs_read;
829 vfs_undelfs_ops->opendir = undelfs_opendir;
830 vfs_undelfs_ops->readdir = undelfs_readdir;
831 vfs_undelfs_ops->closedir = undelfs_closedir;
832 vfs_undelfs_ops->stat = undelfs_stat;
833 vfs_undelfs_ops->lstat = undelfs_lstat;
834 vfs_undelfs_ops->fstat = undelfs_fstat;
835 vfs_undelfs_ops->chdir = undelfs_chdir;
836 vfs_undelfs_ops->lseek = undelfs_lseek;
837 vfs_undelfs_ops->getid = undelfs_getid;
838 vfs_undelfs_ops->nothingisopen = undelfs_nothingisopen;
839 vfs_undelfs_ops->free = undelfs_free;
840 vfs_register_class (vfs_undelfs_ops);
841 }
842
843