33# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44#
55
6- from typing import Any , Mapping
7- import ctypes , os , uuid
8-
9- from pathlib import Path , PurePosixPath , PureWindowsPath , PosixPath , WindowsPath
10- from unicorn import UcError
6+ import os
7+ from typing import Union
8+ from pathlib import Path , PurePath , PurePosixPath , PureWindowsPath
119
1210from qiling import Qiling
13- from qiling .os .windows .wdk_const import *
14- from qiling .os .windows .structs import *
15- from qiling .utils import verify_ret
11+ from qiling .const import QL_OS , QL_OS_POSIX
1612
1713# OH-MY-WIN32 !!!
1814# Some codes from cygwin.
@@ -25,27 +21,24 @@ class QlPathManager:
2521 def __init__ (self , ql : Qiling , cwd : str ):
2622 self .ql = ql
2723 self ._cwd = cwd
28-
24+
2925 @property
30- def cwd (self ):
26+ def cwd (self ) -> str :
3127 return self ._cwd
32-
28+
3329 @cwd .setter
34- def cwd (self , c ):
35- if c [0 ] != "/" :
36- self .ql .log .warning (f"Sanity check: cur_path doesn't start with a /!" )
30+ def cwd (self , c : str ) -> None :
31+ if not c .startswith ('/' ):
32+ self .ql .log .warning (f'Sanity check: path does not start with a forward slash "/"' )
33+
3734 self ._cwd = c
3835
3936 @staticmethod
40- def normalize (path ):
41- if type (path ) is PurePosixPath :
42- normalized_path = PurePosixPath ()
43- elif type (path ) is PureWindowsPath :
44- normalized_path = PureWindowsPath ()
45- elif type (path ) is PosixPath :
46- normalized_path = PosixPath ()
47- elif type (path ) is WindowsPath :
48- normalized_path = WindowsPath ()
37+ def normalize (path : Union [Path , PurePath ]) -> Union [Path , PurePath ]:
38+ # expected types: PosixPath, PurePosixPath, WindowsPath, PureWindowsPath
39+ assert isinstance (path , (Path , PurePath )), f'did not expect { type (path ).__name__ !r} here'
40+
41+ normalized_path = type (path )()
4942
5043 # remove anchor (necessary for Windows UNC paths) and convert to relative path
5144 if path .is_absolute ():
@@ -64,101 +57,103 @@ def normalize(path):
6457 return normalized_path
6558
6659 @staticmethod
67- def convert_win32_to_posix (rootfs , cwd , path ):
68- # rootfs is a concrete path.
69- rootfs = Path (rootfs )
70- # cwd and path are pure paths
71- cwd = PurePosixPath (cwd [1 :])
60+ def convert_win32_to_posix (rootfs : Union [str , Path ], cwd : str , path : str ) -> Path :
61+ _rootfs = Path (rootfs )
62+ _cwd = PurePosixPath (cwd [1 :])
7263
73- result = None
7464 # Things are complicated here.
7565 # See https://docs.microsoft.com/zh-cn/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN
7666 if PureWindowsPath (path ).is_absolute ():
77- if (len (path ) >= 2 and path [ 0 ] == '\\ ' and path [ 1 ] == ' \\ ' ) or \
78- (len (path ) >= 3 and path [0 ].isalpha () and path [2 ] == '\\ ' ): # \\.\PhysicalDrive0 or \\Server\Share\Directory or X:\
67+ if (len (path ) >= 2 and path . startswith ( r '\\') ) or \
68+ (len (path ) >= 3 and path [0 ].isalpha () and path [1 : 3 ] == ': \\ ' ): # \\.\PhysicalDrive0 or \\Server\Share\Directory or X:\
7969 # UNC path should be handled in fs mapping. If not, append it to rootfs directly.
8070 pw = PureWindowsPath (path )
81- result = rootfs / QlPathManager .normalize (pw )
71+ result = _rootfs / QlPathManager .normalize (pw )
8272 else :
8373 # code should never reach here.
84- result = rootfs / QlPathManager .normalize (path )
74+ result = _rootfs / QlPathManager .normalize (path )
8575 else :
8676 if len (path ) >= 3 and path [:3 ] == r'\\?' or path [:3 ] == r'\??' : # \??\ or \\?\ or \Device\..
8777 # Similair to \\.\, it should be handled in fs mapping.
8878 pw = PureWindowsPath (path )
89- result = rootfs / QlPathManager .normalize (cwd / pw .relative_to (pw .anchor ).as_posix ())
79+ result = _rootfs / QlPathManager .normalize (_cwd / pw .relative_to (pw .anchor ).as_posix ())
9080 else :
9181 # a normal relative path
92- result = rootfs / QlPathManager .normalize (cwd / PureWindowsPath (path ).as_posix ())
82+ result = _rootfs / QlPathManager .normalize (_cwd / PureWindowsPath (path ).as_posix ())
83+
9384 return result
9485
9586 @staticmethod
96- def convert_posix_to_win32 (rootfs , cwd , path ):
97- # rootfs is a concrete path.
98- rootfs = Path (rootfs )
99- # cwd and path are pure paths
100- cwd = PurePosixPath (cwd [1 :])
101- path = PurePosixPath (path )
102- if path .is_absolute ():
103- return rootfs / QlPathManager .normalize (path )
87+ def convert_posix_to_win32 (rootfs : Union [str , Path ], cwd : str , path : str ) -> Path :
88+ _rootfs = Path (rootfs )
89+ _cwd = PurePosixPath (cwd [1 :])
90+ _path = PurePosixPath (path )
91+
92+ if _path .is_absolute ():
93+ return _rootfs / QlPathManager .normalize (_path )
10494 else :
105- return rootfs / QlPathManager .normalize (cwd / path )
95+ return _rootfs / QlPathManager .normalize (_cwd / _path )
10696
10797 @staticmethod
108- def convert_for_native_os (rootfs , cwd , path ):
109- rootfs = Path (rootfs )
110- cwd = PurePosixPath (cwd [1 :])
111- path = Path (path )
112- if path .is_absolute ():
113- return rootfs / QlPathManager .normalize (path )
98+ def convert_for_native_os (rootfs : Union [str , Path ], cwd : str , path : str ) -> Path :
99+ _rootfs = Path (rootfs )
100+ _cwd = PurePosixPath (cwd [1 :])
101+ _path = Path (path )
102+
103+ if _path .is_absolute ():
104+ return _rootfs / QlPathManager .normalize (_path )
114105 else :
115- return rootfs / QlPathManager .normalize (cwd / path .as_posix ())
106+ return _rootfs / QlPathManager .normalize (_cwd / _path .as_posix ())
116107
117- def convert_path (self , rootfs , cwd , path ):
118- if (self .ql .ostype == self .ql .platform ) \
119- or (self .ql .ostype in [QL_OS .LINUX , QL_OS .MACOS ] and self .ql .platform in [QL_OS .LINUX , QL_OS .MACOS ]):
108+ def convert_path (self , rootfs : Union [str , Path ], cwd : str , path : str ) -> Path :
109+ emulated_os = self .ql .ostype
110+ hosting_os = self .ql .platform
111+
112+ # emulated os and hosting platform are of the same type
113+ if (emulated_os == hosting_os ) or (emulated_os in QL_OS_POSIX and hosting_os in QL_OS_POSIX ):
120114 return QlPathManager .convert_for_native_os (rootfs , cwd , path )
121- elif self .ql .ostype in [QL_OS .LINUX , QL_OS .MACOS ] and self .ql .platform == QL_OS .WINDOWS :
115+
116+ elif emulated_os in QL_OS_POSIX and hosting_os == QL_OS .WINDOWS :
122117 return QlPathManager .convert_posix_to_win32 (rootfs , cwd , path )
123- elif self .ql .ostype == QL_OS .WINDOWS and self .ql .platform in [QL_OS .LINUX , QL_OS .MACOS ]:
118+
119+ elif emulated_os == QL_OS .WINDOWS and hosting_os in QL_OS_POSIX :
124120 return QlPathManager .convert_win32_to_posix (rootfs , cwd , path )
121+
125122 else :
126- # Fallback
127123 return QlPathManager .convert_for_native_os (rootfs , cwd , path )
128-
129- def transform_to_link_path (self , path ):
130- rootfs = self .ql .rootfs
131- real_path = self .convert_path (rootfs , self .cwd , path )
124+
125+ def transform_to_link_path (self , path : str ) -> str :
126+ real_path = self .convert_path (self .ql .rootfs , self .cwd , path )
132127
133128 return str (real_path .absolute ())
134129
135- def transform_to_real_path (self , path ) :
136- from types import FunctionType
130+ def transform_to_real_path (self , path : str ) -> str :
131+ real_path = self . convert_path ( self . ql . rootfs , self . cwd , path )
137132
138- rootfs = self .ql .rootfs
139- real_path = self .convert_path (rootfs , self .cwd , path )
140-
141133 if os .path .islink (real_path ):
142134 link_path = Path (os .readlink (real_path ))
135+
143136 if not link_path .is_absolute ():
144137 real_path = Path (os .path .join (os .path .dirname (real_path ), link_path ))
145138
146139 # resolve multilevel symbolic link
147140 if not os .path .exists (real_path ):
148141 path_dirs = link_path .parts
142+
149143 if link_path .is_absolute ():
150144 path_dirs = path_dirs [1 :]
151145
152- for i in range (0 , len (path_dirs )- 1 ):
146+ for i in range (len (path_dirs ) - 1 ):
153147 path_prefix = os .path .sep .join (path_dirs [:i + 1 ])
154148 real_path_prefix = self .transform_to_real_path (path_prefix )
155149 path_remain = os .path .sep .join (path_dirs [i + 1 :])
156150 real_path = Path (os .path .join (real_path_prefix , path_remain ))
151+
157152 if os .path .exists (real_path ):
158153 break
159-
154+
160155 return str (real_path .absolute ())
161156
162157 # The `relative path` here refers to the path which is relative to the rootfs.
163- def transform_to_relative_path (self , path ) :
158+ def transform_to_relative_path (self , path : str ) -> str :
164159 return str (Path (self .cwd ) / path )
0 commit comments