fsinv 0.1.2

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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YzM2OGFhZGJlOWI5MmRjZDQyOWE4Y2E1NjgyYjk1ZDMxZTA3ZDVjMw==
5
+ data.tar.gz: !binary |-
6
+ YWU5MjBiMDc5NTgzMDI5OWZlZDM4NDBkYmZhNTQ1Mjk2M2EyZmY3NQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ OWY5ZDk3NTJkMTVkYTYzOGU2ZTFiNDdhNjNmZjk1ZWJkNzczNjcyYmNiN2U4
10
+ NzUxNWQzYzcwYzcwMmEyYTM3MTQ1ZTM5NWVjM2EyN2NkY2UzMzdkYTU3NDUx
11
+ YTRkOWM5MDFjYjNmOGRlZmI5N2E3OGI5N2FjY2E5ZjM4ZDgzZWE=
12
+ data.tar.gz: !binary |-
13
+ MjRhMzFjNDY0NjcwZjNiNTRmMDVmYzUxZDE4MjJjZDUxMTNhZTUwMjc4NzIw
14
+ ZTAyNThiZTU1NWY4MWVjNDgyNTA2MDMwOGFhNDY3NTA0YWYwYzIzMjk5ZGI5
15
+ M2QzMjM5ODliMzFlNzIzYmYzZDRjN2I2YTVjMjZlOWY0YWEyZWI=
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.bin
2
+ *.yaml
3
+ *.json
4
+ *.xml
5
+ *.db
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fsinv.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Maximilian Irro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # fsinv: file system inventory tool
2
+
3
+ imagine a very detailed README message here (please?)
4
+
5
+ ## Installation
6
+
7
+ Just run ```gem install fsinv```
8
+
9
+ ## Usage of the executable
10
+
11
+ Usage: fsinv.rb basepath1 [basepath2 [basepath3 [...]]] [options]
12
+
13
+ fsinv is used to index file systems. By default for each file/directory the size
14
+ in bytes as well as creation time (ctime) and modification time (mtime) are indexed.
15
+
16
+ Files additionally have their mime type, magic file description (see 'man file'),
17
+ OSX Finder tags (kMDItemUserTags) if run on osx, and a special 'fshugo' extended
18
+ file attribute (used by https://github.com/mpgirro/fshugo) stored as well.
19
+
20
+ Directories have also their xattr (osx, fshugo) stored, as well as a count of their
21
+ direct children files (file_count), direct children directories (dir_count) and a
22
+ general children item count (all dir/item count throughout their descendent hierarchie
23
+ tree)
24
+
25
+ Note that some files are ignored (like .AppleDouble, .DS_Store, Thumbs.db, etc.)
26
+ Additionally, some directories will only have reduced indizes, for their content
27
+ is huge of files, yet they are of lesser interest (like .git, .wine, etc.)
28
+ On OSX system, some items appear as files yet are in fact directories (.app, .bundle)
29
+ They will be marked as directories, but will only have their size calculated. Their
30
+ inner file hierarchie is also of lesser interrest.
31
+
32
+ Specific options:
33
+
34
+ -a, --all Save in all formats to the default destinations.
35
+ Equal to -b -j -q -x -y. Use -n to change the
36
+ file names of all target at once
37
+
38
+ -b, --binary [FILE] Dump iventory data stuctures in binary format.
39
+ Default destination is inventory.bin
40
+
41
+ -c, --crc32 Calculate CRC32 checksum for each file
42
+
43
+ -d, --db [FILE] Save inventory as SQLite database.
44
+ Default destination is inventory.db
45
+
46
+ -j, --json [FILE] Save inventory in JSON file format.
47
+ Default destination is inventory.json
48
+
49
+ -m, --md5 Calculate MD5 hashes for each file
50
+
51
+ -n, --name NAME This will change the name of the output files.
52
+ Default is 'inventory'. Specific targets for
53
+ file formats will overwrite this.
54
+
55
+ -p, --print FORMAT Print a format to stdout (json|yaml|xml)
56
+
57
+ -s, --silent Run in silent mode. No output or non-critical
58
+ error messages will be printed
59
+
60
+ -v, --verbose Run verbosely. This will output processed
61
+ filenames and error messages too
62
+
63
+ -x, --xml [FILE] Save inventory in XML file format.
64
+ Default destination is inventory.xml
65
+
66
+ -y, --yaml [FILE] Save inventory in YAML file format.
67
+ Default destination is inventory.yaml
68
+
69
+ -h, --help Show this message
70
+
71
+ ## Usage as a library
72
+
73
+ Note: You must set ```Fsinv.options``` before using any Methods/Classes.
data/bin/fsinv ADDED
@@ -0,0 +1,420 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding : utf-8 -*-
3
+
4
+ require 'optparse'
5
+
6
+ require 'fsinv'
7
+
8
+ DEFAULT_NAME = "inventory"
9
+ USAGE = "Usage: fsinv basepath1 [basepath2 [basepath3 [...]]] [options]"
10
+
11
+ Fsinv.options = {}
12
+ OptionParser.new do |opts|
13
+ opts.banner = USAGE
14
+ opts.separator ""
15
+ opts.separator "fsinv is used to index file systems. By default for each file/directory the size"
16
+ opts.separator "in bytes as well as creation time (ctime) and modification time (mtime) are indexed."
17
+ opts.separator ""
18
+ opts.separator "Files additionally have their mime type, magic file description (see 'man file'),"
19
+ opts.separator "OSX Finder tags (kMDItemUserTags) if run on osx, and a special 'fshugo' extended"
20
+ opts.separator "file attribute (used by https://github.com/mpgirro/fshugo) stored as well."
21
+ opts.separator ""
22
+ opts.separator "Directories have also their xattr (osx, fshugo) stored, as well as a count of their"
23
+ opts.separator "direct children files (file_count), direct children directories (dir_count) and a"
24
+ opts.separator "general children item count (all dir/item count throughout their descendent hierarchie"
25
+ opts.separator "tree)"
26
+ opts.separator ""
27
+ opts.separator "Multiple file system hierarchie trees can be indexed simultaniously, by using more than"
28
+ opts.separator "one basepath (see the usage)"
29
+ opts.separator ""
30
+ opts.separator "Note that some files are ignored (like .AppleDouble, .DS_Store, Thumbs.db, etc.)"
31
+ opts.separator "Additionally, some directories will only have reduced indizes (e.g. only their byte size,"
32
+ opts.separator "yet no children file list), for their content is huge of files, yet they are of lesser"
33
+ opts.separator "interest (like .git, .wine, etc.)"
34
+ opts.separator ""
35
+ opts.separator "On OSX system, some items appear as files yet are in fact directories (.app, .bundle)"
36
+ opts.separator "They will be marked as directories, but will only have their sizes calculated. Their"
37
+ opts.separator "inner file hierarchie is also of lesser interrest."
38
+ opts.separator ""
39
+ opts.separator "Specific options:"
40
+ opts.separator ""
41
+
42
+ opts.on("-a", "--all", "Save in all formats to the default destinations.
43
+ Equal to -b -j -q -x -y. Use -n to change the
44
+ file names of all target at once") do |all_flag|
45
+ Fsinv.options[:binary] = true
46
+ Fsinv.options[:json] = true
47
+ Fsinv.options[:db] = true
48
+ Fsinv.options[:xml] = true
49
+ Fsinv.options[:yaml] = true
50
+ end
51
+ opts.separator ""
52
+
53
+ opts.on("--binary [FILE]", "Dump iventory data stuctures in binary format.
54
+ Default destination is ~/#{DEFAULT_NAME}.bin") do |binary_file|
55
+ Fsinv.options[:binary] = true
56
+ Fsinv.options[:binary_file] = binary_file
57
+ end
58
+ opts.separator ""
59
+
60
+ opts.on("--crc32", "Calculate CRC32 checksum for each file") do |crc|
61
+ Fsinv.options[:crc32] = true
62
+ end
63
+ opts.separator ""
64
+
65
+ opts.on("--db [FILE]", "Save inventory as SQLite database.
66
+ Default destination is ~/#{DEFAULT_NAME}.db") do |sql_file|
67
+ Fsinv.options[:db] = true
68
+ Fsinv.options[:db_file] = sql_file
69
+ end
70
+ opts.separator ""
71
+
72
+ opts.on_tail("-h", "--help", "Show this message") do
73
+ puts opts
74
+ exit
75
+ end
76
+ opts.separator ""
77
+
78
+ opts.on("-j", "--json [FILE]", "Save inventory in JSON file format.
79
+ Default destination is ~/#{DEFAULT_NAME}.json") do |json_file|
80
+ Fsinv.options[:json] = true
81
+ Fsinv.options[:json_file] = json_file
82
+ end
83
+ opts.separator ""
84
+
85
+ opts.on("--md5", "Calculate MD5 hash for each file") do |md5|
86
+ Fsinv.options[:md5] = true
87
+ end
88
+ opts.separator ""
89
+
90
+ opts.on("-n", "--name NAME", "This will change the name of the output files.
91
+ Default is '#{DEFAULT_NAME}'. Specific targets for
92
+ file formats will overwrite this.") do |name|
93
+ Fsinv.options[:name] = name
94
+ end
95
+ opts.separator ""
96
+
97
+ opts.on("-p", "--print FORMAT", [:json, :yaml, :xml], "Print a format to stdout (json|yaml|xml)") do |format|
98
+ Fsinv.options[:print] = true
99
+ Fsinv.options[:print_format] = format
100
+ end
101
+ opts.separator ""
102
+
103
+ opts.on("-s", "--silent", "Run in silent mode. No output or non-critical
104
+ error messages will be printed") do |s|
105
+ Fsinv.options[:silent] = s
106
+ end
107
+ opts.separator ""
108
+
109
+ opts.on("-v", "--verbose", "Run verbosely. This will output processed
110
+ filenames and error messages too") do |v|
111
+ Fsinv.options[:verbose] = v
112
+ end
113
+ opts.separator ""
114
+
115
+ opts.on_tail("--version", "Show version") do
116
+ puts ::Version.join('.')
117
+ exit
118
+ end
119
+ opts.separator ""
120
+
121
+ opts.on("--xml [FILE]", "Save inventory in XML file format.
122
+ Default destination is ~/#{DEFAULT_NAME}.xml") do |xml_file|
123
+ Fsinv.options[:xml] = true
124
+ Fsinv.options[:xml_file] = xml_file
125
+ end
126
+ opts.separator ""
127
+
128
+ opts.on("--yaml [FILE]", "Save inventory in YAML file format.
129
+ Default destination is ~/#{DEFAULT_NAME}.yaml") do |yaml_file|
130
+ Fsinv.options[:yaml] = true
131
+ Fsinv.options[:yaml_file] = yaml_file
132
+ end
133
+ opts.separator ""
134
+
135
+ end.parse! # do the parsing. do it now!
136
+
137
+ #p Fsinv.options
138
+ #p ARGV
139
+
140
+ if ARGV[0].nil?
141
+ puts "No basepath provided. At least one needed"
142
+ puts USAGE
143
+ exit
144
+ end
145
+
146
+ ARGV.each do |arg|
147
+ unless File.directory?(arg)
148
+ puts "Not a directory: #{arg}"
149
+ puts USAGE
150
+ exit
151
+ end
152
+ end
153
+
154
+ if Fsinv.options[:crc32]
155
+ begin
156
+ require 'digest/crc32'
157
+ rescue
158
+ puts "You have selected crc32 calculation option. This requires gem 'digest/crc32'."
159
+ puts "Install using 'gem install digest-crc'"
160
+ exit
161
+ end
162
+ end
163
+
164
+ if Fsinv.options[:md5]
165
+ begin
166
+ require 'digest/md5'
167
+ rescue
168
+ puts "You have selected md5 calculation option. This requires gem 'digest/md5'."
169
+ puts "Install using 'gem install digest'"
170
+ exit
171
+ end
172
+ end
173
+
174
+ file_structure = []
175
+ ARGV.each do |basepath|
176
+ file_structure << Fsinv.parse(basepath)
177
+ end
178
+
179
+ inventory = Fsinv::Inventory.new(file_structure)
180
+
181
+ unless Fsinv.options[:silent]
182
+ file_structure.each do |fs_tree|
183
+ size = fs_tree.bytes
184
+ puts "basepath: #{fs_tree.path}"
185
+ puts " size: #{Fsinv.pretty_SI_bytes(size)} (#{size} Bytes)"
186
+ puts " files: #{fs_tree.file_list.length}"
187
+ puts " items: #{fs_tree.item_count}"
188
+ end
189
+ if file_structure.length > 1
190
+ size = inventory.size
191
+ puts "total:"
192
+ puts " size: #{Fsinv.pretty_SI_bytes(size)} (#{size} Bytes)"
193
+ puts " items: #{inventory.item_count}"
194
+ end
195
+ end
196
+
197
+ # this is the default output
198
+ unless (Fsinv.options[:binary] || Fsinv.options[:db] || Fsinv.options[:xml] || Fsinv.options[:yaml]) && Fsinv.options[:json].nil?
199
+ if Fsinv.options[:json_file].nil?
200
+ Fsinv.options[:json_file] = File.join(Dir.home,
201
+ if Fsinv.options[:name].nil?
202
+ "#{DEFAULT_NAME}.json"
203
+ else
204
+ "#{Fsinv.options[:name]}.json"
205
+ end
206
+ )
207
+ end
208
+
209
+ puts "writing JSON to #{Fsinv.options[:json_file]}" unless Fsinv.options[:silent]
210
+
211
+ begin
212
+ require 'json'
213
+
214
+ # monkey-patch for "JSON::NestingError: nesting is too deep"
215
+ module JSON
216
+ class << self
217
+ def parse(source, opts = {})
218
+ opts = ({:max_nesting => 100}).merge(opts)
219
+ Parser.new(source, opts).parse
220
+ end
221
+ end
222
+ end
223
+
224
+ json_data = Fsinv.inventory_to_json(inventory)
225
+
226
+ unless json_data.nil?
227
+ begin
228
+ file = File.open(Fsinv.options[:json_file], 'w')
229
+ file.write(json_data)
230
+ rescue
231
+ puts "error writing JSON file"
232
+ ensure
233
+ file.close unless file.nil?
234
+ end
235
+ end
236
+ rescue LoadError
237
+ puts "gem 'json' needed for JSON creation. Install using 'gem install json'"
238
+ end
239
+ end
240
+
241
+ if Fsinv.options[:yaml]
242
+ if Fsinv.options[:yaml_file].nil?
243
+ Fsinv.options[:yaml_file] = File.join(Dir.home,
244
+ if Fsinv.options[:name].nil?
245
+ "#{DEFAULT_NAME}.yaml"
246
+ else
247
+ "#{Fsinv.options[:name]}.yaml"
248
+ end
249
+ )
250
+ end
251
+ puts "writing YAML to #{Fsinv.options[:yaml_file]}" unless Fsinv.options[:silent]
252
+ yaml_data = Fsinv.inventory_to_yaml(inventory)
253
+ unless yaml_data.nil?
254
+ begin
255
+ file = File.open(Fsinv.options[:yaml_file], 'w')
256
+ file.write(yaml_data)
257
+ rescue
258
+ puts "error writing YAML file"
259
+ ensure
260
+ file.close unless file.nil?
261
+ end
262
+ end
263
+ end
264
+
265
+ if Fsinv.options[:binary]
266
+ if Fsinv.options[:binary_file].nil?
267
+ Fsinv.options[:binary_file] = File.join(Dir.home,
268
+ if Fsinv.options[:name].nil?
269
+ "#{DEFAULT_NAME}.bin"
270
+ else
271
+ "#{Fsinv.options[:name]}.bin"
272
+ end
273
+ )
274
+ end
275
+ puts "writing binary dump to #{Fsinv.options[:binary_file]}" unless Fsinv.options[:silent]
276
+ begin
277
+ file = File.open(Fsinv.options[:binary_file], 'wb')
278
+ file.write(Marshal.dump(inventory))
279
+ rescue
280
+ puts "error writing binary dump file"
281
+ ensure
282
+ file.close unless file.nil?
283
+ end
284
+ end
285
+
286
+ if Fsinv.options[:db]
287
+ if Fsinv.options[:db_file].nil?
288
+ Fsinv.options[:db_file] = File.join(Dir.home,
289
+ if Fsinv.options[:name].nil?
290
+ "#{DEFAULT_NAME}.db"
291
+ else
292
+ "#{Fsinv.options[:name]}.db"
293
+ end
294
+ )
295
+ end
296
+
297
+ puts "writing database dump to #{Fsinv.options[:db_file]}" unless Fsinv.options[:silent]
298
+ `rm #{Fsinv.options[:db_file]}` if File.exists?(Fsinv.options[:db_file])
299
+
300
+ begin
301
+
302
+ require 'active_record'
303
+
304
+ ActiveRecord::Base.establish_connection(
305
+ :adapter => "sqlite3",
306
+ :database => Fsinv.options[:db_file]
307
+ )
308
+
309
+ ActiveRecord::Schema.define do
310
+
311
+ create_table :file_structures, force: true do |t|
312
+ t.datetime :created_at
313
+ t.datetime :updated_at
314
+ t.string :path
315
+ t.integer :bytes
316
+ t.datetime :ctime
317
+ t.datetime :mtime
318
+ t.string :entity_type
319
+ t.integer :file_count
320
+ t.integer :item_count
321
+ t.string :osx_tags
322
+ t.string :fshugo_tags
323
+ t.integer :mimetype
324
+ t.integer :magicdescr
325
+ end
326
+
327
+ create_table :fshugo_tags, force: true do |t|
328
+ t.string :tag
329
+ end
330
+
331
+ create_table :magic_descriptions, force: true do |t|
332
+ t.string :magicdescr
333
+ end
334
+
335
+ create_table :mime_types, force: true do |t|
336
+ t.string :mimetype
337
+ end
338
+
339
+ create_table :osx_tags, force: true do |t|
340
+ t.string :tag
341
+ end
342
+
343
+ end
344
+
345
+ class MimeType < ActiveRecord::Base
346
+ attr_accessor :mimetype
347
+ end
348
+
349
+ class MagicDescription < ActiveRecord::Base
350
+ attr_accessor :magicdescr
351
+ end
352
+
353
+ class FshugoTag < ActiveRecord::Base
354
+ attr_accessor :tag
355
+ end
356
+
357
+ class OsxTag < ActiveRecord::Base
358
+ attr_accessor :tag
359
+ end
360
+
361
+ class FileStructure < ActiveRecord::Base
362
+ attr_accessor :path, :bytes, :ctime, :mtime, :entity_type
363
+ attr_accessor :file_count, :item_count # used if referencing a directory
364
+ attr_accessor :mimetype, :magicdescr # used if referencing a file
365
+ attr_accessor :osx_tags, :fshugo_tags
366
+
367
+ serialize :osx_tags,Array # tags is text type, make it behave like an array
368
+ serialize :fshugo_tags,Array # tags is text type, make it behave like an array
369
+ end
370
+
371
+ inventory.mime_tab.val_map.each { |id, val| MimeType.create(:mimetype => val) }
372
+ inventory.magic_tab.val_map.each { |id, val| MagicDescription.create(:magicdescr => val) }
373
+ inventory.fshugo_tab.val_map.each { |id, val| FshugoTag.create(:tag => val) }
374
+ inventory.osx_tab.val_map.each { |id, val| OsxTag.create(:tag => val) }
375
+ inventory.file_structure.each { |fstruct| Fsinv.filestructure_to_db(fstruct) }
376
+
377
+ rescue SQLite3::Exception => e
378
+ puts e
379
+ rescue LoadError
380
+ puts "gem 'active_record' needed for DB creation. Install using 'gem install active_record'"
381
+ end
382
+ end
383
+
384
+ if Fsinv.options[:xml]
385
+ if Fsinv.options[:xml_file].nil?
386
+ Fsinv.options[:xml_file] = File.join(Dir.home,
387
+ if Fsinv.options[:name].nil?
388
+ "#{DEFAULT_NAME}.xml"
389
+ else
390
+ "#{Fsinv.options[:name]}.xml"
391
+ end
392
+ )
393
+ end
394
+
395
+ puts "writing XML to #{Fsinv.options[:xml_file]}" unless Fsinv.options[:silent]
396
+
397
+ #$progressbar = ProgressBar.new(inventory.file_structure.inject{ |arr,item| arr + item.item_count }, :bar, :counter)
398
+ xml_data = Fsinv.inventory_to_xml(inventory)
399
+
400
+ unless xml_data.nil?
401
+ begin
402
+ file = File.open(Fsinv.options[:xml_file], 'w')
403
+ file.write(xml_data)
404
+ rescue
405
+ puts "error writing XML file"
406
+ ensure
407
+ file.close unless file.nil?
408
+ end
409
+ end
410
+ end
411
+
412
+ if Fsinv.options[:print]
413
+ print_data = case Fsinv.options[:print_format]
414
+ when :json then Fsinv.inventory_to_json(inventory)
415
+ when :xml then Fsinv.inventory_to_xml(inventory)
416
+ when :yaml then Fsinv.inventory_to_yaml(inventory)
417
+ else nil
418
+ end
419
+ puts print_data unless print_data.nil?
420
+ end
data/fsinv.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fsinv'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'fsinv'
8
+ spec.version = Fsinv::VERSION
9
+ spec.date = '2014-08-14'
10
+ spec.summary = "file system inventory tool"
11
+ spec.description = "fsinv indexes file systems. It creates a complex inventory of one or more file system hierarchies and supports output formats like JSON, YAML, XML, binary (ruby marshall dump) and SQLite3 db (via active_record)."
12
+ spec.author = "Maximilian Irro"
13
+ spec.email = 'max@disposia.org'
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = ['fsinv']
16
+ spec.homepage = 'https://github.com/mpgirro/fsinv'
17
+ spec.license = 'MIT'
18
+
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.required_ruby_version = '>= 1.9.3'
22
+ spec.add_dependency 'activerecord', '~> 3.2', '>=3.2.12'
23
+ spec.add_dependency 'mime-types', '~> 2.2', '>= 1.21'
24
+ spec.add_dependency 'nokogiri', '~> 1.6', '>= 1.6.2.1'
25
+ spec.add_dependency 'ruby-filemagic', '~> 0.6', '>= 0.6.0'
26
+ spec.add_dependency 'sqlite3', '~> 1.3', '>= 1.3.7'
27
+ spec.add_dependency 'ffi-xattr', '~> 0.1', '>= 0.1.2'
28
+ spec.add_dependency 'digest-crc', '~> 0.4', '>= 0.4.1'
29
+ end
@@ -0,0 +1,101 @@
1
+
2
+ require 'fsinv'
3
+
4
+ module Fsinv
5
+
6
+ class BaseDescription
7
+
8
+ include Fsinv
9
+
10
+ attr_accessor :path,:bytes,:ctime,:mtime,:osx_tags,:fshugo_tags
11
+
12
+ def initialize(path, reduced_scan = false)
13
+ @path = path.encode("UTF-8")
14
+
15
+ @bytes = 0
16
+
17
+ unless reduced_scan # don't do this if we only want to know file sizes (for pseudofiles, .git folders, etc)
18
+ @ctime = File.ctime(path) rescue (puts "error getting creation time for file #{path}" if Fsinv.options[:verbose])
19
+ @mtime = File.ctime(path) rescue (puts "error getting modification time for file #{path}" if Fsinv.options[:verbose])
20
+ @osx_tags = osx_tag_ids(path)
21
+ @fshugo_tags = fshugo_tag_ids(path)
22
+ else
23
+ @osx_tags = []
24
+ @fshugo_tags = []
25
+ end
26
+ end # initialize
27
+
28
+ def to_hash
29
+ p = sanitize_string(@path) rescue "path encoding broken" # there can be ArgumentError and UndefinedConversionError
30
+ h = {
31
+ "path" => p,
32
+ "bytes" => @bytes
33
+ }
34
+ h['ctime'] = @ctime unless @ctime.nil?
35
+ h['mtime'] = @mtime unless @mtime.nil?
36
+ h["osx_tags"] = @osx_tags unless @osx_tags.empty?
37
+ h["fshugo_tags"] = @fshugo_tags unless @fshugo_tags.empty?
38
+ return h
39
+ end # to_hash
40
+
41
+ def as_json(options = { })
42
+ return to_hash
43
+ end
44
+
45
+ def to_json(*a)
46
+ return as_json.to_json(*a )
47
+ end
48
+
49
+ def osx_tag_ids(file_path)
50
+
51
+ # well, we can only that if we are on osx, for the
52
+ # mechanism used is only avalable on that plattform
53
+ return [] unless /darwin/.match(RUBY_PLATFORM) # == osx
54
+
55
+ # if we had problem loading (or installing) ffi-xattr
56
+ # don't do the tags thing at all (fixes FreeBSD bug)
57
+ return [] unless Fsinv.options[:xattr]
58
+
59
+ # array with the kMDItemUserTags strings
60
+ # of the extended file attributes of 'path'
61
+ tags = %x{mdls -name 'kMDItemUserTags' -raw "#{file_path}"|tr -d "()\n"}.split(',').map { |tag|
62
+ tag.strip.gsub(/"(.*?)"/,"\\1")
63
+ }
64
+ # if there are now tags, mdls returns "null" -> we don't want this
65
+ if tags.length == 1 && tags[0] == "null"
66
+ return []
67
+ else
68
+ tag_ids = []
69
+ tags.each do |tag|
70
+ Fsinv.osx_tab.add(tag) unless Fsinv.osx_tab.contains?(tag)
71
+ tag_ids << Fsinv.osx_tab.get_id(tag)
72
+ end
73
+ return tag_ids
74
+ end
75
+ end # osx_tag_ids
76
+
77
+
78
+ def fshugo_tag_ids(file_path)
79
+
80
+ # if we had problem loading (or installing) ffi-xattr
81
+ # don't do the tags thing at all (fixes FreeBSD bug)
82
+ return [] unless Fsinv.options[:xattr]
83
+
84
+ xattr = Xattr.new(file_path)
85
+ unless xattr["fshugo"].nil?
86
+ tags = xattr["fshugo"].split(";")
87
+ tag_ids = []
88
+ tags.each do |tag|
89
+ Fsinv.fshugo_tab.add(tag) unless Fsinv.fshugo_tab.contains?(tag)
90
+ tag_ids << Fsinv.fshugo_tab.get_id(tag)
91
+ end
92
+ return tag_ids
93
+ #return tags
94
+ else
95
+ return []
96
+ end
97
+ end # fshugo_tag_ids
98
+
99
+ end # FileDefinition
100
+
101
+ end # Fsinv