Skip to content

Commit cba769c

Browse files
[Normal] Update Some Codes
1 parent f0ebb1f commit cba769c

2 files changed

Lines changed: 275 additions & 11 deletions

File tree

imgextractor.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@
1111
from timeit import default_timer as dti
1212
from utils import simg2img
1313

14+
try:
15+
from pycase import ensure_dir_case_sensitive
16+
except ImportError:
17+
ensure_dir_case_sensitive = lambda *x: ...
18+
1419

1520
class Extractor:
1621
def __init__(self):
17-
self.CONFING_DIR = None
22+
self.CONFIG_DIR = None
1823
self.FileName = ""
1924
self.OUTPUT_IMAGE_FILE = ""
2025
self.EXTRACT_DIR = ""
@@ -121,7 +126,7 @@ def scan_dir(root_inode, root_path=""):
121126
link_target = root_inode.volume.read(link_target_block * root_inode.volume.block_size,
122127
entry_inode.inode.i_size).decode("utf8")
123128
if tmp_path.find(' ', 1, len(tmp_path)) > 0:
124-
self.__append(tmp_path, os.path.join(self.CONFING_DIR, self.FileName + '_space.txt'))
129+
self.__append(tmp_path, os.path.join(self.CONFIG_DIR, self.FileName + '_space.txt'))
125130
self.fs_config.append(
126131
f"{tmp_path.replace(' ', '_')} {uid} {gid} {mode}{cap} {link_target}")
127132
else:
@@ -133,6 +138,11 @@ def scan_dir(root_inode, root_path=""):
133138
dir_target = dir_target[:-1]
134139
if not os.path.isdir(dir_target):
135140
os.makedirs(dir_target)
141+
if os.name == 'nt' and windll.shell32.IsUserAnAdmin():
142+
try:
143+
ensure_dir_case_sensitive(dir_target)
144+
except (Exception, BaseException):
145+
...
136146
if os.name == 'posix' and os.geteuid() == 0:
137147
os.chmod(dir_target, int(mode, 8))
138148
os.chown(dir_target, uid, gid)
@@ -143,7 +153,7 @@ def scan_dir(root_inode, root_path=""):
143153
with open(file_target, 'wb') as out:
144154
out.write(entry_inode.open_read().read())
145155
except Exception and BaseException as e:
146-
print(f'[E] Cannot Write {file_target}, Because of {e}')
156+
print(f'[E] Cannot Write to {file_target}, Reason: {e}')
147157
if os.name == 'posix' and os.geteuid() == 0:
148158
os.chmod(file_target, int(mode, 8))
149159
os.chown(file_target, uid, gid)
@@ -181,16 +191,16 @@ def scan_dir(root_inode, root_path=""):
181191
finally:
182192
...
183193

184-
if not os.path.isdir(self.CONFING_DIR):
185-
os.makedirs(self.CONFING_DIR)
186-
self.__append(os.path.getsize(self.OUTPUT_IMAGE_FILE), self.CONFING_DIR + os.sep + self.FileName + '_size.txt')
194+
if not os.path.isdir(self.CONFIG_DIR):
195+
os.makedirs(self.CONFIG_DIR)
196+
self.__append(os.path.getsize(self.OUTPUT_IMAGE_FILE), self.CONFIG_DIR + os.sep + self.FileName + '_size.txt')
187197
with open(self.OUTPUT_IMAGE_FILE, 'rb') as file:
188198
dir_r = self.FileName
189199
scan_dir(ext4.Volume(file).root)
190200
self.fs_config.insert(0, '/ 0 2000 0755' if dir_r == 'vendor' else '/ 0 0 0755')
191201
self.fs_config.insert(1, f'{dir_r} 0 2000 0755' if dir_r == 'vendor' else '/lost+found 0 0 0700')
192202
self.fs_config.insert(2 if dir_r == 'system' else 1, f'{dir_r} 0 0 0755')
193-
self.__append('\n'.join(self.fs_config), self.CONFING_DIR + os.sep + self.FileName + '_fs_config')
203+
self.__append('\n'.join(self.fs_config), self.CONFIG_DIR + os.sep + self.FileName + '_fs_config')
194204
p1 = p2 = 0
195205
if self.context:
196206
self.context.sort()
@@ -207,7 +217,7 @@ def scan_dir(root_inode, root_path=""):
207217
p2 = 1
208218
if p1 == p2 == 1:
209219
break
210-
self.__append('\n'.join(self.context), self.CONFING_DIR + os.sep + self.FileName + "_file_contexts")
220+
self.__append('\n'.join(self.context), self.CONFIG_DIR + os.sep + self.FileName + "_file_contexts")
211221

212222
@staticmethod
213223
def fix_moto(input_file):
@@ -250,24 +260,29 @@ def fix_size(self):
250260
t = ext4.Volume(file)
251261
real_size = t.get_block_count * t.block_size
252262
if orig_size < real_size:
253-
print(f"......Wrong Size!Fixing.......\nShould:{real_size}\nYours:{orig_size}")
263+
print(
264+
f"......Your image is smaller than expected! Expanding the file.......\n"
265+
f"Expected:{real_size}\nGot:{orig_size}")
254266
file.truncate(real_size)
255267

256268
def main(self, target: str, output_dir: str, work: str, target_type: str = 'img'):
257269
self.EXTRACT_DIR = os.path.realpath(os.path.dirname(output_dir)) + os.sep + self.__out_name(
258270
os.path.basename(output_dir))
259271
self.OUTPUT_IMAGE_FILE = (os.path.realpath(os.path.dirname(target)) + os.sep) + os.path.basename(target)
260272
self.FileName = self.__out_name(os.path.basename(target), out=0)
261-
self.CONFING_DIR = work + os.sep + 'config'
273+
self.CONFIG_DIR = work + os.sep + 'config'
262274
with open(self.OUTPUT_IMAGE_FILE, 'rb+') as file:
263275
mount = ext4.Volume(file).get_mount_point
264276
if mount[:1] == '/':
265277
mount = mount[1:]
266278
if '/' in mount:
267279
mount = mount.split('/')
268280
mount = mount[len(mount) - 1]
281+
if [True for i in [".", "@", "#"] if i in mount]:
282+
mount = ""
269283
if self.__out_name(os.path.basename(output_dir)) != mount and mount and self.FileName != 'mi_ext':
270-
print(f"[N]:Your File Name Not Right , We will Extract {self.OUTPUT_IMAGE_FILE} to {mount}")
284+
print(
285+
f"[N]:Filename appears to be wrong , We will Extract {self.OUTPUT_IMAGE_FILE} to {mount}")
271286
self.EXTRACT_DIR = os.path.realpath(os.path.dirname(output_dir)) + os.sep + mount
272287
self.FileName = mount
273288
if target_type == 's_img':

pycase.py

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
#!/usr/bin/env python3
2+
"""
3+
set directory case sensitive on Windows directly with ctypes
4+
5+
**requires WSL to be enabled**
6+
7+
thus for Windows 10 1903 and up
8+
"""
9+
10+
from ctypes import (
11+
WinDLL,
12+
c_void_p,
13+
get_last_error,
14+
WinError,
15+
c_int,
16+
Structure,
17+
sizeof,
18+
byref
19+
)
20+
from ctypes.wintypes import (
21+
HANDLE,
22+
LPCSTR,
23+
DWORD,
24+
BOOL,
25+
LPVOID,
26+
ULONG
27+
)
28+
try:
29+
from enum import IntEnum
30+
except ImportError:
31+
IntEnum = int
32+
import os.path
33+
34+
# ==================================================================
35+
# ======================== WinApi Bindings =========================
36+
# ==================================================================
37+
38+
# https://stackoverflow.com/questions/29847679/get-error-message-from-ctypes-windll
39+
kernel32 = WinDLL('kernel32', use_last_error=True)
40+
41+
42+
def _check_handle(h, *_):
43+
if h == INVALID_HANDLE_VALUE:
44+
raise WinError(get_last_error())
45+
46+
return h
47+
48+
49+
def _expect_nonzero(res, *_):
50+
if not res:
51+
raise WinError(get_last_error())
52+
53+
54+
# https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
55+
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
56+
FILE_FLAG_POSIX_SEMANTICS = 0x01000000
57+
58+
OPEN_EXISTING = 3
59+
60+
FILE_SHARE_READ = 0x00000001
61+
FILE_SHARE_WRITE = 0x00000002
62+
FILE_SHARE_DELETE = 0x00000004
63+
FILE_SHARE_VALID_FLAGS = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
64+
65+
"""
66+
HANDLE CreateFileA(
67+
[in] LPCSTR lpFileName,
68+
[in] DWORD dwDesiredAccess,
69+
[in] DWORD dwShareMode,
70+
[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,
71+
[in] DWORD dwCreationDisposition,
72+
[in] DWORD dwFlagsAndAttributes,
73+
[in, optional] HANDLE hTemplateFile
74+
);
75+
"""
76+
_CreateFileA = kernel32.CreateFileA
77+
_CreateFileA.argtypes = [
78+
LPCSTR, DWORD, DWORD, c_void_p, DWORD, DWORD, HANDLE
79+
]
80+
_CreateFileA.restype = HANDLE
81+
_CreateFileA.errcheck = _check_handle
82+
83+
# https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights
84+
GENERIC_READ = 0x80000000
85+
GENERIC_WRITE = 0x40000000
86+
87+
# https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilenamew
88+
INVALID_HANDLE_VALUE = HANDLE(-1).value
89+
90+
# https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
91+
"""
92+
BOOL CloseHandle(
93+
[in] HANDLE hObject
94+
);
95+
"""
96+
_CloseHandle = kernel32.CloseHandle
97+
_CloseHandle.argtypes = [HANDLE]
98+
_CloseHandle.restype = BOOL
99+
_CloseHandle.errcheck = _expect_nonzero
100+
101+
# https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
102+
"""
103+
BOOL GetFileInformationByHandleEx(
104+
[in] HANDLE hFile,
105+
[in] FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
106+
[out] LPVOID lpFileInformation,
107+
[in] DWORD dwBufferSize
108+
);
109+
"""
110+
_GetFileInformationByHandleEx = kernel32.GetFileInformationByHandleEx
111+
_GetFileInformationByHandleEx.argtypes = [HANDLE, c_int, LPVOID, DWORD]
112+
_GetFileInformationByHandleEx.restype = BOOL
113+
_GetFileInformationByHandleEx.errcheck = _expect_nonzero
114+
115+
116+
# ===== The start of the undocumented craps... =====
117+
118+
# /mingw64/include/winbase.h
119+
class FILE_CASE_SENSITIVE_INFO(Structure):
120+
_fields_ = [
121+
('Flags', ULONG)
122+
]
123+
124+
125+
FILE_INFO_BY_HANDLE = FILE_CASE_SENSITIVE_INFO
126+
127+
128+
# https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ne-minwinbase-file_info_by_handle_class
129+
class FILE_INFO_BY_HANDLE_CLASS(IntEnum):
130+
FileCaseSensitiveInfo = 23
131+
132+
133+
# /mingw64/include/winnt.h
134+
# https://github.com/DDoSolitary/LxRunOffline/blob/bdc6d7d77f886c6dcdab3b4c9c136557ca6694c4/src/lib/fs.cpp#L89
135+
FILE_CS_FLAG_CASE_SENSITIVE_DIR = 0x00000001
136+
137+
# https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
138+
"""
139+
BOOL SetFileInformationByHandle(
140+
[in] HANDLE hFile,
141+
[in] FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
142+
[in] LPVOID lpFileInformation,
143+
[in] DWORD dwBufferSize
144+
);
145+
"""
146+
_SetFileInformationByHandle = kernel32.SetFileInformationByHandle
147+
_SetFileInformationByHandle.argtypes = [HANDLE, c_int, LPVOID, DWORD]
148+
_SetFileInformationByHandle.restype = BOOL
149+
_SetFileInformationByHandle.errcheck = _expect_nonzero
150+
151+
152+
# ==================================================================
153+
# ======================= Wrappers functions =======================
154+
# ==================================================================
155+
156+
def CreateFileA(path: str, access: int, share: int,
157+
oflag: int, flags: int) -> HANDLE:
158+
return _CreateFileA(
159+
path.encode(encoding='utf-8'),
160+
access, share,
161+
None, # default
162+
oflag, flags,
163+
None # unused
164+
)
165+
166+
167+
def CloseHandle(h: HANDLE):
168+
_CloseHandle(h)
169+
170+
171+
def GetFileInformationByHandleEx(
172+
h: HANDLE,
173+
kind: FILE_INFO_BY_HANDLE_CLASS
174+
) -> FILE_INFO_BY_HANDLE:
175+
if kind == FILE_INFO_BY_HANDLE_CLASS.FileCaseSensitiveInfo:
176+
dtype = FILE_CASE_SENSITIVE_INFO
177+
else:
178+
raise ValueError('Invalid file info class')
179+
180+
data = dtype()
181+
182+
_GetFileInformationByHandleEx(h, kind,
183+
byref(data), sizeof(dtype))
184+
185+
return data
186+
187+
188+
def SetFileInformationByHandle(
189+
h: HANDLE,
190+
kind: FILE_INFO_BY_HANDLE_CLASS,
191+
data: FILE_INFO_BY_HANDLE
192+
):
193+
if kind == FILE_INFO_BY_HANDLE_CLASS.FileCaseSensitiveInfo:
194+
dtype = FILE_CASE_SENSITIVE_INFO
195+
else:
196+
raise ValueError('Invalid file info class')
197+
198+
_SetFileInformationByHandle(h, kind,
199+
byref(data), sizeof(dtype))
200+
201+
202+
# ==================================================================
203+
# ======================== Helper functions ========================
204+
# ==================================================================
205+
206+
def open_dir_handle(path: str, access: int) -> HANDLE:
207+
return CreateFileA(
208+
path, access,
209+
FILE_SHARE_VALID_FLAGS, OPEN_EXISTING,
210+
FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_BACKUP_SEMANTICS
211+
)
212+
213+
214+
# ==================================================================
215+
# ======================= Exported functions ========================
216+
# ==================================================================
217+
218+
def ensure_dir_case_sensitive(path: str):
219+
if not os.path.isdir(path):
220+
raise NotADirectoryError(
221+
f'Cannot set case sensitive for non-directory: {path}'
222+
)
223+
224+
h = open_dir_handle(path, GENERIC_READ)
225+
try:
226+
info: FILE_CASE_SENSITIVE_INFO = GetFileInformationByHandleEx(
227+
h, FILE_INFO_BY_HANDLE_CLASS.FileCaseSensitiveInfo
228+
)
229+
230+
if info.Flags & FILE_CS_FLAG_CASE_SENSITIVE_DIR:
231+
print(f'{path!r} is already case sensitive')
232+
else:
233+
h2 = open_dir_handle(path, GENERIC_WRITE)
234+
235+
try:
236+
info.Flags |= FILE_CS_FLAG_CASE_SENSITIVE_DIR
237+
238+
SetFileInformationByHandle(
239+
h2,
240+
FILE_INFO_BY_HANDLE_CLASS.FileCaseSensitiveInfo,
241+
info
242+
)
243+
244+
print(f'set case sensitive state for {path!r}')
245+
finally:
246+
CloseHandle(h2)
247+
finally:
248+
CloseHandle(h)
249+

0 commit comments

Comments
 (0)