manageiq-smartstate 0.3.4 → 0.3.9

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 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: []