time_machine_tools 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/tm_copy +52 -0
  2. data/lib/time_machine_tools.rb +179 -0
  3. metadata +49 -0
data/bin/tm_copy ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--
4
+ # /* ***** BEGIN LICENSE BLOCK *****
5
+ # *
6
+ # * time_machine_tools.rb
7
+ # * Copyright (c) 2012 Colin J. Fuller
8
+ # *
9
+ # * Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ # * of this software and associated documentation files (the Software), to deal
11
+ # * in the Software without restriction, including without limitation the rights
12
+ # * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ # * copies of the Software, and to permit persons to whom the Software is
14
+ # * furnished to do so, subject to the following conditions:
15
+ # *
16
+ # * The above copyright notice and this permission notice shall be included in
17
+ # * all copies or substantial portions of the Software.
18
+ # *
19
+ # * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ # * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ # * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ # * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ # * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ # * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ # * SOFTWARE.
26
+ # *
27
+ # * ***** END LICENSE BLOCK ***** */
28
+ #++
29
+
30
+ require 'time_machine_tools'
31
+
32
+ # usage:
33
+ # tm_copy mountpoint sourcepath destpath
34
+ #
35
+ # where mountpoint is the location to which the backup drive is mounted (e.g. /mnt/my_backup)
36
+ # sourcepath is the source folder you want to copy, specified relative to mountpoint. Its contents
37
+ # will be copied, but the folder itself will not.
38
+ # destpath is the destination folder. The contents of sourcepath will be copied (including
39
+ # subfolders, which will be copied recursively) into destpath.
40
+ #
41
+
42
+ mount_point = ARGV[0]
43
+ source_path = ARGV[1]
44
+ dest_path = ARGV[2]
45
+
46
+ tmc = TimeMachineTools::TMCopier.new(mount_point)
47
+
48
+ origin_path = File.join(mount_point, source_path)
49
+
50
+ tmc.copy_dir(origin_path, dest_path)
51
+
52
+
@@ -0,0 +1,179 @@
1
+ #--
2
+ # /* ***** BEGIN LICENSE BLOCK *****
3
+ # *
4
+ # * time_machine_tools.rb
5
+ # * Copyright (c) 2012 Colin J. Fuller
6
+ # *
7
+ # * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # * of this software and associated documentation files (the Software), to deal
9
+ # * in the Software without restriction, including without limitation the rights
10
+ # * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # * copies of the Software, and to permit persons to whom the Software is
12
+ # * furnished to do so, subject to the following conditions:
13
+ # *
14
+ # * The above copyright notice and this permission notice shall be included in
15
+ # * all copies or substantial portions of the Software.
16
+ # *
17
+ # * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # * SOFTWARE.
24
+ # *
25
+ # * ***** END LICENSE BLOCK ***** */
26
+ #++
27
+
28
+ ##
29
+ # Time machine tools is a utility for copying data off an Apple time machine
30
+ # backup on a system (e.g. linux) that does not support the type of hard links
31
+ # used for the backup.
32
+ #
33
+ # usage (with install through rubygems):
34
+ #
35
+ # gem install time_machine_tools
36
+ # tm_copy mountpoint sourcepath destpath
37
+ #
38
+ # where mountpoint is the location to which the backup drive is mounted (e.g. /mnt/my_backup)
39
+ # sourcepath is the source folder you want to copy, specified relative to mountpoint. Its contents
40
+ # will be copied, but the folder itself will not.
41
+ # destpath is the destination folder. The contents of sourcepath will be copied (including
42
+ # subfolders, which will be copied recursively) into destpath.
43
+ #
44
+
45
+ require 'fileutils'
46
+
47
+ module TimeMachineTools
48
+
49
+ Dirlisting_prefix = "dir_"
50
+ Entries_dir = ".HFS+ Private Directory Data\r"
51
+
52
+
53
+ class TMCopier
54
+
55
+ ##
56
+ # Creates a new TMCopier.
57
+ # @param mount_point the path to which the backup drive is mounted
58
+ # @param path_to_dir_entries the path relative to mount_point that contains the numbered directories for the backup
59
+ # this defaults to the hidden folder ".HFS+ Private Directory Data\r", which to my knowledge
60
+ # is the standard location for time machine backups.
61
+ #
62
+ def initialize(mount_point, path_to_dir_entries=Entries_dir)
63
+
64
+ @path_to_dir_entries = path_to_dir_entries
65
+ @mount_point = mount_point
66
+
67
+ #I think all the linked directories are numbered higher than this.
68
+ @min_link_count = 1000
69
+
70
+ end
71
+
72
+ attr_accessor :min_link_count
73
+
74
+ ##
75
+ # Maps a path that would have existed on the system being backed up to its actual path on the time machine drive.
76
+ # @param path the path to be mapped (which is relative to the root of the filesystem being backed up).
77
+ # @return a string containing the path to the actual location of the directory on the backup drive.
78
+ #
79
+ def get_non_linked_dir_path_for_path(path)
80
+
81
+ #check if the directory exists (either as an actual directory or hard link) or whether we need to get the parent first
82
+
83
+ if File.exist?(path) then
84
+
85
+ #check first if we can go and get it directly
86
+
87
+ if File.directory?(path) then
88
+
89
+ return path
90
+
91
+ end
92
+
93
+ #otherwise, find the index from hard link count
94
+
95
+ index = File.stat(path).nlink
96
+
97
+ final_dir = File.join(@mount_point, @path_to_dir_entries, Dirlisting_prefix + index.to_s)
98
+
99
+ return final_dir
100
+
101
+ end
102
+
103
+ #recursively get the parent directory
104
+
105
+ split_path = File.split(path)
106
+
107
+ parent_path = get_non_linked_dir_path_for_path(split_path[0])
108
+
109
+ get_non_linked_dir_path_for_path(File.join(parent_path, split_path[1]))
110
+
111
+ end
112
+
113
+ ##
114
+ # Copy the contents of the named directory into the named destination.
115
+ # @param origin_path the directory whose *contents* will be copied. The directory itself will not be copied.
116
+ # @param dest_path the directory into which the contents of origin_path will be copied.
117
+ #
118
+ def copy_dir(origin_path, dest_path)
119
+
120
+ p origin_path if $DEBUG
121
+
122
+ real_dir = get_non_linked_dir_path_for_path(origin_path)
123
+
124
+ unless File.exist?(dest_path) and File.directory?(dest_path) then
125
+
126
+ Dir.mkdir(dest_path)
127
+
128
+ end
129
+
130
+ Dir.foreach(real_dir) do |f|
131
+
132
+ next if f == "." or f == ".."
133
+
134
+ full_path= File.join(real_dir, f)
135
+
136
+ #check if this is a hard link to a directory
137
+ if File.exist?(full_path) and (not File.directory?(full_path)) and File.stat(full_path).nlink > @min_link_count then
138
+ full_path = get_non_linked_dir_path_for_path(full_path)
139
+ end
140
+
141
+ if File.directory?(full_path) then
142
+ copy_dir(full_path, File.join(dest_path, f))
143
+ else
144
+
145
+ if File.exist?(full_path) and not File.symlink?(full_path) then
146
+
147
+ FileUtils.cp(full_path, dest_path)
148
+
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+
155
+ nil
156
+
157
+ end
158
+
159
+ end
160
+
161
+ end
162
+
163
+ if __FILE__ == $0 then
164
+
165
+ mount_point = ARGV[0]
166
+ source_path = ARGV[1]
167
+ dest_path = ARGV[2]
168
+
169
+ tmc = TimeMachineTools::TMCopier.new(mount_point)
170
+
171
+ origin_path = File.join(mount_point, source_path)
172
+
173
+ tmc.copy_dir(origin_path, dest_path)
174
+
175
+ end
176
+
177
+
178
+
179
+
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: time_machine_tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Colin J. Fuller
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-30 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Tools that copy data off Apple time machine backups on systems that do
15
+ not support the style of directory hard links used by those backups
16
+ email: cjfuller@gmail.com
17
+ executables:
18
+ - tm_copy
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - lib/time_machine_tools.rb
23
+ - bin/tm_copy
24
+ homepage: http://code.google.com/p/timemachinetools
25
+ licenses:
26
+ - MIT
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ none: false
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 1.8.24
46
+ signing_key:
47
+ specification_version: 3
48
+ summary: Tools for copying data off of Apple time machine backups
49
+ test_files: []