Coverage for sources/mimeogram/fsprotect/windows.py: 80%
71 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 19:15 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 19:15 +0000
1# vim: set filetype=python fileencoding=utf-8:
2# -*- coding: utf-8 -*-
4#============================================================================#
5# #
6# Licensed under the Apache License, Version 2.0 (the "License"); #
7# you may not use this file except in compliance with the License. #
8# You may obtain a copy of the License at #
9# #
10# http://www.apache.org/licenses/LICENSE-2.0 #
11# #
12# Unless required by applicable law or agreed to in writing, software #
13# distributed under the License is distributed on an "AS IS" BASIS, #
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15# See the License for the specific language governing permissions and #
16# limitations under the License. #
17# #
18#============================================================================#
21''' Sensitive filesystem locations on Windows. '''
24from . import __
27_scribe = __.produce_scribe( __name__ )
30CSIDL_PROGRAM_FILES_COMMON = 0x002b # C:\Program Files\Common Files
31CSIDL_PROGRAM_FILES_COMMONX86 = 0x002c # C:\Program Files (x86)\Common Files
34def discover_system_paths( ) -> frozenset[ __.Path ]:
35 ''' Discovers system paths via standard Windows mechanisms. '''
36 paths: set[ __.Path ] = set( )
37 paths.update( _discover_system_paths_via_environment( ) )
38 paths.update( _discover_system_paths_via_api( ) )
39 # TODO? Cygwin
40 if _detect_mingw( ): _discover_add_mingw_system_paths( paths )
41 return frozenset( paths )
44def _detect_mingw( ) -> bool:
45 ''' Checks if running in MinGW environment. '''
46 # TODO: If environment vars are not set, then return False.
47 # Else, proceed to more expensive checck to ensure sane MinGW.
48 mingw_env = __.os.environ.get( 'MSYSTEM', '' )
49 if mingw_env.startswith( ('MINGW', 'MSYS') ): 49 ↛ 52line 49 didn't jump to line 52 because the condition on line 49 was always true
50 _scribe.debug( f'MinGW detected via MSYSTEM={mingw_env}' )
51 return True
52 mingw_paths = ( '/mingw32', '/mingw64', '/msys', '/usr/bin/msys-2.0.dll' )
53 for path in mingw_paths:
54 if not __.Path( path ).exists( ): continue
55 _scribe.debug( f'MinGW detected via path: {path}' )
56 return True
57 return False
60def _discover_add_mingw_system_paths( paths: set[ __.Path ] ) -> None:
61 paths_: set[ __.Path ] = set( )
62 for path in paths:
63 parts = path.parts
64 if 1 >= len( parts ): continue 64 ↛ 62line 64 didn't jump to line 62 because the continue on line 64 wasn't executed
65 drive = parts[ 0 ][ 0 ].lower( ) # TODO? Consider UNC paths.
66 paths_.add( __.Path( f"/{drive}" ).joinpath( *parts[ 1 : ] ) )
67 _scribe.debug(
68 "Calculated {} MingGW system paths.".format( len( paths_ ) ) )
69 paths_.update( map(
70 __.Path,
71 ( '/bin', '/dev', '/etc',
72 '/mingw32', '/mingw64', '/msys', '/proc', '/usr',
73 ) ) )
74 paths.update( paths_ )
77def _discover_system_paths_via_environment( ) -> frozenset[ __.Path ]:
78 ''' Discovers system paths via environment. '''
79 environ = __.os.environ
80 paths: set[ __.Path ] = set( )
81 system_drive = environ.get( 'SystemDrive', 'C:' )
82 system_root = environ.get( 'SystemRoot', f"{system_drive}\\Windows" )
83 paths.add( __.Path( system_root ) )
84 paths.add( __.Path( f"{system_drive}/System Volume Information" ) )
85 # Program Files variations
86 progfiles = __.os.environ.get(
87 'ProgramFiles', f"{system_drive}\\Program Files" )
88 paths.add( __.Path( progfiles ) )
89 for progfiles_ename in (
90 'ProgramFiles(x86)', 'ProgramFiles(Arm)', 'ProgramW6432'
91 ):
92 progfiles = environ.get( progfiles_ename )
93 if progfiles: paths.add( __.Path( progfiles ) )
94 return frozenset( paths )
97def _discover_system_paths_via_api( ) -> set[ __.Path ]:
98 ''' Discovers system paths via API. '''
99 import ctypes
100 from ctypes.wintypes import MAX_PATH
101 dmessage = "Could not retrieve additional Windows system paths via API."
102 paths: set[ __.Path ] = set( )
103 try: dll = ctypes.windll.shell32 # pyright: ignore
104 except Exception:
105 _scribe.debug( dmessage )
106 buf = ctypes.create_unicode_buffer( MAX_PATH + 1 )
107 for key in (
108 CSIDL_PROGRAM_FILES_COMMON,
109 CSIDL_PROGRAM_FILES_COMMONX86,
110 ):
111 try:
112 dll.SHGetFolderPathW( # pyright: ignore
113 None, key, None, 0, buf )
114 paths.add( __.Path( buf.value ) )
115 except Exception: # noqa: PERF203
116 _scribe.debug( dmessage )
117 return paths
120def discover_user_paths( ) -> frozenset[ __.Path ]:
121 ''' Discovers Windows user-specific paths that should be protected. '''
122 paths: set[ __.Path ] = set( )
123 appdata = __.os.environ.get( 'APPDATA' )
124 local_appdata = __.os.environ.get( 'LOCALAPPDATA' )
125 userprofile = __.os.environ.get( 'USERPROFILE' )
126 if appdata: paths.add( __.Path( appdata ) )
127 if local_appdata: paths.add( __.Path( local_appdata ) )
128 if userprofile: 128 ↛ 138line 128 didn't jump to line 138 because the condition on line 128 was always true
129 profile = __.Path( userprofile )
130 paths.update( (
131 profile / 'AppData' / 'Local',
132 profile / 'AppData' / 'LocalLow',
133 profile / 'AppData' / 'Roaming',
134 # Legacy Paths
135 profile / 'Application Data',
136 profile / 'Local Settings',
137 ) )
138 return frozenset( paths )