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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
require 'byteback/restore_file'
module Byteback
class Restore
def self.find(byteback_root, snapshot, paths)
x = Byteback::Restore.new(byteback_root)
x.snapshot = snapshot
x.find(paths)
return x
end
#
# This takes a string or array of strings as an argument, and QP encodes
# each argument. This is for safe parsing of spaces etc at the remote end.
#
# Returns an array of encoded strings.
#
def self.encode_args(args)
[args].flatten.collect{|s| [s].pack("M").gsub(" ","=20").gsub("=\n","")}
end
#
# This takes a string or array of strings, each of which is quoted
# printable, and unpacks it.
#
# Returns an array of decoded strings.
#
def self.decode_args(args)
[args].flatten.collect{|s| (s + "=\n").unpack("M")}.flatten
end
def initialize(byteback_root)
#
# We use expand_path here to make sure we have a full path, with no
# trailing slash.
#
@byteback_root = File.expand_path(byteback_root)
@now = Time.now
@snapshot = "*"
@results = []
end
def snapshot=(r)
if r =~ /^[a-z0-9:\+\*\-]+$/i
@snapshot = r
else
puts "*** Warning: Bad snapshot #{r.inspect}"
end
end
def results
@results
end
def find(paths, opts = {})
results = []
#
# Make sure we've an array, and that we get rid of any ".." nonsense.
#
paths = [paths].flatten.collect{|p| File.expand_path(p, "/")}
seen = []
@results = paths.collect do |path|
Dir.glob(File.expand_path(File.join(@byteback_root, @snapshot, path))).collect do |f|
restore_file = Byteback::RestoreFile.new(f, @byteback_root, @now)
end
end.flatten
#
# If we want an unpruned list, return it now.
#
if opts == true or (opts.is_a?(Hash) and opts[:verbose])
@results = @results.sort{|a,b| [a.path, a.snapshot_time] <=> [b.path, b.snapshot_time]}
return @results
end
@results = @results.sort{|a,b| [a.path, b.snapshot_time] <=> [b.path, a.snapshot_time]}
pruned_results = []
@results.each do |r|
if (opts.is_a?(Hash) and opts[:all])
pruned_results << r unless pruned_results.include?(r)
else
pruned_results << r unless pruned_results.any?{|pr| pr.path == r.path}
end
end
@results = pruned_results
end
def list
heading = %w(snapshot modestring size uid gid mtime path)
listings = [heading]
@results.sort.each do |r|
listing = heading.collect{|m| r.__send__(m.to_sym).to_s }
if r.symlink?
listing[-1] << " -> "+r.readlink
end
listings << listing
end
field_sizes = [0]*heading.length
listings.each do |fields|
fields.each_with_index do |field, i|
field_sizes[i] = (field_sizes[i] > field.length) ? field_sizes[i] : field.length
end
end
fmt = field_sizes.collect{|i| "%-#{i}.#{i}s"}.join(" ")
bar = "-"*field_sizes.inject(field_sizes.length){|m,s| m+=s}
output = []
listings.each do |fields|
output << sprintf(fmt, *fields)
if bar
output << bar
bar = nil
end
end
return output.join("\n")
end
end
end
|