pymobiledevice3 6.1.5__py3-none-any.whl → 6.1.6__py3-none-any.whl
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.
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/services/afc.py +239 -215
- pymobiledevice3/services/mobilebackup2.py +2 -2
- {pymobiledevice3-6.1.5.dist-info → pymobiledevice3-6.1.6.dist-info}/METADATA +2 -1
- {pymobiledevice3-6.1.5.dist-info → pymobiledevice3-6.1.6.dist-info}/RECORD +9 -9
- {pymobiledevice3-6.1.5.dist-info → pymobiledevice3-6.1.6.dist-info}/WHEEL +0 -0
- {pymobiledevice3-6.1.5.dist-info → pymobiledevice3-6.1.6.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-6.1.5.dist-info → pymobiledevice3-6.1.6.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-6.1.5.dist-info → pymobiledevice3-6.1.6.dist-info}/top_level.txt +0 -0
pymobiledevice3/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '6.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (6, 1,
|
|
31
|
+
__version__ = version = '6.1.6'
|
|
32
|
+
__version_tuple__ = version_tuple = (6, 1, 6)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
pymobiledevice3/services/afc.py
CHANGED
|
@@ -18,13 +18,15 @@ import struct
|
|
|
18
18
|
import sys
|
|
19
19
|
import warnings
|
|
20
20
|
from collections import namedtuple
|
|
21
|
+
from dataclasses import dataclass, field
|
|
21
22
|
from datetime import datetime
|
|
22
23
|
from re import Pattern
|
|
23
24
|
from typing import Callable, Optional, Union
|
|
24
25
|
|
|
25
26
|
import hexdump
|
|
26
27
|
from click.exceptions import Exit
|
|
27
|
-
from construct import Const,
|
|
28
|
+
from construct import Const, CString, GreedyRange, Int64ul, Tell
|
|
29
|
+
from construct_typed import DataclassMixin, EnumBase, TEnum, TStruct, csfield
|
|
28
30
|
from parameter_decorators import path_to_str
|
|
29
31
|
from pygments import formatters, highlight, lexers
|
|
30
32
|
from pygnuutils.cli.ls import ls as ls_cli
|
|
@@ -63,188 +65,210 @@ StatResult = namedtuple(
|
|
|
63
65
|
],
|
|
64
66
|
)
|
|
65
67
|
|
|
66
|
-
afc_opcode_t = Enum(
|
|
67
|
-
Int64ul,
|
|
68
|
-
STATUS=0x00000001,
|
|
69
|
-
DATA=0x00000002, # Data */
|
|
70
|
-
READ_DIR=0x00000003, # ReadDir */
|
|
71
|
-
READ_FILE=0x00000004, # ReadFile */
|
|
72
|
-
WRITE_FILE=0x00000005, # WriteFile */
|
|
73
|
-
WRITE_PART=0x00000006, # WritePart */
|
|
74
|
-
TRUNCATE=0x00000007, # TruncateFile */
|
|
75
|
-
REMOVE_PATH=0x00000008, # RemovePath */
|
|
76
|
-
MAKE_DIR=0x00000009, # MakeDir */
|
|
77
|
-
GET_FILE_INFO=0x0000000A, # GetFileInfo */
|
|
78
|
-
GET_DEVINFO=0x0000000B, # GetDeviceInfo */
|
|
79
|
-
WRITE_FILE_ATOM=0x0000000C, # WriteFileAtomic (tmp file+rename) */
|
|
80
|
-
FILE_OPEN=0x0000000D, # FileRefOpen */
|
|
81
|
-
FILE_OPEN_RES=0x0000000E, # FileRefOpenResult */
|
|
82
|
-
READ=0x0000000F, # FileRefRead */
|
|
83
|
-
WRITE=0x00000010, # FileRefWrite */
|
|
84
|
-
FILE_SEEK=0x00000011, # FileRefSeek */
|
|
85
|
-
FILE_TELL=0x00000012, # FileRefTell */
|
|
86
|
-
FILE_TELL_RES=0x00000013, # FileRefTellResult */
|
|
87
|
-
FILE_CLOSE=0x00000014, # FileRefClose */
|
|
88
|
-
FILE_SET_SIZE=0x00000015, # FileRefSetFileSize (ftruncate) */
|
|
89
|
-
GET_CON_INFO=0x00000016, # GetConnectionInfo */
|
|
90
|
-
SET_CON_OPTIONS=0x00000017, # SetConnectionOptions */
|
|
91
|
-
RENAME_PATH=0x00000018, # RenamePath */
|
|
92
|
-
SET_FS_BS=0x00000019, # SetFSBlockSize (0x800000) */
|
|
93
|
-
SET_SOCKET_BS=0x0000001A, # SetSocketBlockSize (0x800000) */
|
|
94
|
-
FILE_LOCK=0x0000001B, # FileRefLock */
|
|
95
|
-
MAKE_LINK=0x0000001C, # MakeLink */
|
|
96
|
-
SET_FILE_TIME=0x0000001E, # set st_mtime */
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
afc_error_t = Enum(
|
|
100
|
-
Int64ul,
|
|
101
|
-
SUCCESS=0,
|
|
102
|
-
UNKNOWN_ERROR=1,
|
|
103
|
-
OP_HEADER_INVALID=2,
|
|
104
|
-
NO_RESOURCES=3,
|
|
105
|
-
READ_ERROR=4,
|
|
106
|
-
WRITE_ERROR=5,
|
|
107
|
-
UNKNOWN_PACKET_TYPE=6,
|
|
108
|
-
INVALID_ARG=7,
|
|
109
|
-
OBJECT_NOT_FOUND=8,
|
|
110
|
-
OBJECT_IS_DIR=9,
|
|
111
|
-
PERM_DENIED=10,
|
|
112
|
-
SERVICE_NOT_CONNECTED=11,
|
|
113
|
-
OP_TIMEOUT=12,
|
|
114
|
-
TOO_MUCH_DATA=13,
|
|
115
|
-
END_OF_DATA=14,
|
|
116
|
-
OP_NOT_SUPPORTED=15,
|
|
117
|
-
OBJECT_EXISTS=16,
|
|
118
|
-
OBJECT_BUSY=17,
|
|
119
|
-
NO_SPACE_LEFT=18,
|
|
120
|
-
OP_WOULD_BLOCK=19,
|
|
121
|
-
IO_ERROR=20,
|
|
122
|
-
OP_INTERRUPTED=21,
|
|
123
|
-
OP_IN_PROGRESS=22,
|
|
124
|
-
INTERNAL_ERROR=23,
|
|
125
|
-
MUX_ERROR=30,
|
|
126
|
-
NO_MEM=31,
|
|
127
|
-
NOT_ENOUGH_DATA=32,
|
|
128
|
-
DIR_NOT_EMPTY=33,
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
afc_link_type_t = Enum(
|
|
132
|
-
Int64ul,
|
|
133
|
-
HARDLINK=1,
|
|
134
|
-
SYMLINK=2,
|
|
135
|
-
)
|
|
136
68
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
69
|
+
class AfcOpcode(EnumBase):
|
|
70
|
+
STATUS = 0x00000001
|
|
71
|
+
DATA = 0x00000002 # Data
|
|
72
|
+
READ_DIR = 0x00000003 # ReadDir
|
|
73
|
+
READ_FILE = 0x00000004 # ReadFile
|
|
74
|
+
WRITE_FILE = 0x00000005 # WriteFile
|
|
75
|
+
WRITE_PART = 0x00000006 # WritePart
|
|
76
|
+
TRUNCATE = 0x00000007 # TruncateFile
|
|
77
|
+
REMOVE_PATH = 0x00000008 # RemovePath
|
|
78
|
+
MAKE_DIR = 0x00000009 # MakeDir
|
|
79
|
+
GET_FILE_INFO = 0x0000000A # GetFileInfo
|
|
80
|
+
GET_DEVINFO = 0x0000000B # GetDeviceInfo
|
|
81
|
+
WRITE_FILE_ATOM = 0x0000000C # WriteFileAtomic (tmp file+rename)
|
|
82
|
+
FILE_OPEN = 0x0000000D # FileRefOpen
|
|
83
|
+
FILE_OPEN_RES = 0x0000000E # FileRefOpenResult
|
|
84
|
+
READ = 0x0000000F # FileRefRead
|
|
85
|
+
WRITE = 0x00000010 # FileRefWrite
|
|
86
|
+
FILE_SEEK = 0x00000011 # FileRefSeek
|
|
87
|
+
FILE_TELL = 0x00000012 # FileRefTell
|
|
88
|
+
FILE_TELL_RES = 0x00000013 # FileRefTellResult
|
|
89
|
+
FILE_CLOSE = 0x00000014 # FileRefClose
|
|
90
|
+
FILE_SET_SIZE = 0x00000015 # FileRefSetFileSize (ftruncate)
|
|
91
|
+
GET_CON_INFO = 0x00000016 # GetConnectionInfo
|
|
92
|
+
SET_CON_OPTIONS = 0x00000017 # SetConnectionOptions
|
|
93
|
+
RENAME_PATH = 0x00000018 # RenamePath
|
|
94
|
+
SET_FS_BS = 0x00000019 # SetFSBlockSize (0x800000)
|
|
95
|
+
SET_SOCKET_BS = 0x0000001A # SetSocketBlockSize (0x800000)
|
|
96
|
+
FILE_LOCK = 0x0000001B # FileRefLock
|
|
97
|
+
MAKE_LINK = 0x0000001C # MakeLink
|
|
98
|
+
SET_FILE_TIME = 0x0000001E # set st_mtime
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class AfcError(EnumBase):
|
|
102
|
+
SUCCESS = 0
|
|
103
|
+
UNKNOWN_ERROR = 1
|
|
104
|
+
OP_HEADER_INVALID = 2
|
|
105
|
+
NO_RESOURCES = 3
|
|
106
|
+
READ_ERROR = 4
|
|
107
|
+
WRITE_ERROR = 5
|
|
108
|
+
UNKNOWN_PACKET_TYPE = 6
|
|
109
|
+
INVALID_ARG = 7
|
|
110
|
+
OBJECT_NOT_FOUND = 8
|
|
111
|
+
OBJECT_IS_DIR = 9
|
|
112
|
+
PERM_DENIED = 10
|
|
113
|
+
SERVICE_NOT_CONNECTED = 11
|
|
114
|
+
OP_TIMEOUT = 12
|
|
115
|
+
TOO_MUCH_DATA = 13
|
|
116
|
+
END_OF_DATA = 14
|
|
117
|
+
OP_NOT_SUPPORTED = 15
|
|
118
|
+
OBJECT_EXISTS = 16
|
|
119
|
+
OBJECT_BUSY = 17
|
|
120
|
+
NO_SPACE_LEFT = 18
|
|
121
|
+
OP_WOULD_BLOCK = 19
|
|
122
|
+
IO_ERROR = 20
|
|
123
|
+
OP_INTERRUPTED = 21
|
|
124
|
+
OP_IN_PROGRESS = 22
|
|
125
|
+
INTERNAL_ERROR = 23
|
|
126
|
+
MUX_ERROR = 30
|
|
127
|
+
NO_MEM = 31
|
|
128
|
+
NOT_ENOUGH_DATA = 32
|
|
129
|
+
DIR_NOT_EMPTY = 33
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class AfcLinkType(EnumBase):
|
|
133
|
+
HARDLINK = 1
|
|
134
|
+
SYMLINK = 2
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class AfcFopenMode(EnumBase):
|
|
138
|
+
RDONLY = 0x00000001 # r O_RDONLY
|
|
139
|
+
RW = 0x00000002 # r+ O_RDWR | O_CREAT
|
|
140
|
+
WRONLY = 0x00000003 # w O_WRONLY | O_CREAT | O_TRUNC
|
|
141
|
+
WR = 0x00000004 # w+ O_RDWR | O_CREAT | O_TRUNC
|
|
142
|
+
APPEND = 0x00000005 # a O_WRONLY | O_APPEND | O_CREAT
|
|
143
|
+
RDAPPEND = 0x00000006 # a+ O_RDWR | O_APPEND | O_CREAT
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# typed construct adapters for the enums
|
|
147
|
+
afc_opcode_t = TEnum(Int64ul, AfcOpcode)
|
|
148
|
+
afc_error_construct = TEnum(Int64ul, AfcError)
|
|
149
|
+
afc_link_type_construct = TEnum(Int64ul, AfcLinkType)
|
|
150
|
+
afc_fopen_mode_construct = TEnum(Int64ul, AfcFopenMode)
|
|
146
151
|
|
|
147
152
|
AFC_FOPEN_TEXTUAL_MODES = {
|
|
148
|
-
"r":
|
|
149
|
-
"r+":
|
|
150
|
-
"w":
|
|
151
|
-
"w+":
|
|
152
|
-
"a":
|
|
153
|
-
"a+":
|
|
153
|
+
"r": AfcFopenMode.RDONLY,
|
|
154
|
+
"r+": AfcFopenMode.RW,
|
|
155
|
+
"w": AfcFopenMode.WRONLY,
|
|
156
|
+
"w+": AfcFopenMode.WR,
|
|
157
|
+
"a": AfcFopenMode.APPEND,
|
|
158
|
+
"a+": AfcFopenMode.RDAPPEND,
|
|
154
159
|
}
|
|
155
160
|
|
|
156
|
-
AFC_LOCK_SH = 1 | 4 #
|
|
157
|
-
AFC_LOCK_EX = 2 | 4 #
|
|
158
|
-
AFC_LOCK_UN = 8 | 4 #
|
|
161
|
+
AFC_LOCK_SH = 1 | 4 # shared lock
|
|
162
|
+
AFC_LOCK_EX = 2 | 4 # exclusive lock
|
|
163
|
+
AFC_LOCK_UN = 8 | 4 # unlock
|
|
159
164
|
|
|
160
165
|
MAXIMUM_WRITE_SIZE = 1 << 30
|
|
161
166
|
|
|
162
167
|
AFCMAGIC = b"CFA6LPAA"
|
|
163
168
|
|
|
164
|
-
afc_header_t = Struct(
|
|
165
|
-
"magic" / Const(AFCMAGIC),
|
|
166
|
-
"entire_length" / Int64ul,
|
|
167
|
-
"this_length" / Int64ul,
|
|
168
|
-
"packet_num" / Int64ul,
|
|
169
|
-
"operation" / afc_opcode_t,
|
|
170
|
-
"_data_offset" / Tell,
|
|
171
|
-
)
|
|
172
169
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
)
|
|
170
|
+
@dataclass
|
|
171
|
+
class AfcHeader(DataclassMixin):
|
|
172
|
+
magic: bytes = csfield(Const(AFCMAGIC))
|
|
173
|
+
entire_length: int = csfield(Int64ul)
|
|
174
|
+
this_length: int = csfield(Int64ul)
|
|
175
|
+
packet_num: int = csfield(Int64ul)
|
|
176
|
+
operation: AfcOpcode = csfield(afc_opcode_t)
|
|
177
|
+
_data_offset: int = field(default=0, init=False, metadata={"subcon": Tell})
|
|
176
178
|
|
|
177
|
-
afc_read_dir_resp_t = Struct(
|
|
178
|
-
"filenames" / GreedyRange(CString("utf8")),
|
|
179
|
-
)
|
|
180
179
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
)
|
|
180
|
+
@dataclass
|
|
181
|
+
class AfcReadDirRequest(DataclassMixin):
|
|
182
|
+
filename: str = csfield(CString("utf8"))
|
|
184
183
|
|
|
185
|
-
afc_stat_t = Struct(
|
|
186
|
-
"filename" / CString("utf8"),
|
|
187
|
-
)
|
|
188
184
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
"source" / CString("utf8"),
|
|
193
|
-
)
|
|
185
|
+
@dataclass
|
|
186
|
+
class AfcReadDirResponse(DataclassMixin):
|
|
187
|
+
filenames: list[str] = csfield(GreedyRange(CString("utf8")))
|
|
194
188
|
|
|
195
|
-
afc_fopen_req_t = Struct(
|
|
196
|
-
"mode" / afc_fopen_mode_t,
|
|
197
|
-
"filename" / CString("utf8"),
|
|
198
|
-
)
|
|
199
189
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
)
|
|
190
|
+
@dataclass
|
|
191
|
+
class AfcMkdirRequest(DataclassMixin):
|
|
192
|
+
filename: str = csfield(CString("utf8"))
|
|
203
193
|
|
|
204
|
-
afc_fclose_req_t = Struct(
|
|
205
|
-
"handle" / Int64ul,
|
|
206
|
-
)
|
|
207
194
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
)
|
|
195
|
+
@dataclass
|
|
196
|
+
class AfcStatRequest(DataclassMixin):
|
|
197
|
+
filename: str = csfield(CString("utf8"))
|
|
211
198
|
|
|
212
|
-
afc_rename_req_t = Struct(
|
|
213
|
-
"source" / CString("utf8"),
|
|
214
|
-
"target" / CString("utf8"),
|
|
215
|
-
)
|
|
216
199
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
)
|
|
200
|
+
@dataclass
|
|
201
|
+
class AfcMakeLinkRequest(DataclassMixin):
|
|
202
|
+
type: AfcLinkType = csfield(afc_link_type_construct)
|
|
203
|
+
target: str = csfield(CString("utf8"))
|
|
204
|
+
source: str = csfield(CString("utf8"))
|
|
221
205
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
)
|
|
206
|
+
|
|
207
|
+
@dataclass
|
|
208
|
+
class AfcFopenRequest(DataclassMixin):
|
|
209
|
+
mode: AfcFopenMode = csfield(afc_fopen_mode_construct)
|
|
210
|
+
filename: str = csfield(CString("utf8"))
|
|
226
211
|
|
|
227
212
|
|
|
228
|
-
|
|
213
|
+
@dataclass
|
|
214
|
+
class AfcFopenResponse(DataclassMixin):
|
|
215
|
+
handle: int = csfield(Int64ul)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@dataclass
|
|
219
|
+
class AfcFcloseRequest(DataclassMixin):
|
|
220
|
+
handle: int = csfield(Int64ul)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@dataclass
|
|
224
|
+
class AfcRmRequest(DataclassMixin):
|
|
225
|
+
filename: str = csfield(CString("utf8"))
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@dataclass
|
|
229
|
+
class AfcRenameRequest(DataclassMixin):
|
|
230
|
+
source: str = csfield(CString("utf8"))
|
|
231
|
+
target: str = csfield(CString("utf8"))
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@dataclass
|
|
235
|
+
class AfcFreadRequest(DataclassMixin):
|
|
236
|
+
handle: int = csfield(Int64ul)
|
|
237
|
+
size: int = csfield(Int64ul)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@dataclass
|
|
241
|
+
class AfcLockRequest(DataclassMixin):
|
|
242
|
+
handle: int = csfield(Int64ul)
|
|
243
|
+
op: int = csfield(Int64ul)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
afc_header_t = TStruct(AfcHeader)
|
|
247
|
+
afc_read_dir_req_t = TStruct(AfcReadDirRequest)
|
|
248
|
+
afc_read_dir_resp_t = TStruct(AfcReadDirResponse)
|
|
249
|
+
afc_mkdir_req_t = TStruct(AfcMkdirRequest)
|
|
250
|
+
afc_stat_t = TStruct(AfcStatRequest)
|
|
251
|
+
afc_make_link_req_t = TStruct(AfcMakeLinkRequest)
|
|
252
|
+
afc_fopen_req_t = TStruct(AfcFopenRequest)
|
|
253
|
+
afc_fopen_resp_t = TStruct(AfcFopenResponse)
|
|
254
|
+
afc_fclose_req_t = TStruct(AfcFcloseRequest)
|
|
255
|
+
afc_rm_req_t = TStruct(AfcRmRequest)
|
|
256
|
+
afc_rename_req_t = TStruct(AfcRenameRequest)
|
|
257
|
+
afc_fread_req_t = TStruct(AfcFreadRequest)
|
|
258
|
+
afc_lock_t = TStruct(AfcLockRequest)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def list_to_dict(raw: bytes) -> dict[str, str]:
|
|
229
262
|
"""
|
|
230
263
|
Convert a null-terminated key-value list to a dictionary.
|
|
231
264
|
|
|
232
265
|
The input is expected to be a byte string with alternating keys and values,
|
|
233
|
-
each separated by null bytes (
|
|
234
|
-
|
|
235
|
-
:param d: Byte string containing null-terminated key-value pairs
|
|
236
|
-
:return: Dictionary mapping keys to values
|
|
237
|
-
:raises: AssertionError if the list doesn't contain an even number of elements
|
|
266
|
+
each separated by null bytes (``\\x00``).
|
|
238
267
|
"""
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
assert len(t) % 2 == 0
|
|
244
|
-
res = {}
|
|
245
|
-
for i in range(int(len(t) / 2)):
|
|
246
|
-
res[t[i * 2]] = t[i * 2 + 1]
|
|
247
|
-
return res
|
|
268
|
+
parts = raw.decode("utf-8").split("\x00")[:-1]
|
|
269
|
+
if len(parts) % 2:
|
|
270
|
+
raise ValueError("AFC list is not key/value aligned")
|
|
271
|
+
return dict(zip(parts[::2], parts[1::2]))
|
|
248
272
|
|
|
249
273
|
|
|
250
274
|
class AfcService(LockdownService):
|
|
@@ -314,15 +338,13 @@ class AfcService(LockdownService):
|
|
|
314
338
|
if src_size <= MAXIMUM_READ_SIZE:
|
|
315
339
|
f.write(self.get_file_contents(src))
|
|
316
340
|
else:
|
|
317
|
-
left_size = src_size
|
|
318
341
|
handle = self.fopen(src)
|
|
342
|
+
iterator = range(0, src_size, MAXIMUM_READ_SIZE)
|
|
319
343
|
if progress_bar:
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
f.write(self.fread(handle, min(MAXIMUM_READ_SIZE, left_size)))
|
|
325
|
-
left_size -= MAXIMUM_READ_SIZE
|
|
344
|
+
iterator = trange(0, src_size, MAXIMUM_READ_SIZE)
|
|
345
|
+
for offset in iterator:
|
|
346
|
+
to_read = min(MAXIMUM_READ_SIZE, src_size - offset)
|
|
347
|
+
f.write(self.fread(handle, to_read))
|
|
326
348
|
self.fclose(handle)
|
|
327
349
|
os.utime(dst, (os.stat(dst).st_atime, self.stat(src)["st_mtime"].timestamp()))
|
|
328
350
|
if callback is not None:
|
|
@@ -464,7 +486,7 @@ class AfcService(LockdownService):
|
|
|
464
486
|
:rtype: bool
|
|
465
487
|
"""
|
|
466
488
|
try:
|
|
467
|
-
self._do_operation(
|
|
489
|
+
self._do_operation(AfcOpcode.REMOVE_PATH, afc_rm_req_t.build(AfcRmRequest(filename=filename)), filename)
|
|
468
490
|
except AfcException:
|
|
469
491
|
if force:
|
|
470
492
|
return False
|
|
@@ -532,7 +554,7 @@ class AfcService(LockdownService):
|
|
|
532
554
|
|
|
533
555
|
:return: Dictionary containing device file system information
|
|
534
556
|
"""
|
|
535
|
-
return list_to_dict(self._do_operation(
|
|
557
|
+
return list_to_dict(self._do_operation(AfcOpcode.GET_DEVINFO))
|
|
536
558
|
|
|
537
559
|
@path_to_str()
|
|
538
560
|
def listdir(self, filename: str):
|
|
@@ -543,7 +565,7 @@ class AfcService(LockdownService):
|
|
|
543
565
|
:return: List of filenames in the directory (excluding '.' and '..')
|
|
544
566
|
:raises: AfcException if the path is not a directory or doesn't exist
|
|
545
567
|
"""
|
|
546
|
-
data = self._do_operation(
|
|
568
|
+
data = self._do_operation(AfcOpcode.READ_DIR, afc_read_dir_req_t.build(AfcReadDirRequest(filename=filename)))
|
|
547
569
|
return afc_read_dir_resp_t.parse(data).filenames[2:] # skip the . and ..
|
|
548
570
|
|
|
549
571
|
@path_to_str()
|
|
@@ -556,7 +578,7 @@ class AfcService(LockdownService):
|
|
|
556
578
|
:param filename: Path of the directory to create
|
|
557
579
|
:return: Response data from the operation
|
|
558
580
|
"""
|
|
559
|
-
return self._do_operation(
|
|
581
|
+
return self._do_operation(AfcOpcode.MAKE_DIR, afc_mkdir_req_t.build(AfcMkdirRequest(filename=filename)))
|
|
560
582
|
|
|
561
583
|
@path_to_str()
|
|
562
584
|
def isdir(self, filename: str) -> bool:
|
|
@@ -580,10 +602,12 @@ class AfcService(LockdownService):
|
|
|
580
602
|
"""
|
|
581
603
|
try:
|
|
582
604
|
stat = list_to_dict(
|
|
583
|
-
self._do_operation(
|
|
605
|
+
self._do_operation(
|
|
606
|
+
AfcOpcode.GET_FILE_INFO, afc_stat_t.build(AfcStatRequest(filename=filename)), filename
|
|
607
|
+
)
|
|
584
608
|
)
|
|
585
609
|
except AfcException as e:
|
|
586
|
-
if e.status !=
|
|
610
|
+
if e.status != AfcError.READ_ERROR:
|
|
587
611
|
raise
|
|
588
612
|
raise AfcFileNotFoundError(e.args[0], e.status) from e
|
|
589
613
|
|
|
@@ -629,7 +653,7 @@ class AfcService(LockdownService):
|
|
|
629
653
|
)
|
|
630
654
|
|
|
631
655
|
@path_to_str()
|
|
632
|
-
def link(self, target: str, source: str, type_=
|
|
656
|
+
def link(self, target: str, source: str, type_=AfcLinkType.SYMLINK):
|
|
633
657
|
"""
|
|
634
658
|
Create a symbolic or hard link on the device.
|
|
635
659
|
|
|
@@ -639,7 +663,8 @@ class AfcService(LockdownService):
|
|
|
639
663
|
:return: Response data from the operation
|
|
640
664
|
"""
|
|
641
665
|
return self._do_operation(
|
|
642
|
-
|
|
666
|
+
AfcOpcode.MAKE_LINK,
|
|
667
|
+
afc_make_link_req_t.build(AfcMakeLinkRequest(type=type_, target=target, source=source)),
|
|
643
668
|
)
|
|
644
669
|
|
|
645
670
|
@path_to_str()
|
|
@@ -656,7 +681,10 @@ class AfcService(LockdownService):
|
|
|
656
681
|
raise ArgumentError(f"mode can be only one of: {AFC_FOPEN_TEXTUAL_MODES.keys()}")
|
|
657
682
|
|
|
658
683
|
data = self._do_operation(
|
|
659
|
-
|
|
684
|
+
AfcOpcode.FILE_OPEN,
|
|
685
|
+
afc_fopen_req_t.build(
|
|
686
|
+
AfcFopenRequest(mode=AFC_FOPEN_TEXTUAL_MODES[mode], filename=filename),
|
|
687
|
+
),
|
|
660
688
|
)
|
|
661
689
|
return afc_fopen_resp_t.parse(data).handle
|
|
662
690
|
|
|
@@ -667,7 +695,7 @@ class AfcService(LockdownService):
|
|
|
667
695
|
:param handle: File handle returned from fopen
|
|
668
696
|
:return: Response data from the operation
|
|
669
697
|
"""
|
|
670
|
-
return self._do_operation(
|
|
698
|
+
return self._do_operation(AfcOpcode.FILE_CLOSE, afc_fclose_req_t.build(AfcFcloseRequest(handle=handle)))
|
|
671
699
|
|
|
672
700
|
@path_to_str()
|
|
673
701
|
def rename(self, source: str, target: str) -> None:
|
|
@@ -680,8 +708,8 @@ class AfcService(LockdownService):
|
|
|
680
708
|
"""
|
|
681
709
|
try:
|
|
682
710
|
self._do_operation(
|
|
683
|
-
|
|
684
|
-
afc_rename_req_t.build(
|
|
711
|
+
AfcOpcode.RENAME_PATH,
|
|
712
|
+
afc_rename_req_t.build(AfcRenameRequest(source=source, target=target)),
|
|
685
713
|
)
|
|
686
714
|
except AfcException as e:
|
|
687
715
|
if self.exists(source):
|
|
@@ -690,7 +718,7 @@ class AfcService(LockdownService):
|
|
|
690
718
|
f"Failed to rename {source} into {target}. Got status: {e.status}", e.args[0], str(e.status)
|
|
691
719
|
) from e
|
|
692
720
|
|
|
693
|
-
def fread(self, handle: int, sz:
|
|
721
|
+
def fread(self, handle: int, sz: int) -> bytes:
|
|
694
722
|
"""
|
|
695
723
|
Read data from an open file handle.
|
|
696
724
|
|
|
@@ -704,15 +732,15 @@ class AfcService(LockdownService):
|
|
|
704
732
|
data = b""
|
|
705
733
|
while sz > 0:
|
|
706
734
|
to_read = MAXIMUM_READ_SIZE if sz > MAXIMUM_READ_SIZE else sz
|
|
707
|
-
self._dispatch_packet(
|
|
735
|
+
self._dispatch_packet(AfcOpcode.READ, afc_fread_req_t.build(AfcFreadRequest(handle=handle, size=to_read)))
|
|
708
736
|
status, chunk = self._receive_data()
|
|
709
|
-
if status !=
|
|
737
|
+
if status != AfcError.SUCCESS:
|
|
710
738
|
raise AfcException("fread error", status)
|
|
711
739
|
sz -= to_read
|
|
712
740
|
data += chunk
|
|
713
741
|
return data
|
|
714
742
|
|
|
715
|
-
def fwrite(self, handle, data, chunk_size=MAXIMUM_WRITE_SIZE):
|
|
743
|
+
def fwrite(self, handle: int, data: bytes, chunk_size: int = MAXIMUM_WRITE_SIZE) -> None:
|
|
716
744
|
"""
|
|
717
745
|
Write data to an open file handle.
|
|
718
746
|
|
|
@@ -725,24 +753,20 @@ class AfcService(LockdownService):
|
|
|
725
753
|
"""
|
|
726
754
|
file_handle = struct.pack("<Q", handle)
|
|
727
755
|
chunks_count = len(data) // chunk_size
|
|
728
|
-
b = b""
|
|
729
756
|
for i in range(chunks_count):
|
|
730
757
|
chunk = data[i * chunk_size : (i + 1) * chunk_size]
|
|
731
|
-
self._dispatch_packet(
|
|
732
|
-
b += chunk
|
|
758
|
+
self._dispatch_packet(AfcOpcode.WRITE, file_handle + chunk, this_length=48)
|
|
733
759
|
|
|
734
760
|
status, _response = self._receive_data()
|
|
735
|
-
if status !=
|
|
761
|
+
if status != AfcError.SUCCESS:
|
|
736
762
|
raise AfcException(f"failed to write chunk: {status}", status)
|
|
737
763
|
|
|
738
764
|
if len(data) % chunk_size:
|
|
739
765
|
chunk = data[chunks_count * chunk_size :]
|
|
740
|
-
self._dispatch_packet(
|
|
741
|
-
|
|
742
|
-
b += chunk
|
|
766
|
+
self._dispatch_packet(AfcOpcode.WRITE, file_handle + chunk, this_length=48)
|
|
743
767
|
|
|
744
768
|
status, _response = self._receive_data()
|
|
745
|
-
if status !=
|
|
769
|
+
if status != AfcError.SUCCESS:
|
|
746
770
|
raise AfcException(f"failed to write last chunk: {status}", status)
|
|
747
771
|
|
|
748
772
|
@path_to_str()
|
|
@@ -777,7 +801,7 @@ class AfcService(LockdownService):
|
|
|
777
801
|
info = self.stat(filename)
|
|
778
802
|
|
|
779
803
|
if info["st_ifmt"] != "S_IFREG":
|
|
780
|
-
raise AfcException(f"{filename} isn't a file",
|
|
804
|
+
raise AfcException(f"{filename} isn't a file", AfcError.INVALID_ARG)
|
|
781
805
|
|
|
782
806
|
h = self.fopen(filename)
|
|
783
807
|
if not h:
|
|
@@ -855,9 +879,9 @@ class AfcService(LockdownService):
|
|
|
855
879
|
:param operation: Lock operation (AFC_LOCK_SH, AFC_LOCK_EX, or AFC_LOCK_UN)
|
|
856
880
|
:return: Response data from the operation
|
|
857
881
|
"""
|
|
858
|
-
return self._do_operation(
|
|
882
|
+
return self._do_operation(AfcOpcode.FILE_LOCK, afc_lock_t.build(AfcLockRequest(handle=handle, op=operation)))
|
|
859
883
|
|
|
860
|
-
def _dispatch_packet(self, operation, data, this_length=0):
|
|
884
|
+
def _dispatch_packet(self, operation: AfcOpcode, data: bytes, this_length: int = 0) -> None:
|
|
861
885
|
"""
|
|
862
886
|
Send an AFC protocol packet to the device.
|
|
863
887
|
|
|
@@ -865,16 +889,15 @@ class AfcService(LockdownService):
|
|
|
865
889
|
:param data: Packet payload data
|
|
866
890
|
:param this_length: Override for the packet length field (0 for auto-calculation)
|
|
867
891
|
"""
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
892
|
+
entire_length = afc_header_t.sizeof() + len(data)
|
|
893
|
+
header = afc_header_t.build(
|
|
894
|
+
AfcHeader(
|
|
895
|
+
entire_length=entire_length,
|
|
896
|
+
this_length=this_length or entire_length,
|
|
897
|
+
packet_num=self.packet_num,
|
|
898
|
+
operation=operation,
|
|
899
|
+
)
|
|
874
900
|
)
|
|
875
|
-
if this_length:
|
|
876
|
-
afcpack.this_length = this_length
|
|
877
|
-
header = afc_header_t.build(afcpack)
|
|
878
901
|
self.packet_num += 1
|
|
879
902
|
self.service.sendall(header + data)
|
|
880
903
|
|
|
@@ -884,23 +907,23 @@ class AfcService(LockdownService):
|
|
|
884
907
|
|
|
885
908
|
:return: Tuple of (status_code, response_data)
|
|
886
909
|
"""
|
|
887
|
-
|
|
888
|
-
status =
|
|
889
|
-
data = ""
|
|
890
|
-
if
|
|
891
|
-
|
|
892
|
-
assert
|
|
893
|
-
length =
|
|
910
|
+
header_bytes = self.service.recvall(afc_header_t.sizeof())
|
|
911
|
+
status = AfcError.SUCCESS
|
|
912
|
+
data = b""
|
|
913
|
+
if header_bytes:
|
|
914
|
+
header = afc_header_t.parse(header_bytes)
|
|
915
|
+
assert header.entire_length >= afc_header_t.sizeof()
|
|
916
|
+
length = header.entire_length - afc_header_t.sizeof()
|
|
894
917
|
data = self.service.recvall(length)
|
|
895
|
-
if
|
|
918
|
+
if header.operation == AfcOpcode.STATUS:
|
|
896
919
|
if length != 8:
|
|
897
920
|
self.logger.error("Status length != 8")
|
|
898
|
-
status =
|
|
899
|
-
elif
|
|
900
|
-
|
|
921
|
+
status = afc_error_construct.parse(data)
|
|
922
|
+
elif header.operation != AfcOpcode.DATA:
|
|
923
|
+
self.logger.debug("Unexpected AFC opcode %s", header.operation)
|
|
901
924
|
return status, data
|
|
902
925
|
|
|
903
|
-
def _do_operation(self, opcode:
|
|
926
|
+
def _do_operation(self, opcode: AfcOpcode, data: bytes = b"", filename: Optional[str] = None) -> bytes:
|
|
904
927
|
"""
|
|
905
928
|
Performs a low-level operation using the specified opcode and additional data.
|
|
906
929
|
|
|
@@ -924,11 +947,12 @@ class AfcService(LockdownService):
|
|
|
924
947
|
status, data = self._receive_data()
|
|
925
948
|
|
|
926
949
|
exception = AfcException
|
|
927
|
-
if status !=
|
|
928
|
-
if status ==
|
|
950
|
+
if status != AfcError.SUCCESS:
|
|
951
|
+
if status == AfcError.OBJECT_NOT_FOUND:
|
|
929
952
|
exception = AfcFileNotFoundError
|
|
930
953
|
|
|
931
|
-
|
|
954
|
+
opcode_name = opcode.name if isinstance(opcode, AfcOpcode) else opcode
|
|
955
|
+
message = f"Opcode: {opcode_name} failed with status: {status}"
|
|
932
956
|
if filename is not None:
|
|
933
957
|
message += f" for file: {filename}"
|
|
934
958
|
raise exception(message, status, filename)
|
|
@@ -1257,7 +1281,7 @@ class AfcShell:
|
|
|
1257
1281
|
:param target: Target path that the link will point to
|
|
1258
1282
|
:param source: Path where the link will be created
|
|
1259
1283
|
"""
|
|
1260
|
-
self.afc.link(self.relative_path(target), self.relative_path(source),
|
|
1284
|
+
self.afc.link(self.relative_path(target), self.relative_path(source), AfcLinkType.SYMLINK)
|
|
1261
1285
|
|
|
1262
1286
|
def _do_cd(self, directory: Annotated[str, Arg(completer=dir_completer)]) -> None:
|
|
1263
1287
|
"""
|
|
@@ -1320,8 +1344,8 @@ class AfcShell:
|
|
|
1320
1344
|
self,
|
|
1321
1345
|
remote_path: Annotated[str, Arg(completer=path_completer)],
|
|
1322
1346
|
local_path: str,
|
|
1323
|
-
ignore_errors: bool = False,
|
|
1324
|
-
progress_bar: bool = False,
|
|
1347
|
+
ignore_errors: Annotated[bool, Arg("--ignore-errors", action="store_true")] = False,
|
|
1348
|
+
progress_bar: Annotated[bool, Arg("--progress-bar", action="store_true")] = False,
|
|
1325
1349
|
) -> None:
|
|
1326
1350
|
"""
|
|
1327
1351
|
Pull a file or directory from device to local machine.
|
|
@@ -16,7 +16,7 @@ from pymobiledevice3.exceptions import (
|
|
|
16
16
|
)
|
|
17
17
|
from pymobiledevice3.lockdown import LockdownClient
|
|
18
18
|
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
19
|
-
from pymobiledevice3.services.afc import AFC_LOCK_EX, AFC_LOCK_UN,
|
|
19
|
+
from pymobiledevice3.services.afc import AFC_LOCK_EX, AFC_LOCK_UN, AfcError, AfcService
|
|
20
20
|
from pymobiledevice3.services.device_link import DeviceLink
|
|
21
21
|
from pymobiledevice3.services.installation_proxy import InstallationProxyService
|
|
22
22
|
from pymobiledevice3.services.lockdown_service import LockdownService
|
|
@@ -386,7 +386,7 @@ class Mobilebackup2Service(LockdownService):
|
|
|
386
386
|
try:
|
|
387
387
|
afc.lock(lockfile, AFC_LOCK_EX)
|
|
388
388
|
except AfcException as e:
|
|
389
|
-
if e.status ==
|
|
389
|
+
if e.status == AfcError.OP_WOULD_BLOCK:
|
|
390
390
|
time.sleep(0.2)
|
|
391
391
|
else:
|
|
392
392
|
afc.fclose(lockfile)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pymobiledevice3
|
|
3
|
-
Version: 6.1.
|
|
3
|
+
Version: 6.1.6
|
|
4
4
|
Summary: Pure python3 implementation for working with iDevices (iPhone, etc...)
|
|
5
5
|
Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
|
|
6
6
|
Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
|
|
@@ -21,6 +21,7 @@ Requires-Python: >=3.9
|
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
23
|
Requires-Dist: construct>=2.9.29
|
|
24
|
+
Requires-Dist: construct-typing>=0.7.0
|
|
24
25
|
Requires-Dist: asn1
|
|
25
26
|
Requires-Dist: click
|
|
26
27
|
Requires-Dist: coloredlogs
|
|
@@ -8,7 +8,7 @@ misc/understanding_idevice_protocol_layers.md,sha256=8tEqRXWOUPoxOJLZVh7C7H9JGCh
|
|
|
8
8
|
misc/usbmux_sniff.sh,sha256=iWtbucOEQ9_UEFXk9x-2VNt48Jg5zrPsnUbZ_LfZxwA,212
|
|
9
9
|
pymobiledevice3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
pymobiledevice3/__main__.py,sha256=hpLgWH1Pmwkf1pX-JvYkfJUkphpEb4YhoRV3qQUwbOs,12718
|
|
11
|
-
pymobiledevice3/_version.py,sha256=
|
|
11
|
+
pymobiledevice3/_version.py,sha256=Ec6zPeP28xAN98SxhNS4Y3DF-kiPUdlSd205c6mn9wo,704
|
|
12
12
|
pymobiledevice3/bonjour.py,sha256=y1Zd-__GnvK2ShxmvqFpNfi5NGF6PEWGcuKp8mJVFNA,13419
|
|
13
13
|
pymobiledevice3/ca.py,sha256=5_Y4F-zDFX_KeDL-M_TRCKKyrRRb9h1lBE8MGTWv91o,10606
|
|
14
14
|
pymobiledevice3/common.py,sha256=FZzF0BQYV5fCEUPbLo6jbt2Ig9s5YwR8AvX_iR124Ew,329
|
|
@@ -100,7 +100,7 @@ pymobiledevice3/restore/restored_client.py,sha256=tv1hyIV7UBDb_OUwj_w6qJsH_x36oB
|
|
|
100
100
|
pymobiledevice3/restore/tss.py,sha256=EY8XpUaexHyDTtUCuXQnOgLVIFAikcs9p0ysNSG1Q0U,30818
|
|
101
101
|
pymobiledevice3/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
102
102
|
pymobiledevice3/services/accessibilityaudit.py,sha256=7AvGqfAqvsSULib06mpxP94-P-Zr4SwSZohgmbXLuog,15474
|
|
103
|
-
pymobiledevice3/services/afc.py,sha256=
|
|
103
|
+
pymobiledevice3/services/afc.py,sha256=cIjOyeVDRkE1iKVLpSNt2UGI6jVbOiPoS-siLTeDyWw,55008
|
|
104
104
|
pymobiledevice3/services/amfi.py,sha256=SWGh5UQtf3YhD_4cT8M3dhH1sPE-mnIzkmiZjJ8d2x4,2522
|
|
105
105
|
pymobiledevice3/services/companion.py,sha256=6rvL1KF2-Gflv77rL9txINMoiQplVouL_nnGKNq-Maw,2612
|
|
106
106
|
pymobiledevice3/services/crash_reports.py,sha256=ODsgT3WgpOHIFM-ht9za_-xI9AAh7dKiq50NsRB5q3I,10945
|
|
@@ -119,7 +119,7 @@ pymobiledevice3/services/misagent.py,sha256=CGh1EhN_f1rV9RhZfP53OBirXdY0elX_nZS-
|
|
|
119
119
|
pymobiledevice3/services/mobile_activation.py,sha256=0zvQn2CMmf47--OtDqv3eOK5Ofu-eBw-ab1TxZSrOlY,9230
|
|
120
120
|
pymobiledevice3/services/mobile_config.py,sha256=2UmdqYNikznxI6bA2lkyIWS3NcHg3pTb5i6yLl8yZAY,18170
|
|
121
121
|
pymobiledevice3/services/mobile_image_mounter.py,sha256=PZEN9O7XtLW9VH1qNTJ19zo_tFZhX68bTX0O-Uy9sck,15034
|
|
122
|
-
pymobiledevice3/services/mobilebackup2.py,sha256=
|
|
122
|
+
pymobiledevice3/services/mobilebackup2.py,sha256=7hB0tNpNoLoneDNbMUmCpg0UhahT5QnF8fxSPwaqVWc,18297
|
|
123
123
|
pymobiledevice3/services/notification_proxy.py,sha256=mk4kxLRi6aDTXKOazgldliZG4q0bME7jBcxPyJsSpDw,2125
|
|
124
124
|
pymobiledevice3/services/os_trace.py,sha256=nTODlyWvb10fpqWHDU3m7i9sADIMF0ezfyo9Ql2BZa8,7422
|
|
125
125
|
pymobiledevice3/services/pcapd.py,sha256=Gd6xN9eBHnLIQ5M2LM-y4Z-eCquxVEnSKuyBECwZlRs,11960
|
|
@@ -167,9 +167,9 @@ pymobiledevice3/services/web_protocol/switch_to.py,sha256=TCdVrMfsvd18o-vZ0owVrE
|
|
|
167
167
|
pymobiledevice3/tunneld/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
168
168
|
pymobiledevice3/tunneld/api.py,sha256=Lwl1OdhPTgX6Zqezy8T4dEcXRfaEPwyGNClioTx3fUc,2338
|
|
169
169
|
pymobiledevice3/tunneld/server.py,sha256=dMEZAv_X-76l0vSalpq4x0IVkbE-MNGR77T-u1TiHuE,25752
|
|
170
|
-
pymobiledevice3-6.1.
|
|
171
|
-
pymobiledevice3-6.1.
|
|
172
|
-
pymobiledevice3-6.1.
|
|
173
|
-
pymobiledevice3-6.1.
|
|
174
|
-
pymobiledevice3-6.1.
|
|
175
|
-
pymobiledevice3-6.1.
|
|
170
|
+
pymobiledevice3-6.1.6.dist-info/licenses/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
|
|
171
|
+
pymobiledevice3-6.1.6.dist-info/METADATA,sha256=0M0UURfJmr_HkuOMOQO8Dqq6A8zPIR8C4iMcFkeqyvI,17455
|
|
172
|
+
pymobiledevice3-6.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
173
|
+
pymobiledevice3-6.1.6.dist-info/entry_points.txt,sha256=jJMlOanHlVwUxcY__JwvKeWPrvBJr_wJyEq4oHIZNKE,66
|
|
174
|
+
pymobiledevice3-6.1.6.dist-info/top_level.txt,sha256=MjZoRqcWPOh5banG-BbDOnKEfsS3kCxqV9cv-nzyg2Q,21
|
|
175
|
+
pymobiledevice3-6.1.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|