flashpod 0.2.1__tar.gz → 0.2.2__tar.gz
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.
- {flashpod-0.2.1 → flashpod-0.2.2}/PKG-INFO +1 -1
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/platform/windows.py +56 -13
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod.egg-info/PKG-INFO +1 -1
- {flashpod-0.2.1 → flashpod-0.2.2}/pyproject.toml +1 -1
- {flashpod-0.2.1 → flashpod-0.2.2}/LICENSE +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/README.md +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/__init__.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/__main__.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/cli.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/contrib/99-flashpod-firewire-ipod.rules +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/fat32.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/fatfs.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/firmware/firmware.json +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/ipod_flash.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/itunesdb.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/platform/__init__.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/platform/base.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/platform/linux.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/platform/macos.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod/resources.py +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod.egg-info/SOURCES.txt +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod.egg-info/dependency_links.txt +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod.egg-info/entry_points.txt +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod.egg-info/requires.txt +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/flashpod.egg-info/top_level.txt +0 -0
- {flashpod-0.2.1 → flashpod-0.2.2}/setup.cfg +0 -0
|
@@ -35,7 +35,38 @@ GENERIC_WRITE = 0x40000000
|
|
|
35
35
|
FILE_SHARE_READ = 0x00000001
|
|
36
36
|
FILE_SHARE_WRITE = 0x00000002
|
|
37
37
|
OPEN_EXISTING = 3
|
|
38
|
-
INVALID_HANDLE_VALUE
|
|
38
|
+
# INVALID_HANDLE_VALUE is (HANDLE)-1, so its unsigned value is pointer-sized:
|
|
39
|
+
# 2**64-1 on 64-bit Python, 2**32-1 on 32-bit. Derive it rather than assuming.
|
|
40
|
+
INVALID_HANDLE_VALUE = (1 << (8 * ctypes.sizeof(ctypes.c_void_p))) - 1
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _k32():
|
|
44
|
+
"""kernel32 with correct prototypes for the handle APIs.
|
|
45
|
+
|
|
46
|
+
Declaring these matters: ctypes defaults restype to ``c_int``, but a HANDLE
|
|
47
|
+
is pointer-sized. On 64-bit Windows that truncates the handle, and — far
|
|
48
|
+
worse — a *failed* CreateFileW returns INVALID_HANDLE_VALUE, which as a
|
|
49
|
+
signed int is -1 and never equals the unsigned constant we compare against.
|
|
50
|
+
The failure then goes unnoticed and the bogus handle reaches
|
|
51
|
+
msvcrt.open_osfhandle, whose fd raises EBADF ("Bad file descriptor") on
|
|
52
|
+
first use — hiding the actual Windows error.
|
|
53
|
+
|
|
54
|
+
Re-declaring on every call is harmless and keeps this import-safe on
|
|
55
|
+
non-Windows (nothing here runs until a method is called).
|
|
56
|
+
"""
|
|
57
|
+
k = ctypes.windll.kernel32
|
|
58
|
+
k.CreateFileW.restype = ctypes.c_void_p
|
|
59
|
+
k.CreateFileW.argtypes = [ctypes.c_wchar_p, ctypes.c_uint32,
|
|
60
|
+
ctypes.c_uint32, ctypes.c_void_p,
|
|
61
|
+
ctypes.c_uint32, ctypes.c_uint32,
|
|
62
|
+
ctypes.c_void_p]
|
|
63
|
+
k.CloseHandle.argtypes = [ctypes.c_void_p]
|
|
64
|
+
k.DeviceIoControl.argtypes = [ctypes.c_void_p, ctypes.c_uint32,
|
|
65
|
+
ctypes.c_void_p, ctypes.c_uint32,
|
|
66
|
+
ctypes.c_void_p, ctypes.c_uint32,
|
|
67
|
+
ctypes.POINTER(ctypes.c_ulong),
|
|
68
|
+
ctypes.c_void_p]
|
|
69
|
+
return k
|
|
39
70
|
|
|
40
71
|
|
|
41
72
|
def _powershell(script):
|
|
@@ -73,24 +104,28 @@ class WindowsPlatform(Platform):
|
|
|
73
104
|
|
|
74
105
|
# -- low-level handle helpers -----------------------------------------
|
|
75
106
|
def _open_handle(self, path, write):
|
|
107
|
+
k = _k32()
|
|
76
108
|
access = GENERIC_READ | (GENERIC_WRITE if write else 0)
|
|
77
|
-
h =
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if h
|
|
81
|
-
|
|
82
|
-
|
|
109
|
+
h = k.CreateFileW(path, access,
|
|
110
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE, None,
|
|
111
|
+
OPEN_EXISTING, 0, None)
|
|
112
|
+
if h is None or h == INVALID_HANDLE_VALUE:
|
|
113
|
+
# Report what Windows actually said: error 5 (access denied) and 32
|
|
114
|
+
# (sharing violation) are the usual causes here, and both mean a
|
|
115
|
+
# volume on this disk is mounted and holding the sectors.
|
|
116
|
+
raise OSError("CreateFileW failed for %s: %s"
|
|
117
|
+
% (path, ctypes.WinError(k.GetLastError())))
|
|
83
118
|
return h
|
|
84
119
|
|
|
85
120
|
def _ioctl(self, handle, code, out_size=0):
|
|
121
|
+
k = _k32()
|
|
86
122
|
buf = ctypes.create_string_buffer(out_size) if out_size else None
|
|
87
123
|
returned = ctypes.c_ulong(0)
|
|
88
|
-
ok =
|
|
89
|
-
|
|
90
|
-
ctypes.byref(returned), None)
|
|
124
|
+
ok = k.DeviceIoControl(handle, code, None, 0, buf, out_size,
|
|
125
|
+
ctypes.byref(returned), None)
|
|
91
126
|
if not ok:
|
|
92
|
-
raise OSError("DeviceIoControl 0x%X failed
|
|
93
|
-
% (code, ctypes.
|
|
127
|
+
raise OSError("DeviceIoControl 0x%X failed: %s"
|
|
128
|
+
% (code, ctypes.WinError(k.GetLastError())))
|
|
94
129
|
return buf.raw[:returned.value] if buf else b""
|
|
95
130
|
|
|
96
131
|
# -- device discovery / selection -------------------------------------
|
|
@@ -237,7 +272,15 @@ class WindowsPlatform(Platform):
|
|
|
237
272
|
if os.path.isfile(dev):
|
|
238
273
|
return open(dev, mode)
|
|
239
274
|
import msvcrt
|
|
240
|
-
|
|
275
|
+
write = ("w" in mode or "+" in mode or "a" in mode)
|
|
276
|
+
if write:
|
|
277
|
+
# FSCTL_LOCK_VOLUME only holds while the locking handle is open, so
|
|
278
|
+
# the dismount done before write_layout is already undone by now:
|
|
279
|
+
# writing the new MBR makes Windows rescan and re-mount the data
|
|
280
|
+
# partition, and it then refuses writes into those sectors. Dismount
|
|
281
|
+
# again immediately before each write open.
|
|
282
|
+
self.unmount_all(dev, False)
|
|
283
|
+
h = self._open_handle(dev, write=write)
|
|
241
284
|
fd = msvcrt.open_osfhandle(h, os.O_BINARY)
|
|
242
285
|
return AlignedRawIO(os.fdopen(fd, mode, buffering=0))
|
|
243
286
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flashpod"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Command-line iPod sync + card-flashing tooling for early FireWire-era iPods, pure Python"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.6"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|