Skip to content

Commit 030f398

Browse files
authored
Merge pull request #2623 from nexB/2615-installedwindowsprogram-installed-files-paths
Collect InstalledWindowsProgram installed files #2615
2 parents 493c0db + e32e9f3 commit 030f398

File tree

9 files changed

+225
-95
lines changed

9 files changed

+225
-95
lines changed

src/packagedcode/win_pe.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,14 @@ class WindowsExecutable(models.Package):
233233
'.winmd',
234234
'.sys',
235235
'.tlb',
236+
'.exe_*',
237+
'.dll_*',
238+
'.mui_*',
239+
'.mun_*',
240+
'.com_*',
241+
'.winmd_*',
242+
'.sys_*',
243+
'.tlb_*',
236244
)
237245
filetypes = ('pe32', 'for ms windows',)
238246
mimetypes = ('application/x-dosexec',)

src/packagedcode/win_reg.py

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ def reg_parse(location):
211211
"""
212212
for installed_program in report_installed_programs(location):
213213
yield installed_program
214+
for installed_program in report_installed_programs(
215+
location,
216+
registry_path='\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall'
217+
):
218+
yield installed_program
214219
for installed_dotnet in report_installed_dotnet_versions(location):
215220
yield installed_dotnet
216221

@@ -222,22 +227,38 @@ def get_installed_packages(root_dir, is_container=True):
222227
"""
223228
# These paths are relative to a Windows docker image layer root directory
224229
if is_container:
225-
software_registry_locations = [
226-
os.path.join(root_dir, 'Hives', 'Software_Delta'),
227-
os.path.join(root_dir, 'Files', 'Windows', 'System32', 'config', 'SOFTWARE')
228-
]
229-
# We are setting the root to be the `Files` directory, since this
230-
# directory represents the root `C:\` drive of a Windows installation
231-
root_dir = os.path.join(root_dir, 'Files')
230+
hives_software_delta_loc = os.path.join(root_dir, 'Hives', 'Software_Delta')
231+
files_software_loc = os.path.join(
232+
root_dir,
233+
'Files',
234+
'Windows',
235+
'System32',
236+
'config',
237+
'SOFTWARE'
238+
)
239+
utilityvm_software_loc = os.path.join(
240+
root_dir,
241+
'UtilityVM',
242+
'Files',
243+
'Windows',
244+
'System32',
245+
'config',
246+
'SOFTWARE'
247+
)
248+
root_prefixes_by_software_registry_locations = {
249+
hives_software_delta_loc: 'Files',
250+
files_software_loc: 'Files',
251+
utilityvm_software_loc: os.path.join('UtilityVM', 'Files')
252+
}
232253
else:
233254
# TODO: Add support for virtual machines
234255
raise Exception('Unsuported file system type')
235256

236-
for software_registry_loc in software_registry_locations:
257+
for software_registry_loc, root_prefix in root_prefixes_by_software_registry_locations.items():
237258
if not os.path.exists(software_registry_loc):
238259
continue
239260
for package in reg_parse(software_registry_loc):
240-
package.populate_installed_files(root_dir)
261+
package.populate_installed_files(root_dir, root_prefix=root_prefix)
241262
yield package
242263

243264

@@ -264,16 +285,27 @@ def create_absolute_installed_file_path(root_dir, file_path):
264285
return str(Path(root_dir).joinpath(file_path))
265286

266287

267-
def create_relative_file_path(file_path, root_dir):
288+
def create_relative_file_path(file_path, root_dir, root_prefix=''):
268289
"""
269290
Return a subpath of `file_path` that is relative to `root_dir`
270291
271292
>>> file_path = '/home/test/example/foo.txt'
272293
>>> root_dir = '/home/test/'
273294
>>> create_relative_file_path(file_path, root_dir)
274295
'example/foo.txt'
296+
297+
If there is a `root_prefix`, then it is prepended to the resulting
298+
relative file path.
299+
300+
>>> file_path = '/home/test/example/foo.txt'
301+
>>> root_dir = '/home/test/'
302+
>>> create_relative_file_path(file_path, root_dir, 'prefix')
303+
'prefix/example/foo.txt'
275304
"""
276-
return str(Path(file_path).relative_to(root_dir))
305+
relative_file_path = str(Path(file_path).relative_to(root_dir))
306+
if root_prefix:
307+
return os.path.join(root_prefix, relative_file_path)
308+
return relative_file_path
277309

278310

279311
@attr.s()
@@ -285,11 +317,19 @@ def recognize(cls, location):
285317
for installed in reg_parse(location):
286318
yield installed
287319

288-
def populate_installed_files(self, root_dir):
320+
def populate_installed_files(self, root_dir, root_prefix=''):
289321
install_location = self.extra_data.get('install_location')
290322
if not install_location:
291323
return
292324

325+
if root_prefix:
326+
# The rootfs location of a Docker image layer can be in a
327+
# subdirectory of the layer directory (where `root_dir` is the path
328+
# to the layer directory), so we append `root_prefix` (where prefix
329+
# is relative to the file paths within the Docker image layer's
330+
# rootfs files) to `root_dir`
331+
root_dir = os.path.join(root_dir, root_prefix)
332+
293333
absolute_install_location = create_absolute_installed_file_path(
294334
root_dir=root_dir,
295335
file_path=install_location
@@ -301,7 +341,11 @@ def populate_installed_files(self, root_dir):
301341
for root, _, files in os.walk(absolute_install_location):
302342
for file in files:
303343
installed_file_location = os.path.join(root, file)
304-
relative_installed_file_path = create_relative_file_path(installed_file_location, root_dir)
344+
relative_installed_file_path = create_relative_file_path(
345+
file_path=installed_file_location,
346+
root_dir=root_dir,
347+
root_prefix=root_prefix
348+
)
305349
installed_files.append(relative_installed_file_path)
306350

307351
known_program_files = self.extra_data.get('known_program_files', [])
@@ -310,7 +354,11 @@ def populate_installed_files(self, root_dir):
310354
root_dir=root_dir,
311355
file_path=known_program_file_path,
312356
)
313-
relative_known_file_path = create_relative_file_path(known_program_file_location, root_dir)
357+
relative_known_file_path = create_relative_file_path(
358+
file_path=known_program_file_location,
359+
root_dir=root_dir,
360+
root_prefix=root_prefix
361+
)
314362
if (not os.path.exists(known_program_file_location)
315363
or relative_known_file_path in installed_files):
316364
continue

tests/packagedcode/data/plugin/help.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,6 @@ Package: windows-update
273273
--------------------------------------------
274274
Package: winexe
275275
class: packagedcode.win_pe:WindowsExecutable
276-
extensions: .exe, .dll, .mui, .mun, .com, .winmd, .sys, .tlb
276+
extensions: .exe, .dll, .mui, .mun, .com, .winmd, .sys, .tlb, .exe_*, .dll_*, .mui_*, .mun_*, .com_*, .winmd_*, .sys_*, .tlb_*
277277
filetypes: pe32, for ms windows
278278

Lines changed: 152 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,154 @@
1-
{
2-
"type": "windows-program",
3-
"namespace": null,
4-
"name": "Test",
5-
"version": "0.0.1",
6-
"qualifiers": {},
7-
"subpath": null,
8-
"primary_language": null,
9-
"description": null,
10-
"release_date": null,
11-
"parties": [
12-
{
13-
"type": "organization",
14-
"role": "publisher",
15-
"name": "Test Publisher",
16-
"email": null,
17-
"url": null
18-
}
19-
],
20-
"keywords": [],
21-
"homepage_url": null,
22-
"download_url": null,
23-
"size": null,
24-
"sha1": null,
25-
"md5": null,
26-
"sha256": null,
27-
"sha512": null,
28-
"bug_tracking_url": null,
29-
"code_view_url": null,
30-
"vcs_url": null,
31-
"copyright": null,
32-
"license_expression": null,
33-
"declared_license": null,
34-
"notice_text": null,
35-
"root_path": null,
36-
"dependencies": [],
37-
"contains_source_code": null,
38-
"source_packages": [],
39-
"installed_files": [
40-
{
41-
"path": "Program Files/Test/Test.dat",
42-
"size": 0,
43-
"sha1": null,
44-
"md5": null,
45-
"sha256": null,
46-
"sha512": null
1+
[
2+
{
3+
"type": "windows-program",
4+
"namespace": null,
5+
"name": "Test",
6+
"version": "0.0.1",
7+
"qualifiers": {},
8+
"subpath": null,
9+
"primary_language": null,
10+
"description": null,
11+
"release_date": null,
12+
"parties": [
13+
{
14+
"type": "organization",
15+
"role": "publisher",
16+
"name": "Test Publisher",
17+
"email": null,
18+
"url": null
19+
}
20+
],
21+
"keywords": [],
22+
"homepage_url": null,
23+
"download_url": null,
24+
"size": null,
25+
"sha1": null,
26+
"md5": null,
27+
"sha256": null,
28+
"sha512": null,
29+
"bug_tracking_url": null,
30+
"code_view_url": null,
31+
"vcs_url": null,
32+
"copyright": null,
33+
"license_expression": null,
34+
"declared_license": null,
35+
"notice_text": null,
36+
"root_path": null,
37+
"dependencies": [],
38+
"contains_source_code": null,
39+
"source_packages": [],
40+
"installed_files": [
41+
{
42+
"path": "Files/Program Files/Test/Test.dat",
43+
"size": 0,
44+
"sha1": null,
45+
"md5": null,
46+
"sha256": null,
47+
"sha512": null
48+
},
49+
{
50+
"path": "Files/Program Files/Test/Test.exe",
51+
"size": 0,
52+
"sha1": null,
53+
"md5": null,
54+
"sha256": null,
55+
"sha512": null
56+
},
57+
{
58+
"path": "Files/Program Files/Test/Uninstall.exe",
59+
"size": 0,
60+
"sha1": null,
61+
"md5": null,
62+
"sha256": null,
63+
"sha512": null
64+
}
65+
],
66+
"extra_data": {
67+
"install_location": "C:\\Program Files\\Test\\",
68+
"known_program_files": [
69+
"C:\\Program Files\\Test\\Test.exe",
70+
"C:\\Program Files\\Test\\Uninstall.exe"
71+
]
4772
},
48-
{
49-
"path": "Program Files/Test/Test.exe",
50-
"size": 0,
51-
"sha1": null,
52-
"md5": null,
53-
"sha256": null,
54-
"sha512": null
55-
},
56-
{
57-
"path": "Program Files/Test/Uninstall.exe",
58-
"size": 0,
59-
"sha1": null,
60-
"md5": null,
61-
"sha256": null,
62-
"sha512": null
63-
}
64-
],
65-
"extra_data": {
66-
"install_location": "C:\\Program Files\\Test\\",
67-
"known_program_files": [
68-
"C:\\Program Files\\Test\\Test.exe",
69-
"C:\\Program Files\\Test\\Uninstall.exe"
70-
]
73+
"purl": "pkg:windows-program/[email protected]",
74+
"repository_homepage_url": null,
75+
"repository_download_url": null,
76+
"api_data_url": null
7177
},
72-
"purl": "pkg:windows-program/[email protected]",
73-
"repository_homepage_url": null,
74-
"repository_download_url": null,
75-
"api_data_url": null
76-
}
78+
{
79+
"type": "windows-program",
80+
"namespace": null,
81+
"name": "Test2",
82+
"version": "0.0.1",
83+
"qualifiers": {},
84+
"subpath": null,
85+
"primary_language": null,
86+
"description": null,
87+
"release_date": null,
88+
"parties": [
89+
{
90+
"type": "organization",
91+
"role": "publisher",
92+
"name": "Test Publisher",
93+
"email": null,
94+
"url": null
95+
}
96+
],
97+
"keywords": [],
98+
"homepage_url": null,
99+
"download_url": null,
100+
"size": null,
101+
"sha1": null,
102+
"md5": null,
103+
"sha256": null,
104+
"sha512": null,
105+
"bug_tracking_url": null,
106+
"code_view_url": null,
107+
"vcs_url": null,
108+
"copyright": null,
109+
"license_expression": null,
110+
"declared_license": null,
111+
"notice_text": null,
112+
"root_path": null,
113+
"dependencies": [],
114+
"contains_source_code": null,
115+
"source_packages": [],
116+
"installed_files": [
117+
{
118+
"path": "Files/Program Files (x86)/Test2/Test2.dat",
119+
"size": 0,
120+
"sha1": null,
121+
"md5": null,
122+
"sha256": null,
123+
"sha512": null
124+
},
125+
{
126+
"path": "Files/Program Files (x86)/Test2/Test2.exe",
127+
"size": 0,
128+
"sha1": null,
129+
"md5": null,
130+
"sha256": null,
131+
"sha512": null
132+
},
133+
{
134+
"path": "Files/Program Files (x86)/Test2/Uninstall.exe",
135+
"size": 0,
136+
"sha1": null,
137+
"md5": null,
138+
"sha256": null,
139+
"sha512": null
140+
}
141+
],
142+
"extra_data": {
143+
"install_location": "C:\\Program Files (x86)\\Test2\\",
144+
"known_program_files": [
145+
"C:\\Program Files (x86)\\Test2\\Test2.exe",
146+
"C:\\Program Files (x86)\\Test2\\Uninstall.exe"
147+
]
148+
},
149+
"purl": "pkg:windows-program/[email protected]",
150+
"repository_homepage_url": null,
151+
"repository_download_url": null,
152+
"api_data_url": null
153+
}
154+
]

tests/packagedcode/data/win_reg/get_installed_packages_docker/layer/Files/Program Files (x86)/Test2/Test2.dat

Whitespace-only changes.

tests/packagedcode/data/win_reg/get_installed_packages_docker/layer/Files/Program Files (x86)/Test2/Test2.exe

Whitespace-only changes.

tests/packagedcode/data/win_reg/get_installed_packages_docker/layer/Files/Program Files (x86)/Test2/Uninstall.exe

Whitespace-only changes.
Binary file not shown.

0 commit comments

Comments
 (0)