lnbackup 2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ class FreeSpaceCalc
2
+ def initialize( path, free_files=0, free_blocks=10, log=nil )
3
+ @log = log
4
+ @stat = FileSystem.stat(path)
5
+
6
+ if (free_blocks.class == String) and (free_blocks =~ /^(\d+)%$/)
7
+ free_blocks = @stat.blocks * $1.to_i / 100
8
+ else
9
+ free_blocks = free_blocks.to_i rescue 100
10
+ end
11
+ # vzdy nechame alespon 100 volnych bloku (typicky blok=4kB)
12
+ @free_blocks = free_blocks < 100 ? 100 : free_blocks
13
+
14
+ if (free_files.class == String) and (free_files =~ /^(\d+)%$/)
15
+ free_files = @stat.files * $1.to_i / 100
16
+ else
17
+ free_files = free_files.to_i rescue 100
18
+ end
19
+ # vzdy nechame alespon 100 volnych inodu (pokud dojdou, fs se umi prekne
20
+ # podelat a ani fsck z toho nema radost)
21
+ @free_files = free_files < 100 ? 100 : free_files
22
+ end
23
+
24
+ def much_used?
25
+ @stat = FileSystem.stat(@stat.path)
26
+ if Process.euid == 0
27
+ if (@stat.blocks_free < @free_blocks) or (@stat.files_free < @free_files)
28
+ @log.debug { "FreeSpaceCalc: much used (euid=#{Process.euid}) (#{@stat.blocks_free} < #{@free_blocks}) or (#{@stat.files_free} < #{@free_files})" }
29
+ return true
30
+ end
31
+ else
32
+ if (@stat.blocks_avail < @free_blocks) or (@stat.files_avail < @free_files)
33
+ @log.debug { "FreeSpaceCalc: much used (euid=#{Process.euid}) (#{@stat.blocks_avail} < #{@free_blocks}) or (#{@stat.files_avail} < #{@free_files})" }
34
+ return true
35
+ end
36
+ end
37
+ return false
38
+ end
39
+
40
+ def get_free
41
+ @stat = FileSystem.stat(@stat.path)
42
+ return [ @stat.blocks_free, @stat.files_free ]
43
+ end
44
+
45
+ def can_backup?( path )
46
+ begin
47
+ @stat = FileSystem.stat(@stat.path)
48
+ if Process.euid == 0
49
+ if (@stat.blocks_free < @free_blocks) or (@stat.files_free < @free_files) or
50
+ (File.size(path) >= ( @stat.block_size * (@stat.blocks_free-@free_blocks) ))
51
+
52
+ @log.debug { "FreeSpaceCalc: (euid=#{Process.euid}) can't backup #{path} size #{File.size(path)}" }
53
+ @log.debug { "FreeSpaceCalc: blocks avail: #{@stat.blocks_free} should have: #{@free_blocks}" }
54
+ @log.debug { "FreeSpaceCalc: files avail: #{@stat.files_free} should have: #{@free_files}" }
55
+ return false
56
+ end
57
+ else
58
+ if (@stat.blocks_avail < @free_blocks) or (@stat.files_avail < @free_files) or
59
+ (File.size(path) >= ( @stat.block_size * (@stat.blocks_avail-@free_blocks) ))
60
+
61
+ @log.debug { "FreeSpaceCalc: (euid=#{Process.euid}) can't backup #{path} size #{File.size(path)}" }
62
+ @log.debug { "FreeSpaceCalc: blocks avail: #{@stat.blocks_avail} should have: #{@free_blocks}" }
63
+ @log.debug { "FreeSpaceCalc: files avail: #{@stat.files_avail} should have: #{@free_files}" }
64
+ return false
65
+ end
66
+ end
67
+ return true
68
+ rescue Errno::ENOENT # pokud soubor, ktery kontrolujeme prestal existovat,
69
+ # podminka je trivialne splnena
70
+ return true
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,123 @@
1
+ class File
2
+ TOO_BIG = 1024 * 1024 * 2 # 2MB
3
+
4
+ # a variant of syscopy, that propagates exception Errno::ENOSPC
5
+ # and handles some extra error states
6
+ #
7
+ def File.syscopy2 from, to
8
+ fsize = size(from)
9
+ fsize = 1024 if fsize < 512
10
+ fsize = TOO_BIG if fsize > TOO_BIG
11
+ fmode = stat(from).mode
12
+ tpath = to
13
+ not_exist = !exist?(tpath)
14
+ begin
15
+ from = open(from, "r")
16
+ from.binmode
17
+ to = open(to, "w")
18
+ to.binmode
19
+
20
+ while true
21
+ r = from.sysread(fsize)
22
+ rsize = r.size
23
+ w = 0
24
+ while w < rsize
25
+ t = to.syswrite(r[w, rsize - w])
26
+ w += t
27
+ end
28
+ end
29
+ rescue EOFError
30
+ ret = true
31
+ rescue Errno::ENOSPC
32
+ raise
33
+ rescue
34
+ ret = false
35
+ ensure
36
+ begin; to.close; rescue; end
37
+ begin; from.close; rescue; end
38
+ end
39
+ chmod(fmode, tpath) if not_exist
40
+ ret
41
+ end
42
+ end
43
+
44
+ class Hash
45
+ # "aktualizace" hashe jinou hashi: existujici klice jsou prepsany,
46
+ # neexistujici pridany a to cele rekurzivne po hashich
47
+ def append( hash )
48
+ hash.each_pair do |k,v|
49
+ if self.has_key?(k)
50
+ case v
51
+ when Hash
52
+ self[k].append(v)
53
+ else
54
+ self[k] = v
55
+ end
56
+ else
57
+ self[k] = v
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ class SysCopyFailure < StandardError
64
+ end
65
+
66
+ class MakeSpaceFailure < StandardError
67
+ attr_accessor :code
68
+ def initialize(code)
69
+ @code = code
70
+ super
71
+ end
72
+ end
73
+
74
+ class Date
75
+ # formatovani data do cesty pro zalohu
76
+ def backup_dir(hourly)
77
+ if hourly
78
+ "%d/%02d/%02d-%02d" % [year, month, day, Time.now.hour]
79
+ else
80
+ "%d/%02d/%02d" % [year, month, day]
81
+ end
82
+ end
83
+ end
84
+
85
+ module Find
86
+ #
87
+ # reimplementace funkce "find" s osetrenim vyjimky Errno::EOVERFLOW, ktera minimalne
88
+ # na ruby1.6 nastava pri zachazeni (napr. stat) se souborem o velikosti >2GB
89
+ #
90
+ # pruchod je udelan pomoci zasobniku s hloubkou, aby bylo mozne usetrit pamet
91
+ #
92
+ def Find.find3(*path)
93
+ path.collect!{|d| [d.dup,0]}
94
+ while temp = path.shift
95
+ catch(:prune) do
96
+ (file, depth) = temp
97
+ yield [file, depth]
98
+ begin
99
+ if File.lstat(file).directory? then
100
+ d = Dir.open(file)
101
+ begin
102
+ for f in d
103
+ next if f == "." or f == ".."
104
+ if File::ALT_SEPARATOR and file =~ /^(?:[\/\\]|[A-Za-z]:[\/\\]?)$/ then
105
+ f = file + f
106
+ elsif file == "/" then
107
+ f = "/" + f
108
+ else
109
+ f = File.join(file, f)
110
+ end
111
+ path.unshift [f, depth+1]
112
+ end
113
+ ensure
114
+ d.close
115
+ end
116
+ end
117
+ rescue Errno::ENOENT, Errno::EACCES, Errno::EOVERFLOW
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+
@@ -0,0 +1,3 @@
1
+ module LnBackup
2
+ VERSION=2.1
3
+ end
data/lib/lnbackup.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'lnbackup/backup.rb'
2
+ require 'lnbackup/freespace.rb'
3
+ require 'lnbackup/util.rb'
4
+ require 'lnbackup/version.rb'
5
+
6
+ require 'find'
7
+ require 'date'
8
+ #require 'ftools'
9
+ require 'fileutils'
10
+ begin
11
+ require 'filesystem'
12
+ rescue LoadError
13
+ require 'sys/filesystem'
14
+ include Sys
15
+ FileSystem = Filesystem
16
+ end
17
+
18
+
19
+ require 'logger'
20
+ require 'time'
21
+
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lnbackup
3
+ version: !ruby/object:Gem::Version
4
+ version: '2.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Martin Povolny
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-08 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! "\nLnbackup is a hardlink backup system for hard drives. \n\nLnbackup
15
+ operates in a way similar to the '--link-dest' switch in rsync.\n\nIt creates incremental
16
+ backups using hardlinks so that each backup seems like a full backup. Additionaly
17
+ it can make (using hardlinks) bootable mirror from the latest backup.\n\nObviously
18
+ the target filesystem of lnbackup needs to support hardlinks.\n\nIt's run on ~200
19
+ servers for several years and it is considered stable.\n\nRead the man page for
20
+ more information."
21
+ email: martin.povolny@gmail.com
22
+ executables: []
23
+ extensions: []
24
+ extra_rdoc_files: []
25
+ files:
26
+ - lib/lnbackup.rb
27
+ - lib/lnbackup/version.rb
28
+ - lib/lnbackup/freespace.rb
29
+ - lib/lnbackup/backup.rb
30
+ - lib/lnbackup/util.rb
31
+ - bin/lnbackup
32
+ - bin/lnumount
33
+ - bin/lnmount
34
+ - bin/lnstat
35
+ - bin/pc_backup
36
+ - bin/sql_backup.sh
37
+ homepage: https://github.com/martinpovolny/lnbackup
38
+ licenses: []
39
+ post_install_message:
40
+ rdoc_options:
41
+ - --title
42
+ - Lnbackup -- hardlink backup system for hard drives.
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 1.8.24
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: Hardlink backup system for hard drives.
63
+ test_files: []