manageiq-smartstate 0.3.4 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0c4e0ae5df27aeb31c51bf3cd62249be2b2a53d8
4
- data.tar.gz: d8dc954b070111eb849bf9c0b1af5c2e01b5ee7d
2
+ SHA256:
3
+ metadata.gz: f517cfb3cafa62840376ce516426e2af1b2180a8733cca57f0e6e212a1596f0f
4
+ data.tar.gz: b443f7a19ecfdfafc1c50432853fa22f789c33674f99cb54873dda3cb21b85ac
5
5
  SHA512:
6
- metadata.gz: e59d6441ae21c768e7b25e046dd66395638d21845a4b8465a7c19b0c15a04c43aeaa7a7b0820d483a81562c77726f894a2b82fd39e59ac36e5391e734a3cb66c
7
- data.tar.gz: fef77f29b8e8f2409c0320ea7463d8cd1ccb55fcb31b9cfcad3e187f300b784999b0d94736617b8084db7ea337a30185f08a4183e5bcdf8b73ad6270a5bf8e2c
6
+ metadata.gz: 807d2fb11644d303a15818020dfed093e28a5111f0bd3ec4944f6ee4ee42b6b8cb626f7322d6b59c78db84056d6665332c5f35fdc1011e15955f5bc458b7631b
7
+ data.tar.gz: 20e52907b15cf35f57a9f90104a0323b1ff3406b86668b54ed22db68e7408ac9c3cb9efbcb7468742b09c2c3e25add71979583253e658b714577125ff28548fc
data/Gemfile CHANGED
@@ -3,7 +3,7 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in manageiq-smartstate.gemspec
4
4
  gemspec
5
5
 
6
- gem "manageiq-gems-pending", :git => "https://github.com/ManageIQ/manageiq-gems-pending.git", :branch => "master"
6
+ gem "manageiq-gems-pending", :git => "https://github.com/ManageIQ/manageiq-gems-pending.git", :branch => "ivanchuk"
7
7
 
8
8
  # Modified gems for vmware_web_service. Setting sources here since they are git references
9
9
  gem "handsoap", "~>0.2.5", :require => false, :git => "https://github.com/ManageIQ/handsoap.git", :tag => "v0.2.5-5"
@@ -309,23 +309,27 @@ module LinuxMount
309
309
  #
310
310
  components.each do |c|
311
311
  ncp = File.join(cp, c)
312
- #
313
- # Each file system know how to check for,
314
- # and read its own links.
315
- #
316
- fs, lp = getFsPathBase(ncp)
317
- if fs.fileSymLink?(lp)
318
- sl = getSymLink(fs, lp)
319
- if sl[0, 1] == '/'
320
- cp = sl
321
- else
322
- cp = File.join(cp, sl)
323
- end
312
+ cp = follow_all_symlinks(ncp)
313
+ end
314
+ cp
315
+ end
316
+
317
+ def follow_all_symlinks(link_ptr)
318
+ #
319
+ # Each filesystem knows how to check for,
320
+ # and read its own links.
321
+ #
322
+ no_more_links = false
323
+ until no_more_links
324
+ filesys, tmp_link_ptr = getFsPathBase(link_ptr)
325
+ if filesys.fileSymLink?(tmp_link_ptr)
326
+ symlink = getSymLink(filesys, tmp_link_ptr)
327
+ link_ptr = symlink[0, 1] == '/' ? symlink : File.join(File.dirname(link_ptr), symlink)
324
328
  else
325
- cp = ncp
329
+ no_more_links = true
326
330
  end
327
331
  end
328
- (cp)
332
+ link_ptr
329
333
  end
330
334
 
331
335
  def getSymLink(fs, p)
@@ -282,7 +282,7 @@ module NTFS
282
282
 
283
283
  @runSpec.each_slice(2) do |lcn, len|
284
284
  total_clusters += len
285
- next unless total_clusters > start_vcn
285
+ next unless lcn && len && total_clusters > start_vcn
286
286
 
287
287
  start = lcn + (vcn - (total_clusters - len))
288
288
  count = len - (start - lcn)
@@ -1,5 +1,5 @@
1
1
  module ManageIQ
2
2
  module Smartstate
3
- VERSION = "0.3.4".freeze
3
+ VERSION = "0.3.9".freeze
4
4
  end
5
5
  end
@@ -0,0 +1,133 @@
1
+ module FindClassMethods
2
+ # Return directory entries matching specified glob pattern
3
+ #
4
+ # @param glob_pattern [String] pattern to match
5
+ # @param flags [Integer] file match flags
6
+ # @yield block invoked with each match if specified
7
+ #
8
+ # @see VfsRealFile.fnmatch
9
+ # @see FindClassMethods#dir_and_glob which does most of the work regarding globbing
10
+ # @see FindClassMethods#find which retrieves stats information & dir entries for found files
11
+ #
12
+ def self.glob(glob_pattern, filesys, flags = 0)
13
+ @fs = filesys
14
+ return [] unless (glob = dir_and_glob(glob_pattern))
15
+
16
+ ra = []
17
+ find(@search_path, glob_depth(glob)) do |p|
18
+ if (p = check_file(p, glob, flags))
19
+ block_given? ? yield(p) : ra << p
20
+ end
21
+ end
22
+ ra.sort_by(&:downcase)
23
+ end
24
+
25
+ #
26
+ # Determine if the file returned from "find" will be used or skipped.
27
+ #
28
+ def self.check_file(file, glob, flags)
29
+ return nil if file == @search_path
30
+
31
+ if @search_path == File::SEPARATOR
32
+ file.sub!(File::SEPARATOR, "")
33
+ else
34
+ file.sub!("#{@search_path}#{File::SEPARATOR}", "")
35
+ end
36
+
37
+ return nil if file == "" || !File.fnmatch(glob, file, flags)
38
+
39
+ @specified_path ? File.join(@specified_path, file) : file
40
+ end
41
+
42
+ #
43
+ # Modified version of Find.find:
44
+ # - Accepts only a single path.
45
+ # - Can be restricted by depth - optimization for glob searches.
46
+ #
47
+ # @param path [String] starting directory of the find
48
+ # @param max_depth [Integer] max number of levels to decend befroelookup
49
+ # @yield files found
50
+ #
51
+ def self.find(path, max_depth = nil)
52
+ block_given? || (return enum_for(__method__, path, max_depth))
53
+
54
+ depths = [0]
55
+ paths = [path.dup]
56
+
57
+ while (file = paths.shift)
58
+ depth = depths.shift
59
+ yield file.dup.taint
60
+ next if max_depth && depth + 1 > max_depth
61
+
62
+ get_dir_entries(file).each do |f|
63
+ f = File.join(file, f)
64
+ paths.unshift f.untaint
65
+ depths.unshift depth + 1
66
+ end
67
+ end
68
+ end
69
+
70
+ def self.get_dir_entries(directory)
71
+ return [] unless @fs.fileExists?(directory) && @fs.fileDirectory?(directory)
72
+
73
+ files = @fs.dirEntries(directory)
74
+ files -= [".", ".."]
75
+ files.sort!
76
+ files.reverse_each
77
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
78
+ $log.info "find: while-loop @fs.dirEntries #{directory} returned an error"
79
+ []
80
+ end
81
+
82
+ GLOB_CHARS = '*?[{'.freeze
83
+ def self.glob_str?(str)
84
+ str.gsub(/\\./, "X").count(GLOB_CHARS) != 0
85
+ end
86
+
87
+ # Returns files matching glob pattern
88
+ #
89
+ # @api private
90
+ # @param glob_pattern [String,Regex] pattern to search for
91
+ # @return [String] paths to files found
92
+ #
93
+ def self.dir_and_glob(glob_pattern)
94
+ stripped_path = glob_pattern.sub(/^[a-zA-Z]:/, "")
95
+ glob_path = Pathname.new(stripped_path)
96
+ @search_path = File::SEPARATOR
97
+ @specified_path = File::SEPARATOR
98
+
99
+ unless glob_path.absolute?
100
+ @search_path = Dir.getwd
101
+ @specified_path = nil
102
+ end
103
+
104
+ components = path_components(glob_path)
105
+ @search_path = File.expand_path(@search_path, "/")
106
+ @fs.fileExists?(@search_path) ? File.join(components) : nil
107
+ end
108
+
109
+ def self.path_components(glob_path, search_path = @search_path)
110
+ components = glob_path.each_filename.to_a
111
+ while (comp = components.shift)
112
+ if glob_str?(comp)
113
+ components.unshift(comp)
114
+ break
115
+ end
116
+ @search_path = File.join(search_path, comp)
117
+ @specified_path = @specified_path ? File.join(@specified_path, comp) : comp
118
+ end
119
+ components
120
+ end
121
+
122
+ # Return max levels which glob pattern may resolve to
123
+ #
124
+ # @api private
125
+ # @param glob_pattern [String,Regex] pattern to search for
126
+ # @return [Integer] max levels which pattern may match
127
+ def self.glob_depth(glob_pattern)
128
+ path_components = Pathname(glob_pattern).each_filename.to_a
129
+ return nil if path_components.include?('**')
130
+
131
+ path_components.length
132
+ end
133
+ end
@@ -1,6 +1,7 @@
1
1
  require 'time'
2
2
  require 'metadata/util/win32/peheader'
3
3
  require 'metadata/util/win32/versioninfo'
4
+ require 'metadata/util/find_class_methods'
4
5
  require 'util/miq-xml'
5
6
  require 'ostruct'
6
7
  require 'util/miq-encode'
@@ -54,29 +55,35 @@ class MD5deep
54
55
  def scan_glob(filename)
55
56
  filename.tr!("\\", "/")
56
57
  startDir = File.dirname(filename)
57
- globPattern = File.basename(filename)
58
58
  @xml.root.add_attribute("base_path", startDir)
59
- @fs.chdir(startDir)
59
+ path_prefix = startDir[0, 2]
60
+ @drive_letter = path_prefix.match?(/^\w\:/) ? path_prefix : ""
60
61
 
61
62
  # First check if we are passed a fully qualifed file name
62
63
  if @fs.fileExists?(filename)
63
- isDir?(filename) ? process_dir_as_file(startDir, globPattern, @xml.root) : processFile(startDir, globPattern, @xml.root)
64
+ base_file = File.basename(filename)
65
+ isDir?(filename) ? process_dir_as_file(startDir, base_file, @xml.root) : processFile(startDir, base_file, @xml.root)
64
66
  else
65
67
  # If the file is not found then process the data as a glob pattern.
66
- @fs.dirGlob(globPattern) do |f|
67
- # $log.info "Glob file found: [#{f}]"
68
- # Passing "startDir" as the first parameter is a work-around for issues
69
- # when scanning Win VMs from Linux where the path returned from dirGlob
70
- # do not include the drive letter.
71
- # Below is the original line
72
- # processFile(File.dirname(f), File.basename(f), @xml.root)
73
- processFile(startDir, File.basename(f), @xml.root)
74
- end
68
+ process_each_glob_file(filename)
75
69
  end
76
70
  @xml
77
71
  end
78
72
 
73
+ def process_each_glob_file(file_name)
74
+ FindClassMethods.glob(file_name, @fs) do |f|
75
+ # Passing "startDir" as the first parameter is a work-around for issues
76
+ # when scanning Win VMs from Linux where the path returned from dirGlob
77
+ # do not include the drive letter.
78
+ processFile(File.dirname(f), File.basename(f), @xml.root)
79
+ end
80
+ rescue => err
81
+ $log.error "process_each_glob_file: Exception #{err} rescued"
82
+ $log.debug err.backtrace.join("\n")
83
+ end
84
+
79
85
  def read_fs(path, xmlNode)
86
+ @drive_letter = @drive_letter.nil? ? "" : @drive_letter
80
87
  if @fs
81
88
  @fs.dirForeach(path) { |x| processFile(path, x, xmlNode) }
82
89
  @fs.dirForeach(path) { |x| processDir(path, x, xmlNode) }
@@ -91,7 +98,7 @@ class MD5deep
91
98
 
92
99
  def processDir(path, x, xmlNode)
93
100
  if x != "." && x != ".."
94
- currFile = File.join(path, x)
101
+ currFile = File.join(@drive_letter, path, x)
95
102
 
96
103
  begin
97
104
  if File.directory?(currFile)
@@ -110,7 +117,7 @@ class MD5deep
110
117
 
111
118
  def process_dir_as_file(path, x, xml_node)
112
119
  if x != "." && x != ".."
113
- curr_dir = File.join(path, x)
120
+ curr_dir = File.join(@drive_letter, path, x)
114
121
  if isDir?(curr_dir)
115
122
  xml_file_node = xml_node.add_element("file", "name" => x, "fqname" => curr_dir)
116
123
  stat_hash = {}
@@ -122,39 +129,43 @@ class MD5deep
122
129
 
123
130
  def processFile(path, x, xmlNode)
124
131
  if (@opts.exclude.include?(x) == false) && x[0..0] != "$"
125
- currFile = File.join(path, x)
132
+ currFile = File.join(@drive_letter, path, x)
126
133
 
127
134
  begin
128
135
  # unless File.directory?(currFile) then
129
- unless isDir?(currFile)
130
- # File we have an exclusion list and the current file is in it, skip to the next file
131
- @fullFileCount += 1
132
- fh = fileOpen(currFile)
133
-
134
- xmlFileNode = xmlNode.add_element("file", "name" => x, "fqname" => currFile)
135
- statHash = {}
136
- statHash.merge!(getFileStats(fh))
137
- statHash.merge!(calculate_digest(fh))
138
- xmlFileNode.add_attributes(statHash)
139
-
140
- ext = File.extname(currFile).downcase
141
- if @opts.winVerList.include?(ext)
142
- if @opts.versioninfo || @opts.imports
143
- peHdr = PEheader.new(fh) rescue nil
144
- unless peHdr.nil?
145
- xmlFileNode.add_element("versioninfo", peHdr.versioninfo) if @opts.versioninfo && !peHdr.versioninfo.blank?
146
- xmlFileNode.add_element("libraries", "imports" => peHdr.getImportList) if @opts.imports && !peHdr.imports.blank?
147
- end
148
- end
149
- end
150
-
151
- getFileContents(fh, xmlFileNode) if @opts.contents == true
152
- fh.close
136
+ return if isDir?(currFile)
137
+
138
+ # File we have an exclusion list and the current file is in it, skip to the next file
139
+ @fullFileCount += 1
140
+ fh = fileOpen(currFile)
141
+
142
+ xmlFileNode = xmlNode.add_element("file", "name" => x, "fqname" => currFile)
143
+ statHash = {}
144
+ statHash.merge!(getFileStats(fh))
145
+ statHash.merge!(calculate_digest(fh))
146
+ xmlFileNode.add_attributes(statHash)
147
+
148
+ ext = File.extname(currFile).downcase
149
+ if @opts.winVerList.include?(ext)
150
+ pe_hdr = PEheader.new(fh) rescue nil
151
+ process_pe_header(pe_hdr, xmlFileNode) unless pe_hdr.nil?
153
152
  end
153
+
154
+ getFileContents(fh, xmlFileNode) if @opts.contents == true
155
+ fh.close
154
156
  rescue Errno::EACCES, RuntimeError, SystemCallError
155
157
  fh.close if fh.kind_of?(File) && !fh.closed?
156
158
  end
157
159
  end
160
+ $log.debug "processFile: finished @xml is #{@xml}"
161
+ end
162
+
163
+ def process_pe_header(pe_hdr, xml_file_node)
164
+ xml_file_node.add_element("versioninfo", pe_hdr.versioninfo) if @opts.versioninfo && pe_hdr.versioninfo.present?
165
+ xml_file_node.add_element("libraries", "imports" => pe_hdr.getImportList) if @opts.imports && pe_hdr.imports.present?
166
+ rescue TypeError => err
167
+ $log.info "process_pe_header: TypeError handling PEheader; skipping PEheader info"
168
+ $log.debug err.backtrace.join("\n")
158
169
  end
159
170
 
160
171
  def isDir?(currFile)
@@ -215,10 +226,15 @@ class MD5deep
215
226
  # Create hash for requested digests
216
227
  digest = create_digest_hash
217
228
 
218
- fileName.seek(0, IO::SEEK_SET)
219
- # Loop over each digest and add the file contents
220
- while buf = fileName.read(10240000)
221
- digest.each_pair { |_k, v| v << buf }
229
+ begin
230
+ fileName.seek(0, IO::SEEK_SET)
231
+ # Loop over each digest and add the file contents
232
+ while (buf = fileName.read(10_240_000))
233
+ digest.each_pair { |_k, v| v << buf }
234
+ end
235
+ rescue => err
236
+ $log.error "Error #{err} reading file to calculate digest"
237
+ $log.debug err.backtrace.join("\n")
222
238
  end
223
239
  end
224
240
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manageiq-smartstate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.3.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - ManageIQ Developers
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-09 00:00:00.000000000 Z
11
+ date: 2020-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: azure-armrest
@@ -263,7 +263,7 @@ dependencies:
263
263
  - !ruby/object:Gem::Version
264
264
  version: 1.0.0
265
265
  description: ManageIQ SmartState Analysis
266
- email:
266
+ email:
267
267
  executables: []
268
268
  extensions: []
269
269
  extra_rdoc_files: []
@@ -525,6 +525,7 @@ files:
525
525
  - lib/metadata/linux/MiqConaryPackages.rb
526
526
  - lib/metadata/linux/MiqRpmPackages.rb
527
527
  - lib/metadata/util/event_log_filter.rb
528
+ - lib/metadata/util/find_class_methods.rb
528
529
  - lib/metadata/util/md5deep.rb
529
530
  - lib/metadata/util/win32/Win32Accounts.rb
530
531
  - lib/metadata/util/win32/Win32EventLog.rb
@@ -544,7 +545,7 @@ homepage: https://github.com/ManageIQ/manageiq-smartstate
544
545
  licenses:
545
546
  - Apache-2.0
546
547
  metadata: {}
547
- post_install_message:
548
+ post_install_message:
548
549
  rdoc_options: []
549
550
  require_paths:
550
551
  - lib
@@ -559,9 +560,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
559
560
  - !ruby/object:Gem::Version
560
561
  version: '0'
561
562
  requirements: []
562
- rubyforge_project:
563
- rubygems_version: 2.6.12
564
- signing_key:
563
+ rubygems_version: 3.0.3
564
+ signing_key:
565
565
  specification_version: 4
566
566
  summary: ManageIQ SmartState Analysis
567
567
  test_files: []