source: rubysleuth/sleuth.rb @ 367

Revision 367, 3.3 KB checked in by henning, 5 months ago (diff)

rubysleuth: 1.9 compat, inode name independence todo

Line 
1require 'fileutils'
2
3# TODO when working with an image created with ntfs-3g one can not count
4#      on the file or directory names being present.
5
6deps = {
7        'ils' => false,
8        'fsstat' => false,
9        'ifind' => false,
10        'icat' => false,
11        'istat' => false
12}
13
14deps.each_key do |dep|
15        ENV['PATH'].split( ':' ).each do |path|
16                begin
17                        if File.stat( "#{path}/#{dep}" )
18                                deps[dep] = true
19                                break
20                        end
21                rescue
22                end
23        end
24end
25
26deps.each_value do |value|
27        raise Exception if not value
28end
29
30module Sleuth
31        $haystack = String.new
32
33        class Image
34                def initialize( image )
35                        begin
36                                raise Exception if not File.stat( image ).readable?
37                        rescue
38                                raise Exception
39                        end
40
41                        $haystack = image
42                        @type = ""
43                end
44
45                # TODO search is crappy
46                # Inode has to be expanded and Directory should inherit from it
47                def searchDir( needle )
48                        matches = []
49
50                        `ils -Am #{$haystack} | grep '#{needle}'`.split( "\n" ).each do |match|
51                                matches.push( Directory.new( match ) )
52                                matches.delete_if do |i| i.type != 100 end
53                        end
54
55                        matches
56                end
57
58                def type
59                        if @type.empty?
60                                @type = `fsstat #{$haystack} | grep Type`.split( ' ' )[3].downcase
61                        end
62
63                        @type
64                end
65        end
66
67        class Directory
68                attr_reader :name, :inode, :mode, :type, :atime
69
70                def initialize( line )
71                        tmp = line.split('|')
72
73                        @name = tmp[1]
74                        @inode = Inode.new( tmp[2].to_i )
75                        @mode = tmp[3]
76                        @type = @mode[2]
77                        @atime = Time.at( tmp[7].to_i )
78
79                        basename = $haystack.gsub( /^\/.+\//, "" )
80                        @name.gsub!( "<#{basename}-", "" )
81                        @name.gsub!( "-dead-#{@inode}>", "" )
82
83                        @path = ""
84                end
85
86                def to_s
87                        "#{name} (#{atime.asctime}) #{inode}"
88                end
89
90                def path
91                        @path = inode.path if @path.empty?
92                        @path
93                end
94
95                def recover( *args )
96                        if args.empty?
97                                inode = Inode.new( self.inode )
98                        else
99                                inode = Inode.new( args[0] )
100                        end
101
102                        FileUtils.mkdir_p( self.path )
103                        `ifind -l -p #{inode} #{$haystack}`.each do |item|
104                                inode = Inode.new( item.split( " " )[2].to_i )
105                                if item[2] == 100
106                                        FileUtils.mkdir_p( inode.path )
107                                        recover( inode )
108                                else
109                                        # TODO would be cool to have sth like this:
110                                        # d.recover do |item| puts item.path end
111#                                       print( "#{inode.path}\n" )
112                                        yield
113                                        begin
114                                                File.stat( inode.path )
115                                        rescue
116                                                `icat #{$haystack} #{inode} > '#{inode.path}'`
117                                        end
118                                end
119                                # TODO dir mtime is not written
120                                # (although it works in tests with irb)
121                                FileUtils.touch( inode.path, :mtime => inode.mtime )
122                        end
123                end
124        end
125
126        class Inode
127                attr_reader :inode
128               
129                def initialize( inode )
130                        @inode = inode
131                        @path = ""
132                        @mtime = 0
133                end
134
135                def to_s
136                        @inode.to_s
137                end
138
139                # TODO do not recover whole path for every file
140                def path
141                        if @path.empty?
142                                name = String.new
143                                parent = inode
144                                tmp = Array.new
145
146                                while name != "."
147                                        tmp.push( name ) if not name.empty?
148                                        out = `istat #{$haystack} #{parent} | egrep "^Parent|^Name"`.split( "\n" )
149                                        name = out[0][6..-1]
150                                        parent = out[1].gsub( /^Par.*ry:\ /, "" ).to_i
151                                end
152
153                                @path = tmp.reverse.join( "/" )
154                        end
155
156                        @path
157                end
158
159                def mtime
160                        if @mtime == 0
161                                out = `istat #{$haystack} #{@inode} | grep 'File Modified'`
162                                out = out.split( "\t" ).last.chomp
163                                @mtime = Time.mktime(
164                                        out[20..23].to_i, # year
165                                        out[4..6], # month
166                                        out[8..9].to_i, # day
167                                        out[11..12].to_i, # hour
168                                        out[14..15].to_i, # min
169                                        out[17..18].to_i #sec
170                                )
171                        end
172
173                        @mtime
174                end
175        end
176end
Note: See TracBrowser for help on using the repository browser.