Spaces:
Configuration error
Configuration error
Upload 181 files
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- AUTHORS +21 -0
- COPYING +340 -0
- COPYING.LESSER +502 -0
- Makefile.am +21 -0
- NEWS +602 -0
- README.md +201 -10
- ac_pkg_cython.m4 +67 -0
- afc.c +1314 -0
- afc.h +110 -0
- afc.pxi +337 -0
- afcclient.c +1630 -0
- as-compiler-flag.m4 +62 -0
- asprintf.h +36 -0
- asr.c +461 -0
- asr.h +59 -0
- autogen.sh +26 -0
- ax_pthread.m4 +522 -0
- ax_python_devel.m4 +468 -0
- bt_packet_logger.c +231 -0
- bt_packet_logger.h +37 -0
- common.c +647 -0
- common.h +173 -0
- companion_proxy.c +380 -0
- companion_proxy.h +35 -0
- configure.ac +356 -0
- cython_python.m4 +7 -0
- debug.c +174 -0
- debug.h +53 -0
- debugserver.c +657 -0
- debugserver.h +44 -0
- debugserver.pxi +246 -0
- device_link_service.c +474 -0
- device_link_service.h +57 -0
- dfu.c +470 -0
- dfu.h +58 -0
- diagnostics_relay.c +467 -0
- diagnostics_relay.h +33 -0
- diagnostics_relay.pxi +128 -0
- download.c +156 -0
- download.h +38 -0
- doxygen.cfg.in +0 -0
- endianness.h +123 -0
- fdr.c +629 -0
- fdr.h +54 -0
- file_relay.c +165 -0
- file_relay.h +33 -0
- file_relay.pxi +68 -0
- fls.c +338 -0
- fls.h +85 -0
- ftab.c +197 -0
AUTHORS
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Bastien Nocera
|
| 2 |
+
Bryan Forbes
|
| 3 |
+
Christophe Fergeau
|
| 4 |
+
Geoff Paul
|
| 5 |
+
Ingmar Vanhassel
|
| 6 |
+
John Maguire
|
| 7 |
+
Jonathan Beck
|
| 8 |
+
Joshua Hill
|
| 9 |
+
Julien Lavergne
|
| 10 |
+
Martin Aumueller
|
| 11 |
+
Martin Szulecki
|
| 12 |
+
Marty Rosenberg
|
| 13 |
+
Matt Colyer
|
| 14 |
+
Nikias Bassen
|
| 15 |
+
Patrick Walton
|
| 16 |
+
Paul Sladen
|
| 17 |
+
Peter Hoepfner
|
| 18 |
+
Petr Uzel
|
| 19 |
+
Todd Zullinger
|
| 20 |
+
Zach C
|
| 21 |
+
Zoltan Balaton
|
COPYING
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
GNU GENERAL PUBLIC LICENSE
|
| 2 |
+
Version 2, June 1991
|
| 3 |
+
|
| 4 |
+
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
| 5 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 6 |
+
Everyone is permitted to copy and distribute verbatim copies
|
| 7 |
+
of this license document, but changing it is not allowed.
|
| 8 |
+
|
| 9 |
+
Preamble
|
| 10 |
+
|
| 11 |
+
The licenses for most software are designed to take away your
|
| 12 |
+
freedom to share and change it. By contrast, the GNU General Public
|
| 13 |
+
License is intended to guarantee your freedom to share and change free
|
| 14 |
+
software--to make sure the software is free for all its users. This
|
| 15 |
+
General Public License applies to most of the Free Software
|
| 16 |
+
Foundation's software and to any other program whose authors commit to
|
| 17 |
+
using it. (Some other Free Software Foundation software is covered by
|
| 18 |
+
the GNU Lesser General Public License instead.) You can apply it to
|
| 19 |
+
your programs, too.
|
| 20 |
+
|
| 21 |
+
When we speak of free software, we are referring to freedom, not
|
| 22 |
+
price. Our General Public Licenses are designed to make sure that you
|
| 23 |
+
have the freedom to distribute copies of free software (and charge for
|
| 24 |
+
this service if you wish), that you receive source code or can get it
|
| 25 |
+
if you want it, that you can change the software or use pieces of it
|
| 26 |
+
in new free programs; and that you know you can do these things.
|
| 27 |
+
|
| 28 |
+
To protect your rights, we need to make restrictions that forbid
|
| 29 |
+
anyone to deny you these rights or to ask you to surrender the rights.
|
| 30 |
+
These restrictions translate to certain responsibilities for you if you
|
| 31 |
+
distribute copies of the software, or if you modify it.
|
| 32 |
+
|
| 33 |
+
For example, if you distribute copies of such a program, whether
|
| 34 |
+
gratis or for a fee, you must give the recipients all the rights that
|
| 35 |
+
you have. You must make sure that they, too, receive or can get the
|
| 36 |
+
source code. And you must show them these terms so they know their
|
| 37 |
+
rights.
|
| 38 |
+
|
| 39 |
+
We protect your rights with two steps: (1) copyright the software, and
|
| 40 |
+
(2) offer you this license which gives you legal permission to copy,
|
| 41 |
+
distribute and/or modify the software.
|
| 42 |
+
|
| 43 |
+
Also, for each author's protection and ours, we want to make certain
|
| 44 |
+
that everyone understands that there is no warranty for this free
|
| 45 |
+
software. If the software is modified by someone else and passed on, we
|
| 46 |
+
want its recipients to know that what they have is not the original, so
|
| 47 |
+
that any problems introduced by others will not reflect on the original
|
| 48 |
+
authors' reputations.
|
| 49 |
+
|
| 50 |
+
Finally, any free program is threatened constantly by software
|
| 51 |
+
patents. We wish to avoid the danger that redistributors of a free
|
| 52 |
+
program will individually obtain patent licenses, in effect making the
|
| 53 |
+
program proprietary. To prevent this, we have made it clear that any
|
| 54 |
+
patent must be licensed for everyone's free use or not licensed at all.
|
| 55 |
+
|
| 56 |
+
The precise terms and conditions for copying, distribution and
|
| 57 |
+
modification follow.
|
| 58 |
+
|
| 59 |
+
GNU GENERAL PUBLIC LICENSE
|
| 60 |
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
| 61 |
+
|
| 62 |
+
0. This License applies to any program or other work which contains
|
| 63 |
+
a notice placed by the copyright holder saying it may be distributed
|
| 64 |
+
under the terms of this General Public License. The "Program", below,
|
| 65 |
+
refers to any such program or work, and a "work based on the Program"
|
| 66 |
+
means either the Program or any derivative work under copyright law:
|
| 67 |
+
that is to say, a work containing the Program or a portion of it,
|
| 68 |
+
either verbatim or with modifications and/or translated into another
|
| 69 |
+
language. (Hereinafter, translation is included without limitation in
|
| 70 |
+
the term "modification".) Each licensee is addressed as "you".
|
| 71 |
+
|
| 72 |
+
Activities other than copying, distribution and modification are not
|
| 73 |
+
covered by this License; they are outside its scope. The act of
|
| 74 |
+
running the Program is not restricted, and the output from the Program
|
| 75 |
+
is covered only if its contents constitute a work based on the
|
| 76 |
+
Program (independent of having been made by running the Program).
|
| 77 |
+
Whether that is true depends on what the Program does.
|
| 78 |
+
|
| 79 |
+
1. You may copy and distribute verbatim copies of the Program's
|
| 80 |
+
source code as you receive it, in any medium, provided that you
|
| 81 |
+
conspicuously and appropriately publish on each copy an appropriate
|
| 82 |
+
copyright notice and disclaimer of warranty; keep intact all the
|
| 83 |
+
notices that refer to this License and to the absence of any warranty;
|
| 84 |
+
and give any other recipients of the Program a copy of this License
|
| 85 |
+
along with the Program.
|
| 86 |
+
|
| 87 |
+
You may charge a fee for the physical act of transferring a copy, and
|
| 88 |
+
you may at your option offer warranty protection in exchange for a fee.
|
| 89 |
+
|
| 90 |
+
2. You may modify your copy or copies of the Program or any portion
|
| 91 |
+
of it, thus forming a work based on the Program, and copy and
|
| 92 |
+
distribute such modifications or work under the terms of Section 1
|
| 93 |
+
above, provided that you also meet all of these conditions:
|
| 94 |
+
|
| 95 |
+
a) You must cause the modified files to carry prominent notices
|
| 96 |
+
stating that you changed the files and the date of any change.
|
| 97 |
+
|
| 98 |
+
b) You must cause any work that you distribute or publish, that in
|
| 99 |
+
whole or in part contains or is derived from the Program or any
|
| 100 |
+
part thereof, to be licensed as a whole at no charge to all third
|
| 101 |
+
parties under the terms of this License.
|
| 102 |
+
|
| 103 |
+
c) If the modified program normally reads commands interactively
|
| 104 |
+
when run, you must cause it, when started running for such
|
| 105 |
+
interactive use in the most ordinary way, to print or display an
|
| 106 |
+
announcement including an appropriate copyright notice and a
|
| 107 |
+
notice that there is no warranty (or else, saying that you provide
|
| 108 |
+
a warranty) and that users may redistribute the program under
|
| 109 |
+
these conditions, and telling the user how to view a copy of this
|
| 110 |
+
License. (Exception: if the Program itself is interactive but
|
| 111 |
+
does not normally print such an announcement, your work based on
|
| 112 |
+
the Program is not required to print an announcement.)
|
| 113 |
+
|
| 114 |
+
These requirements apply to the modified work as a whole. If
|
| 115 |
+
identifiable sections of that work are not derived from the Program,
|
| 116 |
+
and can be reasonably considered independent and separate works in
|
| 117 |
+
themselves, then this License, and its terms, do not apply to those
|
| 118 |
+
sections when you distribute them as separate works. But when you
|
| 119 |
+
distribute the same sections as part of a whole which is a work based
|
| 120 |
+
on the Program, the distribution of the whole must be on the terms of
|
| 121 |
+
this License, whose permissions for other licensees extend to the
|
| 122 |
+
entire whole, and thus to each and every part regardless of who wrote it.
|
| 123 |
+
|
| 124 |
+
Thus, it is not the intent of this section to claim rights or contest
|
| 125 |
+
your rights to work written entirely by you; rather, the intent is to
|
| 126 |
+
exercise the right to control the distribution of derivative or
|
| 127 |
+
collective works based on the Program.
|
| 128 |
+
|
| 129 |
+
In addition, mere aggregation of another work not based on the Program
|
| 130 |
+
with the Program (or with a work based on the Program) on a volume of
|
| 131 |
+
a storage or distribution medium does not bring the other work under
|
| 132 |
+
the scope of this License.
|
| 133 |
+
|
| 134 |
+
3. You may copy and distribute the Program (or a work based on it,
|
| 135 |
+
under Section 2) in object code or executable form under the terms of
|
| 136 |
+
Sections 1 and 2 above provided that you also do one of the following:
|
| 137 |
+
|
| 138 |
+
a) Accompany it with the complete corresponding machine-readable
|
| 139 |
+
source code, which must be distributed under the terms of Sections
|
| 140 |
+
1 and 2 above on a medium customarily used for software interchange; or,
|
| 141 |
+
|
| 142 |
+
b) Accompany it with a written offer, valid for at least three
|
| 143 |
+
years, to give any third party, for a charge no more than your
|
| 144 |
+
cost of physically performing source distribution, a complete
|
| 145 |
+
machine-readable copy of the corresponding source code, to be
|
| 146 |
+
distributed under the terms of Sections 1 and 2 above on a medium
|
| 147 |
+
customarily used for software interchange; or,
|
| 148 |
+
|
| 149 |
+
c) Accompany it with the information you received as to the offer
|
| 150 |
+
to distribute corresponding source code. (This alternative is
|
| 151 |
+
allowed only for noncommercial distribution and only if you
|
| 152 |
+
received the program in object code or executable form with such
|
| 153 |
+
an offer, in accord with Subsection b above.)
|
| 154 |
+
|
| 155 |
+
The source code for a work means the preferred form of the work for
|
| 156 |
+
making modifications to it. For an executable work, complete source
|
| 157 |
+
code means all the source code for all modules it contains, plus any
|
| 158 |
+
associated interface definition files, plus the scripts used to
|
| 159 |
+
control compilation and installation of the executable. However, as a
|
| 160 |
+
special exception, the source code distributed need not include
|
| 161 |
+
anything that is normally distributed (in either source or binary
|
| 162 |
+
form) with the major components (compiler, kernel, and so on) of the
|
| 163 |
+
operating system on which the executable runs, unless that component
|
| 164 |
+
itself accompanies the executable.
|
| 165 |
+
|
| 166 |
+
If distribution of executable or object code is made by offering
|
| 167 |
+
access to copy from a designated place, then offering equivalent
|
| 168 |
+
access to copy the source code from the same place counts as
|
| 169 |
+
distribution of the source code, even though third parties are not
|
| 170 |
+
compelled to copy the source along with the object code.
|
| 171 |
+
|
| 172 |
+
4. You may not copy, modify, sublicense, or distribute the Program
|
| 173 |
+
except as expressly provided under this License. Any attempt
|
| 174 |
+
otherwise to copy, modify, sublicense or distribute the Program is
|
| 175 |
+
void, and will automatically terminate your rights under this License.
|
| 176 |
+
However, parties who have received copies, or rights, from you under
|
| 177 |
+
this License will not have their licenses terminated so long as such
|
| 178 |
+
parties remain in full compliance.
|
| 179 |
+
|
| 180 |
+
5. You are not required to accept this License, since you have not
|
| 181 |
+
signed it. However, nothing else grants you permission to modify or
|
| 182 |
+
distribute the Program or its derivative works. These actions are
|
| 183 |
+
prohibited by law if you do not accept this License. Therefore, by
|
| 184 |
+
modifying or distributing the Program (or any work based on the
|
| 185 |
+
Program), you indicate your acceptance of this License to do so, and
|
| 186 |
+
all its terms and conditions for copying, distributing or modifying
|
| 187 |
+
the Program or works based on it.
|
| 188 |
+
|
| 189 |
+
6. Each time you redistribute the Program (or any work based on the
|
| 190 |
+
Program), the recipient automatically receives a license from the
|
| 191 |
+
original licensor to copy, distribute or modify the Program subject to
|
| 192 |
+
these terms and conditions. You may not impose any further
|
| 193 |
+
restrictions on the recipients' exercise of the rights granted herein.
|
| 194 |
+
You are not responsible for enforcing compliance by third parties to
|
| 195 |
+
this License.
|
| 196 |
+
|
| 197 |
+
7. If, as a consequence of a court judgment or allegation of patent
|
| 198 |
+
infringement or for any other reason (not limited to patent issues),
|
| 199 |
+
conditions are imposed on you (whether by court order, agreement or
|
| 200 |
+
otherwise) that contradict the conditions of this License, they do not
|
| 201 |
+
excuse you from the conditions of this License. If you cannot
|
| 202 |
+
distribute so as to satisfy simultaneously your obligations under this
|
| 203 |
+
License and any other pertinent obligations, then as a consequence you
|
| 204 |
+
may not distribute the Program at all. For example, if a patent
|
| 205 |
+
license would not permit royalty-free redistribution of the Program by
|
| 206 |
+
all those who receive copies directly or indirectly through you, then
|
| 207 |
+
the only way you could satisfy both it and this License would be to
|
| 208 |
+
refrain entirely from distribution of the Program.
|
| 209 |
+
|
| 210 |
+
If any portion of this section is held invalid or unenforceable under
|
| 211 |
+
any particular circumstance, the balance of the section is intended to
|
| 212 |
+
apply and the section as a whole is intended to apply in other
|
| 213 |
+
circumstances.
|
| 214 |
+
|
| 215 |
+
It is not the purpose of this section to induce you to infringe any
|
| 216 |
+
patents or other property right claims or to contest validity of any
|
| 217 |
+
such claims; this section has the sole purpose of protecting the
|
| 218 |
+
integrity of the free software distribution system, which is
|
| 219 |
+
implemented by public license practices. Many people have made
|
| 220 |
+
generous contributions to the wide range of software distributed
|
| 221 |
+
through that system in reliance on consistent application of that
|
| 222 |
+
system; it is up to the author/donor to decide if he or she is willing
|
| 223 |
+
to distribute software through any other system and a licensee cannot
|
| 224 |
+
impose that choice.
|
| 225 |
+
|
| 226 |
+
This section is intended to make thoroughly clear what is believed to
|
| 227 |
+
be a consequence of the rest of this License.
|
| 228 |
+
|
| 229 |
+
8. If the distribution and/or use of the Program is restricted in
|
| 230 |
+
certain countries either by patents or by copyrighted interfaces, the
|
| 231 |
+
original copyright holder who places the Program under this License
|
| 232 |
+
may add an explicit geographical distribution limitation excluding
|
| 233 |
+
those countries, so that distribution is permitted only in or among
|
| 234 |
+
countries not thus excluded. In such case, this License incorporates
|
| 235 |
+
the limitation as if written in the body of this License.
|
| 236 |
+
|
| 237 |
+
9. The Free Software Foundation may publish revised and/or new versions
|
| 238 |
+
of the General Public License from time to time. Such new versions will
|
| 239 |
+
be similar in spirit to the present version, but may differ in detail to
|
| 240 |
+
address new problems or concerns.
|
| 241 |
+
|
| 242 |
+
Each version is given a distinguishing version number. If the Program
|
| 243 |
+
specifies a version number of this License which applies to it and "any
|
| 244 |
+
later version", you have the option of following the terms and conditions
|
| 245 |
+
either of that version or of any later version published by the Free
|
| 246 |
+
Software Foundation. If the Program does not specify a version number of
|
| 247 |
+
this License, you may choose any version ever published by the Free Software
|
| 248 |
+
Foundation.
|
| 249 |
+
|
| 250 |
+
10. If you wish to incorporate parts of the Program into other free
|
| 251 |
+
programs whose distribution conditions are different, write to the author
|
| 252 |
+
to ask for permission. For software which is copyrighted by the Free
|
| 253 |
+
Software Foundation, write to the Free Software Foundation; we sometimes
|
| 254 |
+
make exceptions for this. Our decision will be guided by the two goals
|
| 255 |
+
of preserving the free status of all derivatives of our free software and
|
| 256 |
+
of promoting the sharing and reuse of software generally.
|
| 257 |
+
|
| 258 |
+
NO WARRANTY
|
| 259 |
+
|
| 260 |
+
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
| 261 |
+
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
| 262 |
+
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
| 263 |
+
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
| 264 |
+
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
| 265 |
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
| 266 |
+
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
| 267 |
+
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
| 268 |
+
REPAIR OR CORRECTION.
|
| 269 |
+
|
| 270 |
+
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
| 271 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
| 272 |
+
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
| 273 |
+
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
| 274 |
+
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
| 275 |
+
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
| 276 |
+
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
| 277 |
+
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
| 278 |
+
POSSIBILITY OF SUCH DAMAGES.
|
| 279 |
+
|
| 280 |
+
END OF TERMS AND CONDITIONS
|
| 281 |
+
|
| 282 |
+
How to Apply These Terms to Your New Programs
|
| 283 |
+
|
| 284 |
+
If you develop a new program, and you want it to be of the greatest
|
| 285 |
+
possible use to the public, the best way to achieve this is to make it
|
| 286 |
+
free software which everyone can redistribute and change under these terms.
|
| 287 |
+
|
| 288 |
+
To do so, attach the following notices to the program. It is safest
|
| 289 |
+
to attach them to the start of each source file to most effectively
|
| 290 |
+
convey the exclusion of warranty; and each file should have at least
|
| 291 |
+
the "copyright" line and a pointer to where the full notice is found.
|
| 292 |
+
|
| 293 |
+
<one line to give the program's name and a brief idea of what it does.>
|
| 294 |
+
Copyright (C) <year> <name of author>
|
| 295 |
+
|
| 296 |
+
This program is free software; you can redistribute it and/or modify
|
| 297 |
+
it under the terms of the GNU General Public License as published by
|
| 298 |
+
the Free Software Foundation; either version 2 of the License, or
|
| 299 |
+
(at your option) any later version.
|
| 300 |
+
|
| 301 |
+
This program is distributed in the hope that it will be useful,
|
| 302 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 303 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 304 |
+
GNU General Public License for more details.
|
| 305 |
+
|
| 306 |
+
You should have received a copy of the GNU General Public License along
|
| 307 |
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
| 308 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
| 309 |
+
|
| 310 |
+
Also add information on how to contact you by electronic and paper mail.
|
| 311 |
+
|
| 312 |
+
If the program is interactive, make it output a short notice like this
|
| 313 |
+
when it starts in an interactive mode:
|
| 314 |
+
|
| 315 |
+
Gnomovision version 69, Copyright (C) year name of author
|
| 316 |
+
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
| 317 |
+
This is free software, and you are welcome to redistribute it
|
| 318 |
+
under certain conditions; type `show c' for details.
|
| 319 |
+
|
| 320 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
| 321 |
+
parts of the General Public License. Of course, the commands you use may
|
| 322 |
+
be called something other than `show w' and `show c'; they could even be
|
| 323 |
+
mouse-clicks or menu items--whatever suits your program.
|
| 324 |
+
|
| 325 |
+
You should also get your employer (if you work as a programmer) or your
|
| 326 |
+
school, if any, to sign a "copyright disclaimer" for the program, if
|
| 327 |
+
necessary. Here is a sample; alter the names:
|
| 328 |
+
|
| 329 |
+
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
| 330 |
+
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
| 331 |
+
|
| 332 |
+
<signature of Ty Coon>, 1 April 1989
|
| 333 |
+
Ty Coon, President of Vice
|
| 334 |
+
|
| 335 |
+
This General Public License does not permit incorporating your program into
|
| 336 |
+
proprietary programs. If your program is a subroutine library, you may
|
| 337 |
+
consider it more useful to permit linking proprietary applications with the
|
| 338 |
+
library. If this is what you want to do, use the GNU Lesser General
|
| 339 |
+
Public License instead of this License.
|
| 340 |
+
|
COPYING.LESSER
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
GNU LESSER GENERAL PUBLIC LICENSE
|
| 2 |
+
Version 2.1, February 1999
|
| 3 |
+
|
| 4 |
+
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
| 5 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 6 |
+
Everyone is permitted to copy and distribute verbatim copies
|
| 7 |
+
of this license document, but changing it is not allowed.
|
| 8 |
+
|
| 9 |
+
[This is the first released version of the Lesser GPL. It also counts
|
| 10 |
+
as the successor of the GNU Library Public License, version 2, hence
|
| 11 |
+
the version number 2.1.]
|
| 12 |
+
|
| 13 |
+
Preamble
|
| 14 |
+
|
| 15 |
+
The licenses for most software are designed to take away your
|
| 16 |
+
freedom to share and change it. By contrast, the GNU General Public
|
| 17 |
+
Licenses are intended to guarantee your freedom to share and change
|
| 18 |
+
free software--to make sure the software is free for all its users.
|
| 19 |
+
|
| 20 |
+
This license, the Lesser General Public License, applies to some
|
| 21 |
+
specially designated software packages--typically libraries--of the
|
| 22 |
+
Free Software Foundation and other authors who decide to use it. You
|
| 23 |
+
can use it too, but we suggest you first think carefully about whether
|
| 24 |
+
this license or the ordinary General Public License is the better
|
| 25 |
+
strategy to use in any particular case, based on the explanations below.
|
| 26 |
+
|
| 27 |
+
When we speak of free software, we are referring to freedom of use,
|
| 28 |
+
not price. Our General Public Licenses are designed to make sure that
|
| 29 |
+
you have the freedom to distribute copies of free software (and charge
|
| 30 |
+
for this service if you wish); that you receive source code or can get
|
| 31 |
+
it if you want it; that you can change the software and use pieces of
|
| 32 |
+
it in new free programs; and that you are informed that you can do
|
| 33 |
+
these things.
|
| 34 |
+
|
| 35 |
+
To protect your rights, we need to make restrictions that forbid
|
| 36 |
+
distributors to deny you these rights or to ask you to surrender these
|
| 37 |
+
rights. These restrictions translate to certain responsibilities for
|
| 38 |
+
you if you distribute copies of the library or if you modify it.
|
| 39 |
+
|
| 40 |
+
For example, if you distribute copies of the library, whether gratis
|
| 41 |
+
or for a fee, you must give the recipients all the rights that we gave
|
| 42 |
+
you. You must make sure that they, too, receive or can get the source
|
| 43 |
+
code. If you link other code with the library, you must provide
|
| 44 |
+
complete object files to the recipients, so that they can relink them
|
| 45 |
+
with the library after making changes to the library and recompiling
|
| 46 |
+
it. And you must show them these terms so they know their rights.
|
| 47 |
+
|
| 48 |
+
We protect your rights with a two-step method: (1) we copyright the
|
| 49 |
+
library, and (2) we offer you this license, which gives you legal
|
| 50 |
+
permission to copy, distribute and/or modify the library.
|
| 51 |
+
|
| 52 |
+
To protect each distributor, we want to make it very clear that
|
| 53 |
+
there is no warranty for the free library. Also, if the library is
|
| 54 |
+
modified by someone else and passed on, the recipients should know
|
| 55 |
+
that what they have is not the original version, so that the original
|
| 56 |
+
author's reputation will not be affected by problems that might be
|
| 57 |
+
introduced by others.
|
| 58 |
+
|
| 59 |
+
Finally, software patents pose a constant threat to the existence of
|
| 60 |
+
any free program. We wish to make sure that a company cannot
|
| 61 |
+
effectively restrict the users of a free program by obtaining a
|
| 62 |
+
restrictive license from a patent holder. Therefore, we insist that
|
| 63 |
+
any patent license obtained for a version of the library must be
|
| 64 |
+
consistent with the full freedom of use specified in this license.
|
| 65 |
+
|
| 66 |
+
Most GNU software, including some libraries, is covered by the
|
| 67 |
+
ordinary GNU General Public License. This license, the GNU Lesser
|
| 68 |
+
General Public License, applies to certain designated libraries, and
|
| 69 |
+
is quite different from the ordinary General Public License. We use
|
| 70 |
+
this license for certain libraries in order to permit linking those
|
| 71 |
+
libraries into non-free programs.
|
| 72 |
+
|
| 73 |
+
When a program is linked with a library, whether statically or using
|
| 74 |
+
a shared library, the combination of the two is legally speaking a
|
| 75 |
+
combined work, a derivative of the original library. The ordinary
|
| 76 |
+
General Public License therefore permits such linking only if the
|
| 77 |
+
entire combination fits its criteria of freedom. The Lesser General
|
| 78 |
+
Public License permits more lax criteria for linking other code with
|
| 79 |
+
the library.
|
| 80 |
+
|
| 81 |
+
We call this license the "Lesser" General Public License because it
|
| 82 |
+
does Less to protect the user's freedom than the ordinary General
|
| 83 |
+
Public License. It also provides other free software developers Less
|
| 84 |
+
of an advantage over competing non-free programs. These disadvantages
|
| 85 |
+
are the reason we use the ordinary General Public License for many
|
| 86 |
+
libraries. However, the Lesser license provides advantages in certain
|
| 87 |
+
special circumstances.
|
| 88 |
+
|
| 89 |
+
For example, on rare occasions, there may be a special need to
|
| 90 |
+
encourage the widest possible use of a certain library, so that it becomes
|
| 91 |
+
a de-facto standard. To achieve this, non-free programs must be
|
| 92 |
+
allowed to use the library. A more frequent case is that a free
|
| 93 |
+
library does the same job as widely used non-free libraries. In this
|
| 94 |
+
case, there is little to gain by limiting the free library to free
|
| 95 |
+
software only, so we use the Lesser General Public License.
|
| 96 |
+
|
| 97 |
+
In other cases, permission to use a particular library in non-free
|
| 98 |
+
programs enables a greater number of people to use a large body of
|
| 99 |
+
free software. For example, permission to use the GNU C Library in
|
| 100 |
+
non-free programs enables many more people to use the whole GNU
|
| 101 |
+
operating system, as well as its variant, the GNU/Linux operating
|
| 102 |
+
system.
|
| 103 |
+
|
| 104 |
+
Although the Lesser General Public License is Less protective of the
|
| 105 |
+
users' freedom, it does ensure that the user of a program that is
|
| 106 |
+
linked with the Library has the freedom and the wherewithal to run
|
| 107 |
+
that program using a modified version of the Library.
|
| 108 |
+
|
| 109 |
+
The precise terms and conditions for copying, distribution and
|
| 110 |
+
modification follow. Pay close attention to the difference between a
|
| 111 |
+
"work based on the library" and a "work that uses the library". The
|
| 112 |
+
former contains code derived from the library, whereas the latter must
|
| 113 |
+
be combined with the library in order to run.
|
| 114 |
+
|
| 115 |
+
GNU LESSER GENERAL PUBLIC LICENSE
|
| 116 |
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
| 117 |
+
|
| 118 |
+
0. This License Agreement applies to any software library or other
|
| 119 |
+
program which contains a notice placed by the copyright holder or
|
| 120 |
+
other authorized party saying it may be distributed under the terms of
|
| 121 |
+
this Lesser General Public License (also called "this License").
|
| 122 |
+
Each licensee is addressed as "you".
|
| 123 |
+
|
| 124 |
+
A "library" means a collection of software functions and/or data
|
| 125 |
+
prepared so as to be conveniently linked with application programs
|
| 126 |
+
(which use some of those functions and data) to form executables.
|
| 127 |
+
|
| 128 |
+
The "Library", below, refers to any such software library or work
|
| 129 |
+
which has been distributed under these terms. A "work based on the
|
| 130 |
+
Library" means either the Library or any derivative work under
|
| 131 |
+
copyright law: that is to say, a work containing the Library or a
|
| 132 |
+
portion of it, either verbatim or with modifications and/or translated
|
| 133 |
+
straightforwardly into another language. (Hereinafter, translation is
|
| 134 |
+
included without limitation in the term "modification".)
|
| 135 |
+
|
| 136 |
+
"Source code" for a work means the preferred form of the work for
|
| 137 |
+
making modifications to it. For a library, complete source code means
|
| 138 |
+
all the source code for all modules it contains, plus any associated
|
| 139 |
+
interface definition files, plus the scripts used to control compilation
|
| 140 |
+
and installation of the library.
|
| 141 |
+
|
| 142 |
+
Activities other than copying, distribution and modification are not
|
| 143 |
+
covered by this License; they are outside its scope. The act of
|
| 144 |
+
running a program using the Library is not restricted, and output from
|
| 145 |
+
such a program is covered only if its contents constitute a work based
|
| 146 |
+
on the Library (independent of the use of the Library in a tool for
|
| 147 |
+
writing it). Whether that is true depends on what the Library does
|
| 148 |
+
and what the program that uses the Library does.
|
| 149 |
+
|
| 150 |
+
1. You may copy and distribute verbatim copies of the Library's
|
| 151 |
+
complete source code as you receive it, in any medium, provided that
|
| 152 |
+
you conspicuously and appropriately publish on each copy an
|
| 153 |
+
appropriate copyright notice and disclaimer of warranty; keep intact
|
| 154 |
+
all the notices that refer to this License and to the absence of any
|
| 155 |
+
warranty; and distribute a copy of this License along with the
|
| 156 |
+
Library.
|
| 157 |
+
|
| 158 |
+
You may charge a fee for the physical act of transferring a copy,
|
| 159 |
+
and you may at your option offer warranty protection in exchange for a
|
| 160 |
+
fee.
|
| 161 |
+
|
| 162 |
+
2. You may modify your copy or copies of the Library or any portion
|
| 163 |
+
of it, thus forming a work based on the Library, and copy and
|
| 164 |
+
distribute such modifications or work under the terms of Section 1
|
| 165 |
+
above, provided that you also meet all of these conditions:
|
| 166 |
+
|
| 167 |
+
a) The modified work must itself be a software library.
|
| 168 |
+
|
| 169 |
+
b) You must cause the files modified to carry prominent notices
|
| 170 |
+
stating that you changed the files and the date of any change.
|
| 171 |
+
|
| 172 |
+
c) You must cause the whole of the work to be licensed at no
|
| 173 |
+
charge to all third parties under the terms of this License.
|
| 174 |
+
|
| 175 |
+
d) If a facility in the modified Library refers to a function or a
|
| 176 |
+
table of data to be supplied by an application program that uses
|
| 177 |
+
the facility, other than as an argument passed when the facility
|
| 178 |
+
is invoked, then you must make a good faith effort to ensure that,
|
| 179 |
+
in the event an application does not supply such function or
|
| 180 |
+
table, the facility still operates, and performs whatever part of
|
| 181 |
+
its purpose remains meaningful.
|
| 182 |
+
|
| 183 |
+
(For example, a function in a library to compute square roots has
|
| 184 |
+
a purpose that is entirely well-defined independent of the
|
| 185 |
+
application. Therefore, Subsection 2d requires that any
|
| 186 |
+
application-supplied function or table used by this function must
|
| 187 |
+
be optional: if the application does not supply it, the square
|
| 188 |
+
root function must still compute square roots.)
|
| 189 |
+
|
| 190 |
+
These requirements apply to the modified work as a whole. If
|
| 191 |
+
identifiable sections of that work are not derived from the Library,
|
| 192 |
+
and can be reasonably considered independent and separate works in
|
| 193 |
+
themselves, then this License, and its terms, do not apply to those
|
| 194 |
+
sections when you distribute them as separate works. But when you
|
| 195 |
+
distribute the same sections as part of a whole which is a work based
|
| 196 |
+
on the Library, the distribution of the whole must be on the terms of
|
| 197 |
+
this License, whose permissions for other licensees extend to the
|
| 198 |
+
entire whole, and thus to each and every part regardless of who wrote
|
| 199 |
+
it.
|
| 200 |
+
|
| 201 |
+
Thus, it is not the intent of this section to claim rights or contest
|
| 202 |
+
your rights to work written entirely by you; rather, the intent is to
|
| 203 |
+
exercise the right to control the distribution of derivative or
|
| 204 |
+
collective works based on the Library.
|
| 205 |
+
|
| 206 |
+
In addition, mere aggregation of another work not based on the Library
|
| 207 |
+
with the Library (or with a work based on the Library) on a volume of
|
| 208 |
+
a storage or distribution medium does not bring the other work under
|
| 209 |
+
the scope of this License.
|
| 210 |
+
|
| 211 |
+
3. You may opt to apply the terms of the ordinary GNU General Public
|
| 212 |
+
License instead of this License to a given copy of the Library. To do
|
| 213 |
+
this, you must alter all the notices that refer to this License, so
|
| 214 |
+
that they refer to the ordinary GNU General Public License, version 2,
|
| 215 |
+
instead of to this License. (If a newer version than version 2 of the
|
| 216 |
+
ordinary GNU General Public License has appeared, then you can specify
|
| 217 |
+
that version instead if you wish.) Do not make any other change in
|
| 218 |
+
these notices.
|
| 219 |
+
|
| 220 |
+
Once this change is made in a given copy, it is irreversible for
|
| 221 |
+
that copy, so the ordinary GNU General Public License applies to all
|
| 222 |
+
subsequent copies and derivative works made from that copy.
|
| 223 |
+
|
| 224 |
+
This option is useful when you wish to copy part of the code of
|
| 225 |
+
the Library into a program that is not a library.
|
| 226 |
+
|
| 227 |
+
4. You may copy and distribute the Library (or a portion or
|
| 228 |
+
derivative of it, under Section 2) in object code or executable form
|
| 229 |
+
under the terms of Sections 1 and 2 above provided that you accompany
|
| 230 |
+
it with the complete corresponding machine-readable source code, which
|
| 231 |
+
must be distributed under the terms of Sections 1 and 2 above on a
|
| 232 |
+
medium customarily used for software interchange.
|
| 233 |
+
|
| 234 |
+
If distribution of object code is made by offering access to copy
|
| 235 |
+
from a designated place, then offering equivalent access to copy the
|
| 236 |
+
source code from the same place satisfies the requirement to
|
| 237 |
+
distribute the source code, even though third parties are not
|
| 238 |
+
compelled to copy the source along with the object code.
|
| 239 |
+
|
| 240 |
+
5. A program that contains no derivative of any portion of the
|
| 241 |
+
Library, but is designed to work with the Library by being compiled or
|
| 242 |
+
linked with it, is called a "work that uses the Library". Such a
|
| 243 |
+
work, in isolation, is not a derivative work of the Library, and
|
| 244 |
+
therefore falls outside the scope of this License.
|
| 245 |
+
|
| 246 |
+
However, linking a "work that uses the Library" with the Library
|
| 247 |
+
creates an executable that is a derivative of the Library (because it
|
| 248 |
+
contains portions of the Library), rather than a "work that uses the
|
| 249 |
+
library". The executable is therefore covered by this License.
|
| 250 |
+
Section 6 states terms for distribution of such executables.
|
| 251 |
+
|
| 252 |
+
When a "work that uses the Library" uses material from a header file
|
| 253 |
+
that is part of the Library, the object code for the work may be a
|
| 254 |
+
derivative work of the Library even though the source code is not.
|
| 255 |
+
Whether this is true is especially significant if the work can be
|
| 256 |
+
linked without the Library, or if the work is itself a library. The
|
| 257 |
+
threshold for this to be true is not precisely defined by law.
|
| 258 |
+
|
| 259 |
+
If such an object file uses only numerical parameters, data
|
| 260 |
+
structure layouts and accessors, and small macros and small inline
|
| 261 |
+
functions (ten lines or less in length), then the use of the object
|
| 262 |
+
file is unrestricted, regardless of whether it is legally a derivative
|
| 263 |
+
work. (Executables containing this object code plus portions of the
|
| 264 |
+
Library will still fall under Section 6.)
|
| 265 |
+
|
| 266 |
+
Otherwise, if the work is a derivative of the Library, you may
|
| 267 |
+
distribute the object code for the work under the terms of Section 6.
|
| 268 |
+
Any executables containing that work also fall under Section 6,
|
| 269 |
+
whether or not they are linked directly with the Library itself.
|
| 270 |
+
|
| 271 |
+
6. As an exception to the Sections above, you may also combine or
|
| 272 |
+
link a "work that uses the Library" with the Library to produce a
|
| 273 |
+
work containing portions of the Library, and distribute that work
|
| 274 |
+
under terms of your choice, provided that the terms permit
|
| 275 |
+
modification of the work for the customer's own use and reverse
|
| 276 |
+
engineering for debugging such modifications.
|
| 277 |
+
|
| 278 |
+
You must give prominent notice with each copy of the work that the
|
| 279 |
+
Library is used in it and that the Library and its use are covered by
|
| 280 |
+
this License. You must supply a copy of this License. If the work
|
| 281 |
+
during execution displays copyright notices, you must include the
|
| 282 |
+
copyright notice for the Library among them, as well as a reference
|
| 283 |
+
directing the user to the copy of this License. Also, you must do one
|
| 284 |
+
of these things:
|
| 285 |
+
|
| 286 |
+
a) Accompany the work with the complete corresponding
|
| 287 |
+
machine-readable source code for the Library including whatever
|
| 288 |
+
changes were used in the work (which must be distributed under
|
| 289 |
+
Sections 1 and 2 above); and, if the work is an executable linked
|
| 290 |
+
with the Library, with the complete machine-readable "work that
|
| 291 |
+
uses the Library", as object code and/or source code, so that the
|
| 292 |
+
user can modify the Library and then relink to produce a modified
|
| 293 |
+
executable containing the modified Library. (It is understood
|
| 294 |
+
that the user who changes the contents of definitions files in the
|
| 295 |
+
Library will not necessarily be able to recompile the application
|
| 296 |
+
to use the modified definitions.)
|
| 297 |
+
|
| 298 |
+
b) Use a suitable shared library mechanism for linking with the
|
| 299 |
+
Library. A suitable mechanism is one that (1) uses at run time a
|
| 300 |
+
copy of the library already present on the user's computer system,
|
| 301 |
+
rather than copying library functions into the executable, and (2)
|
| 302 |
+
will operate properly with a modified version of the library, if
|
| 303 |
+
the user installs one, as long as the modified version is
|
| 304 |
+
interface-compatible with the version that the work was made with.
|
| 305 |
+
|
| 306 |
+
c) Accompany the work with a written offer, valid for at
|
| 307 |
+
least three years, to give the same user the materials
|
| 308 |
+
specified in Subsection 6a, above, for a charge no more
|
| 309 |
+
than the cost of performing this distribution.
|
| 310 |
+
|
| 311 |
+
d) If distribution of the work is made by offering access to copy
|
| 312 |
+
from a designated place, offer equivalent access to copy the above
|
| 313 |
+
specified materials from the same place.
|
| 314 |
+
|
| 315 |
+
e) Verify that the user has already received a copy of these
|
| 316 |
+
materials or that you have already sent this user a copy.
|
| 317 |
+
|
| 318 |
+
For an executable, the required form of the "work that uses the
|
| 319 |
+
Library" must include any data and utility programs needed for
|
| 320 |
+
reproducing the executable from it. However, as a special exception,
|
| 321 |
+
the materials to be distributed need not include anything that is
|
| 322 |
+
normally distributed (in either source or binary form) with the major
|
| 323 |
+
components (compiler, kernel, and so on) of the operating system on
|
| 324 |
+
which the executable runs, unless that component itself accompanies
|
| 325 |
+
the executable.
|
| 326 |
+
|
| 327 |
+
It may happen that this requirement contradicts the license
|
| 328 |
+
restrictions of other proprietary libraries that do not normally
|
| 329 |
+
accompany the operating system. Such a contradiction means you cannot
|
| 330 |
+
use both them and the Library together in an executable that you
|
| 331 |
+
distribute.
|
| 332 |
+
|
| 333 |
+
7. You may place library facilities that are a work based on the
|
| 334 |
+
Library side-by-side in a single library together with other library
|
| 335 |
+
facilities not covered by this License, and distribute such a combined
|
| 336 |
+
library, provided that the separate distribution of the work based on
|
| 337 |
+
the Library and of the other library facilities is otherwise
|
| 338 |
+
permitted, and provided that you do these two things:
|
| 339 |
+
|
| 340 |
+
a) Accompany the combined library with a copy of the same work
|
| 341 |
+
based on the Library, uncombined with any other library
|
| 342 |
+
facilities. This must be distributed under the terms of the
|
| 343 |
+
Sections above.
|
| 344 |
+
|
| 345 |
+
b) Give prominent notice with the combined library of the fact
|
| 346 |
+
that part of it is a work based on the Library, and explaining
|
| 347 |
+
where to find the accompanying uncombined form of the same work.
|
| 348 |
+
|
| 349 |
+
8. You may not copy, modify, sublicense, link with, or distribute
|
| 350 |
+
the Library except as expressly provided under this License. Any
|
| 351 |
+
attempt otherwise to copy, modify, sublicense, link with, or
|
| 352 |
+
distribute the Library is void, and will automatically terminate your
|
| 353 |
+
rights under this License. However, parties who have received copies,
|
| 354 |
+
or rights, from you under this License will not have their licenses
|
| 355 |
+
terminated so long as such parties remain in full compliance.
|
| 356 |
+
|
| 357 |
+
9. You are not required to accept this License, since you have not
|
| 358 |
+
signed it. However, nothing else grants you permission to modify or
|
| 359 |
+
distribute the Library or its derivative works. These actions are
|
| 360 |
+
prohibited by law if you do not accept this License. Therefore, by
|
| 361 |
+
modifying or distributing the Library (or any work based on the
|
| 362 |
+
Library), you indicate your acceptance of this License to do so, and
|
| 363 |
+
all its terms and conditions for copying, distributing or modifying
|
| 364 |
+
the Library or works based on it.
|
| 365 |
+
|
| 366 |
+
10. Each time you redistribute the Library (or any work based on the
|
| 367 |
+
Library), the recipient automatically receives a license from the
|
| 368 |
+
original licensor to copy, distribute, link with or modify the Library
|
| 369 |
+
subject to these terms and conditions. You may not impose any further
|
| 370 |
+
restrictions on the recipients' exercise of the rights granted herein.
|
| 371 |
+
You are not responsible for enforcing compliance by third parties with
|
| 372 |
+
this License.
|
| 373 |
+
|
| 374 |
+
11. If, as a consequence of a court judgment or allegation of patent
|
| 375 |
+
infringement or for any other reason (not limited to patent issues),
|
| 376 |
+
conditions are imposed on you (whether by court order, agreement or
|
| 377 |
+
otherwise) that contradict the conditions of this License, they do not
|
| 378 |
+
excuse you from the conditions of this License. If you cannot
|
| 379 |
+
distribute so as to satisfy simultaneously your obligations under this
|
| 380 |
+
License and any other pertinent obligations, then as a consequence you
|
| 381 |
+
may not distribute the Library at all. For example, if a patent
|
| 382 |
+
license would not permit royalty-free redistribution of the Library by
|
| 383 |
+
all those who receive copies directly or indirectly through you, then
|
| 384 |
+
the only way you could satisfy both it and this License would be to
|
| 385 |
+
refrain entirely from distribution of the Library.
|
| 386 |
+
|
| 387 |
+
If any portion of this section is held invalid or unenforceable under any
|
| 388 |
+
particular circumstance, the balance of the section is intended to apply,
|
| 389 |
+
and the section as a whole is intended to apply in other circumstances.
|
| 390 |
+
|
| 391 |
+
It is not the purpose of this section to induce you to infringe any
|
| 392 |
+
patents or other property right claims or to contest validity of any
|
| 393 |
+
such claims; this section has the sole purpose of protecting the
|
| 394 |
+
integrity of the free software distribution system which is
|
| 395 |
+
implemented by public license practices. Many people have made
|
| 396 |
+
generous contributions to the wide range of software distributed
|
| 397 |
+
through that system in reliance on consistent application of that
|
| 398 |
+
system; it is up to the author/donor to decide if he or she is willing
|
| 399 |
+
to distribute software through any other system and a licensee cannot
|
| 400 |
+
impose that choice.
|
| 401 |
+
|
| 402 |
+
This section is intended to make thoroughly clear what is believed to
|
| 403 |
+
be a consequence of the rest of this License.
|
| 404 |
+
|
| 405 |
+
12. If the distribution and/or use of the Library is restricted in
|
| 406 |
+
certain countries either by patents or by copyrighted interfaces, the
|
| 407 |
+
original copyright holder who places the Library under this License may add
|
| 408 |
+
an explicit geographical distribution limitation excluding those countries,
|
| 409 |
+
so that distribution is permitted only in or among countries not thus
|
| 410 |
+
excluded. In such case, this License incorporates the limitation as if
|
| 411 |
+
written in the body of this License.
|
| 412 |
+
|
| 413 |
+
13. The Free Software Foundation may publish revised and/or new
|
| 414 |
+
versions of the Lesser General Public License from time to time.
|
| 415 |
+
Such new versions will be similar in spirit to the present version,
|
| 416 |
+
but may differ in detail to address new problems or concerns.
|
| 417 |
+
|
| 418 |
+
Each version is given a distinguishing version number. If the Library
|
| 419 |
+
specifies a version number of this License which applies to it and
|
| 420 |
+
"any later version", you have the option of following the terms and
|
| 421 |
+
conditions either of that version or of any later version published by
|
| 422 |
+
the Free Software Foundation. If the Library does not specify a
|
| 423 |
+
license version number, you may choose any version ever published by
|
| 424 |
+
the Free Software Foundation.
|
| 425 |
+
|
| 426 |
+
14. If you wish to incorporate parts of the Library into other free
|
| 427 |
+
programs whose distribution conditions are incompatible with these,
|
| 428 |
+
write to the author to ask for permission. For software which is
|
| 429 |
+
copyrighted by the Free Software Foundation, write to the Free
|
| 430 |
+
Software Foundation; we sometimes make exceptions for this. Our
|
| 431 |
+
decision will be guided by the two goals of preserving the free status
|
| 432 |
+
of all derivatives of our free software and of promoting the sharing
|
| 433 |
+
and reuse of software generally.
|
| 434 |
+
|
| 435 |
+
NO WARRANTY
|
| 436 |
+
|
| 437 |
+
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
| 438 |
+
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
| 439 |
+
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
| 440 |
+
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
| 441 |
+
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
| 442 |
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| 443 |
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
| 444 |
+
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
| 445 |
+
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
| 446 |
+
|
| 447 |
+
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
| 448 |
+
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
| 449 |
+
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
| 450 |
+
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
| 451 |
+
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
| 452 |
+
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
| 453 |
+
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
| 454 |
+
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
| 455 |
+
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
| 456 |
+
DAMAGES.
|
| 457 |
+
|
| 458 |
+
END OF TERMS AND CONDITIONS
|
| 459 |
+
|
| 460 |
+
How to Apply These Terms to Your New Libraries
|
| 461 |
+
|
| 462 |
+
If you develop a new library, and you want it to be of the greatest
|
| 463 |
+
possible use to the public, we recommend making it free software that
|
| 464 |
+
everyone can redistribute and change. You can do so by permitting
|
| 465 |
+
redistribution under these terms (or, alternatively, under the terms of the
|
| 466 |
+
ordinary General Public License).
|
| 467 |
+
|
| 468 |
+
To apply these terms, attach the following notices to the library. It is
|
| 469 |
+
safest to attach them to the start of each source file to most effectively
|
| 470 |
+
convey the exclusion of warranty; and each file should have at least the
|
| 471 |
+
"copyright" line and a pointer to where the full notice is found.
|
| 472 |
+
|
| 473 |
+
<one line to give the library's name and a brief idea of what it does.>
|
| 474 |
+
Copyright (C) <year> <name of author>
|
| 475 |
+
|
| 476 |
+
This library is free software; you can redistribute it and/or
|
| 477 |
+
modify it under the terms of the GNU Lesser General Public
|
| 478 |
+
License as published by the Free Software Foundation; either
|
| 479 |
+
version 2.1 of the License, or (at your option) any later version.
|
| 480 |
+
|
| 481 |
+
This library is distributed in the hope that it will be useful,
|
| 482 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 483 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 484 |
+
Lesser General Public License for more details.
|
| 485 |
+
|
| 486 |
+
You should have received a copy of the GNU Lesser General Public
|
| 487 |
+
License along with this library; if not, write to the Free Software
|
| 488 |
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 489 |
+
|
| 490 |
+
Also add information on how to contact you by electronic and paper mail.
|
| 491 |
+
|
| 492 |
+
You should also get your employer (if you work as a programmer) or your
|
| 493 |
+
school, if any, to sign a "copyright disclaimer" for the library, if
|
| 494 |
+
necessary. Here is a sample; alter the names:
|
| 495 |
+
|
| 496 |
+
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
| 497 |
+
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
| 498 |
+
|
| 499 |
+
<signature of Ty Coon>, 1 April 1990
|
| 500 |
+
Ty Coon, President of Vice
|
| 501 |
+
|
| 502 |
+
That's all there is to it!
|
Makefile.am
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
AUTOMAKE_OPTIONS = foreign
|
| 2 |
+
ACLOCAL_AMFLAGS = -I m4
|
| 3 |
+
SUBDIRS = 3rd_party common src include $(CYTHON_SUB) tools docs
|
| 4 |
+
|
| 5 |
+
EXTRA_DIST = \
|
| 6 |
+
README.md \
|
| 7 |
+
git-version-gen
|
| 8 |
+
|
| 9 |
+
dist-hook:
|
| 10 |
+
@if ! git diff --quiet; then echo "Uncommitted changes present; not releasing"; exit 1; fi
|
| 11 |
+
echo $(VERSION) > $(distdir)/.tarball-version
|
| 12 |
+
|
| 13 |
+
docs/html: $(top_builddir)/doxygen.cfg $(top_srcdir)/src/*.c $(top_srcdir)/src/*.h $(top_srcdir)/include/libimobiledevice/*.h
|
| 14 |
+
rm -rf docs/html
|
| 15 |
+
doxygen doxygen.cfg
|
| 16 |
+
|
| 17 |
+
docs: doxygen.cfg docs/html
|
| 18 |
+
|
| 19 |
+
indent:
|
| 20 |
+
indent -kr -ut -ts4 -l120 src/*.c src/*.h
|
| 21 |
+
|
NEWS
ADDED
|
@@ -0,0 +1,602 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Version 1.4.0
|
| 2 |
+
~~~~~~~~~~~~~
|
| 3 |
+
|
| 4 |
+
* Development release
|
| 5 |
+
- From now on, releases will be made more frequently
|
| 6 |
+
* Changes:
|
| 7 |
+
- Add support for MbedTLS
|
| 8 |
+
- Add Reverse Proxy implementation
|
| 9 |
+
- Add support for wireless pairing (AppleTV)
|
| 10 |
+
- Embed 3rd party libraries for ed25519 and SRP6a
|
| 11 |
+
- Fixes in idevicedebug
|
| 12 |
+
- idevicecrashreport: Allow filtering crash reports by filename
|
| 13 |
+
- Add idevicedevmodectl tool
|
| 14 |
+
- Fixes for idevicebackup2
|
| 15 |
+
- Add property_list_client_get_service_client() and service_get_connection() functions
|
| 16 |
+
- Add idevicebtlogger
|
| 17 |
+
- Add new idevice_events_subscribe/unsubscribe API
|
| 18 |
+
- Move LIBIMOBILEDEVICE_API to public headers
|
| 19 |
+
- Add afc_strerror function
|
| 20 |
+
- Add libimobiledevice_version() function
|
| 21 |
+
- Use libimobiledevice-glue's SHA1 implementation
|
| 22 |
+
- Add support for iOS 17+ Personalized Developer Disk image mounting
|
| 23 |
+
- Fix compilation on MSVC
|
| 24 |
+
- Add idevice_strerror() to interface
|
| 25 |
+
- Add new idevice_get_device_version() to interface
|
| 26 |
+
- Add os_trace_relay service implementation
|
| 27 |
+
- Fixes for idevicesyslog
|
| 28 |
+
- afc: Add afc_get_file_info_plist and afc_get_device_info_plist functions
|
| 29 |
+
... and several other internal changes
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
Version 1.3.0
|
| 33 |
+
~~~~~~~~~~~~~
|
| 34 |
+
|
| 35 |
+
* Development release "Let's get the party started."
|
| 36 |
+
* Changes:
|
| 37 |
+
- Fix Python 3 support
|
| 38 |
+
- Add more lockdown error codes
|
| 39 |
+
- Add new lockdownd_pair_with_options() function
|
| 40 |
+
- Fix GnuTLS support with iOS 10
|
| 41 |
+
- Make sure sockets only listen locally due to security reasons
|
| 42 |
+
- Plug various memory leaks
|
| 43 |
+
- Fix SSL version negotiation for newer versions of OpenSSL
|
| 44 |
+
- Optimize lockdown pair record handling
|
| 45 |
+
- Return proper error code when a lockdown pair record is missing
|
| 46 |
+
- Fix building with MingGW
|
| 47 |
+
- Store application information in Info.plist using idevicebackup2
|
| 48 |
+
- Fix application backup handling to allow the device to restore applications
|
| 49 |
+
that were installed using idevicebackup2
|
| 50 |
+
- Make idevicebackup2 reboot after restore the default to allow the device to
|
| 51 |
+
migrate data correctly and thus improve the restored device data state
|
| 52 |
+
- Improve console frontend information output in idevicebackup2
|
| 53 |
+
- Extend ideviceprovision tool to allow retrieving and removing all
|
| 54 |
+
provisioning profiles
|
| 55 |
+
- Fix parsing large provisioning profile using ideviceprovision
|
| 56 |
+
- Fix receiving large property lists in property list service
|
| 57 |
+
- Propagate lower level errors to callers instead of returning
|
| 58 |
+
IDEVICE_E_UNKNOWN_ERROR
|
| 59 |
+
- API: Add IDEVICE_DEVICE_PAIRED event type
|
| 60 |
+
- Detect screenshot format to support png, tiff and dat formats using
|
| 61 |
+
idevicescreenshot tool
|
| 62 |
+
- API: Add mobileactivation service implementation
|
| 63 |
+
- Wait for passcode entry if required using idevicesyslog
|
| 64 |
+
- Add HDMI option to diagnostics command for idevicediagnostics
|
| 65 |
+
- Fix IORegistry command for iOS 11+ devices in idevicediagnostics
|
| 66 |
+
- Remove 40-digit character limit for UDID in tools to support newer devices
|
| 67 |
+
- Fix broken validate command in idevicepair with iOS 11+
|
| 68 |
+
- Fix OpenSSL version checks for configure target when using LibreSSL
|
| 69 |
+
- Migrate latest improved common code from libusbmuxd
|
| 70 |
+
- Convert README file to markdown format
|
| 71 |
+
- Fix idevicecrashreport tool to work with iOS 13+
|
| 72 |
+
- Fix various errors in SSL communication logic
|
| 73 |
+
- API: Add preboard service implementation
|
| 74 |
+
- Output hint to user to enter passcode when changing password using
|
| 75 |
+
idevicebackup2
|
| 76 |
+
- Cython: Fix and improve debugserver and diagnostics service bindings
|
| 77 |
+
- API: Add WiFi device support via new idevice_new_with_options() function
|
| 78 |
+
- API: Add idevice_get_device_list_extended() to also list network devices
|
| 79 |
+
- API: Add lockdown_strerror() helper to get error representation as string
|
| 80 |
+
- Add network device support to idevicesyslog and ideviceinfo tools
|
| 81 |
+
- Make debug output consistently output to stderr
|
| 82 |
+
- Add new idevicesetlocation tool (requires mounted developer image)
|
| 83 |
+
- Add option to exit if device disconnects in idevicesyslog
|
| 84 |
+
- API: Add syslog_relay_start_capture_raw() for raw syslog capture
|
| 85 |
+
- Add color output and process filter support to idevicesyslog
|
| 86 |
+
- API: Add companion_proxy service implementation
|
| 87 |
+
- Bump dependency to libusbmuxd 2.0.2
|
| 88 |
+
- Bump dependency to libplist 2.2.0
|
| 89 |
+
- Improve error handling and reporting in library and tools
|
| 90 |
+
- Fix various memory leaks in library and tools
|
| 91 |
+
- Add "--network" and "--version" options to all tools
|
| 92 |
+
- Fix socket_connect_addr() not connecting to network devices using IPv6
|
| 93 |
+
in some cases.
|
| 94 |
+
- Improve IPv6 "scope id" detection to fix connecting to network devices with
|
| 95 |
+
link-local adresses.
|
| 96 |
+
- Update man pages
|
| 97 |
+
- Fix various inconsistent declarations in public headers
|
| 98 |
+
- Allow OpenSSL >= 1.1.0 to use older/disallowed TLS versions fixing issues
|
| 99 |
+
where pairing records were getting removed repeatingly
|
| 100 |
+
- Fixed memory leaks
|
| 101 |
+
- Cython: Rewrite version detection logic in configure.ac
|
| 102 |
+
- Rename "--enable-debug-code" configure option to "--enable-debug"
|
| 103 |
+
- Improve README.md with project description, installation, contributing and
|
| 104 |
+
usage sections
|
| 105 |
+
- Rename library and all related files by adding an API version resulting
|
| 106 |
+
in "libimobiledevice-1.0"
|
| 107 |
+
- Bump soname version
|
| 108 |
+
* API is UNSTABLE
|
| 109 |
+
|
| 110 |
+
Version 1.2.0
|
| 111 |
+
~~~~~~~~~~~~~
|
| 112 |
+
|
| 113 |
+
* Stable release "It took you so long baby!"
|
| 114 |
+
* Changes:
|
| 115 |
+
- Require autoconf 2.64 or later
|
| 116 |
+
- Remove dev tools, will return either as proper tools or website examples
|
| 117 |
+
- Refactor installation proxy service implementation and normalize code
|
| 118 |
+
- API: Added instproxy_lookup() to efficiently lookup app information
|
| 119 |
+
- API: Added instproxy_check_capabilities_match() to check device capabilities
|
| 120 |
+
- API: Added various instproxy command and status plist getters
|
| 121 |
+
- API: Make debugserver_client_set_ack_mode() public
|
| 122 |
+
- Fix handling of clients reconnecting in idevicedebugserverproxy which
|
| 123 |
+
previously didn't work properly
|
| 124 |
+
- Flush stdout for every line in idevicesyslog
|
| 125 |
+
- Fix shutdown of idevicedebugserverproxy tool which could hang
|
| 126 |
+
- Notify user when erroneously using idevicebackup with iOS 4 or later
|
| 127 |
+
- Enable build of idevicecrashreport on WIN32
|
| 128 |
+
- Fix thread handle leaks on WIN32 adding thread_new and thread_free
|
| 129 |
+
- cython: Add receive/receive_timeout methods for iDeviceConnection to
|
| 130 |
+
receive raw data from a connection
|
| 131 |
+
- cython: Add new FILE_RELAY_E_PERMISSION_DENIED(-6) error
|
| 132 |
+
- API: Refactor lockdown service internal error checking and add a bunch of
|
| 133 |
+
new native errors
|
| 134 |
+
- Convert int16_t macro error types into enum within common module, too
|
| 135 |
+
- Add new "idevicenotificationproxy" tool to post or observe notifications
|
| 136 |
+
- Fix overlong blocking in np_client_free()
|
| 137 |
+
- Improve maintainability and Requires of pkg-config file
|
| 138 |
+
- API: Add new LOCKDOWN_E_SERVICE_LIMIT error to detect service limit states
|
| 139 |
+
- API: Remove const argv requirement for debugserver_command_new
|
| 140 |
+
- cython: Add get_path_for_bundle_identifier() method to
|
| 141 |
+
InstallationProxyClient
|
| 142 |
+
- cython: Add DebugServerClient class to communicate with debugserver
|
| 143 |
+
- Comply to strict function prototypes by using (void) instead of just ()
|
| 144 |
+
- Fix notification proxy shutdown process which was incorrectly implemented
|
| 145 |
+
- Fix linking problems on OS X
|
| 146 |
+
- Fix missing debug output which broke with the last release
|
| 147 |
+
- Unify and improve various debug messages
|
| 148 |
+
- Fix re-pairing if pairing with existing pair record failed initially
|
| 149 |
+
- Skip printing long plist (16kb+) files to prevent excessive debug output
|
| 150 |
+
- Move a few common helpers from backup tools to common utility helper code
|
| 151 |
+
- Remove incorrect flags from afc_file_open() documentation
|
| 152 |
+
- Fix various memory leaks
|
| 153 |
+
|
| 154 |
+
Version 1.1.7
|
| 155 |
+
~~~~~~~~~~~~~
|
| 156 |
+
|
| 157 |
+
* Development release "Cleaning up the yard."
|
| 158 |
+
* Changes:
|
| 159 |
+
- Fix broken app args, environment handling and memory leaks in idevicedebug
|
| 160 |
+
- Make all tools print an error if lockdown connection fails
|
| 161 |
+
- Convert int16_t macro error types into enum for better type-checking and
|
| 162 |
+
for various debugging benefits
|
| 163 |
+
- Avoid exporting non-public symbols for better ABI stability
|
| 164 |
+
- Fix failing backup process for devices having a passcode set and entering
|
| 165 |
+
lock state during the process in idevicebackup2
|
| 166 |
+
- API: Added lockdownd_start_service_with_escrow_bag()
|
| 167 |
+
- API: Added afc_remove_path_and_contents() for recursive deletion
|
| 168 |
+
- Fix last memory leak with OpenSSL through proper library deinitialization
|
| 169 |
+
- Add new idevicedebug tool to interact with debugserver on a device
|
| 170 |
+
- API: Add debugserver service implementation
|
| 171 |
+
- Handle new PermissionDenied error of file_relay due new security in iOS 8+
|
| 172 |
+
- Fix retry loop problem when device requests 0 files in idevicebackup2
|
| 173 |
+
- Add trust dialog related error codes to Cython bindings
|
| 174 |
+
- Fix various memory leaks in AFC implementation
|
| 175 |
+
- Fix disk image upload with latest iOS 8 in ideviceimagemounter
|
| 176 |
+
- Add new "dump" command to print information about a provisioning profile in
|
| 177 |
+
ideviceprovision
|
| 178 |
+
- Refactor plist print helper code and move it into common module for better
|
| 179 |
+
reuse accross the tools
|
| 180 |
+
- Do not crash if retrieving the system buid fails
|
| 181 |
+
- API: Make generic "propery_list_service_client" public
|
| 182 |
+
- Moved doc comments from private to public headers
|
| 183 |
+
- Fix possible segfault when using lockdownd_get_value() due to always
|
| 184 |
+
returning success
|
| 185 |
+
- Do not read files entirely into memory during restore in idevicebackup
|
| 186 |
+
- Plug a few memory leaks and fix invalid password check in idevicebackup2
|
| 187 |
+
- Add support for file sizes > 4GB on Win32 in idevicebackup2
|
| 188 |
+
- Fix declaration for DllMain on Win32
|
| 189 |
+
- Silence various compiler warnings
|
| 190 |
+
- Fix assert within pairing logic
|
| 191 |
+
* API is UNSTABLE
|
| 192 |
+
|
| 193 |
+
Version 1.1.6
|
| 194 |
+
~~~~~~~~~~~~~
|
| 195 |
+
|
| 196 |
+
* Development release "Way too overdue."
|
| 197 |
+
* Changes:
|
| 198 |
+
- Remove segmentation code from afc_file_read() to provide raw interface and
|
| 199 |
+
more control to API consumer I/O logic
|
| 200 |
+
- Implement global thread safe library initialization, especially to control
|
| 201 |
+
SSL backend lifecycle
|
| 202 |
+
- Major refactoring of pair record code and logic to use new usbmuxd pair
|
| 203 |
+
record management interface
|
| 204 |
+
- Replace user level with system wide pair record file handling
|
| 205 |
+
- Bump dependency to libplist 1.11 and remove use of "plist_dict_insert_item"
|
| 206 |
+
- Bump dependency to libusbmuxd 1.0.9
|
| 207 |
+
- Finish pair record and trust dialog handling for iOS 7+
|
| 208 |
+
- Improve AFC write performance and memory usage
|
| 209 |
+
- Add support for custom output filename to idevicescreenshot
|
| 210 |
+
- Fix detection and compilation for Python 3.x
|
| 211 |
+
- API: Added file_relay_request_sources_timeout()
|
| 212 |
+
- Fix broken HouseArrestClient class in cython bindings
|
| 213 |
+
- Add new idevicecrashreport tool to retrieve crash reports and logs from a
|
| 214 |
+
device
|
| 215 |
+
- Prevent "Failed to restart/shutdown device" messages in idevicediagnostics
|
| 216 |
+
- Link against ws2_32.dll on Win32
|
| 217 |
+
- Add support for iOS 7+ disk image mounting to ideviceimagemounter
|
| 218 |
+
- Add new idevicename tool to get or set the device name
|
| 219 |
+
- Allow unbacking of encrypted backups with a given password to idevicebackup2
|
| 220 |
+
- Remove sending "Goodbye" request on lockdown
|
| 221 |
+
- Add support for newer PLIST_REAL based time type to idevicedate
|
| 222 |
+
- Add note about setting time not working on iOS 6+ to idevicedate
|
| 223 |
+
- Handle partial SSL reads correctly now to prevent random crashes
|
| 224 |
+
- Fix duplicated output in ideviceinfo output
|
| 225 |
+
- Remove a bunch of dead code
|
| 226 |
+
- Fix deprecated OpenSSL "RSA_generate_key" with "RSA_generate_key_ex" which
|
| 227 |
+
is available since OpenSSL 0.9.8 (July 2005)
|
| 228 |
+
- Improve debug messages
|
| 229 |
+
- Enforce "-fsigned-char" to fix issues on embedded platforms
|
| 230 |
+
- Fix compilation with Clang/LLVM
|
| 231 |
+
- Avoid versioning for shared library on Win32
|
| 232 |
+
- Add experimental support for controlling cloud backup mode to idevicebackup2
|
| 233 |
+
- Save EscrowBag when starting service for automatic unlocking in pair record
|
| 234 |
+
- Remove pairing logic which is obsoleted by usbmuxd's preflight handler
|
| 235 |
+
- Fix shutdown of SSL connection to be correct and no longer generate errors
|
| 236 |
+
on device
|
| 237 |
+
- Add support for GnuTLS 3.x and fix broken GnuTLS backend
|
| 238 |
+
- Add extensions to generated certificates to match native ones
|
| 239 |
+
- Add "systembuid" command to idevicepair
|
| 240 |
+
- Allow starting service without the need for a running SSL session
|
| 241 |
+
- Refactor more code into common module
|
| 242 |
+
- Add option to filerelaytest to specify a source to request
|
| 243 |
+
- Fix support for partial messages in webinspector implementation
|
| 244 |
+
- Implement support for encrypted backups in idevicebackup2
|
| 245 |
+
- API: Export SSL control functions for idevice_connection_t
|
| 246 |
+
- API: Make generic service client public to allow external service
|
| 247 |
+
implementations
|
| 248 |
+
- Implement *_start_service() helper for easier creation of service clients
|
| 249 |
+
- Add public *_SERVICE_NAME defines for each service
|
| 250 |
+
- Fix a great bunch of memory leaks after intensive valgrind session
|
| 251 |
+
- Security: Fix insecure use of the /tmp directory (CVE-2013-2142)
|
| 252 |
+
- A bunch of memory leak fixes
|
| 253 |
+
- Python: Various fixes and support for "with" statement for AfcFile class
|
| 254 |
+
- Python: Add Afc2Client class to allow jailbroken filesystem access
|
| 255 |
+
- Fix linking issue with newer libtool as reported for Ubuntu
|
| 256 |
+
- Fix stuck thread in idevicesyslog which broke quit from within the tool
|
| 257 |
+
- Add syslog_relay service implementation and use it in idevicesyslog
|
| 258 |
+
- API: Add instproxy_client_get_path_for_bundle_identifier() helper
|
| 259 |
+
- API: Add afc_dictionary_free() helper
|
| 260 |
+
- Move thread, socket, debug and userpref code to "common" source directory
|
| 261 |
+
in order to improve code reuse
|
| 262 |
+
- Fix broken byte order detection in configure.ac which could lead to broken
|
| 263 |
+
AFC protocol communication on platforms without endian.h (Raspberry PI)
|
| 264 |
+
* API is UNSTABLE
|
| 265 |
+
|
| 266 |
+
Version 1.1.5
|
| 267 |
+
~~~~~~~~~~~~~
|
| 268 |
+
|
| 269 |
+
* Development release
|
| 270 |
+
* Changes:
|
| 271 |
+
- Implement automatic reconnecting in idevicesyslog
|
| 272 |
+
- Refactor all services to use new base service
|
| 273 |
+
- Add new generic service_client_factory_start_service() helper
|
| 274 |
+
- Implement a base service that all services inherit from
|
| 275 |
+
- API: Refactor use of "port numbers" into a "service descriptor" which is
|
| 276 |
+
a needed change as all services must now transparently support SSL.
|
| 277 |
+
Fortunately, only minor changes are needed to migrate your code properly.
|
| 278 |
+
- Add experimental ideviceheartbeat to allow service checkin over the network
|
| 279 |
+
- Add heartbeat service implementation to keep alive network connections
|
| 280 |
+
- Add webinspector service implementation for WebKit remote debugging
|
| 281 |
+
- Fix idevicebackup2 failing due to integer overflow in free disk space
|
| 282 |
+
calculation on 32 bit architectures and large disk capacities
|
| 283 |
+
- Add support for encrypted and password protected backups to idevicebackup2
|
| 284 |
+
- Fix major "too long filename received" bug in idevicebackup2
|
| 285 |
+
- Various fixes for proper and tested WIN32 support including MinGW building
|
| 286 |
+
- Fix various crashers and improve quality of idevicebackup2 tool
|
| 287 |
+
- Add endianness helpers for systems lacking support
|
| 288 |
+
- Fix idevicedate to work on iOS 6+
|
| 289 |
+
- Add idevicediagnostics tool
|
| 290 |
+
- Add diagnostics_relay service implementation
|
| 291 |
+
- Add idevicedebugserverproxy tool for remote lldb debugging
|
| 292 |
+
- Add ideviceprovision tool
|
| 293 |
+
- Add misagent service implementation to manage provisioning profiles
|
| 294 |
+
- Fix crash if $HOME is empty or not defined
|
| 295 |
+
- Fix non-ASCII characters being stripped when using plist communication
|
| 296 |
+
- Improve compile support for cython and check it at configure time
|
| 297 |
+
- Bump cython requirement to 0.17.0+
|
| 298 |
+
- Fix compilation of cython bindings
|
| 299 |
+
- Python bindings now cover all C APIs
|
| 300 |
+
- Fix iOS 6 compatibility for mobilesync, mobilebackup, mobilebackup2 and
|
| 301 |
+
screenshotr by bumping device link protocol version number
|
| 302 |
+
- Do not strip non_ASCII characters from XML plists
|
| 303 |
+
- Fix possible crash when using OpenSSL
|
| 304 |
+
* API is UNSTABLE
|
| 305 |
+
|
| 306 |
+
Version 1.1.4
|
| 307 |
+
~~~~~~~~~~~~~
|
| 308 |
+
|
| 309 |
+
* Development release
|
| 310 |
+
* Changes:
|
| 311 |
+
- Fix a bug in idevicesyslog causing the connection to close after timeout
|
| 312 |
+
- Bump soname revision
|
| 313 |
+
* API is UNSTABLE
|
| 314 |
+
|
| 315 |
+
Version 1.1.3
|
| 316 |
+
~~~~~~~~~~~~~
|
| 317 |
+
|
| 318 |
+
* Development release
|
| 319 |
+
* Changes:
|
| 320 |
+
- Bump libusbmuxd dependency to 1.0.8
|
| 321 |
+
- Fix reading from syslog_relay and remove null characters
|
| 322 |
+
- Relicense ideviceimagemounter and idevicescreenshot to LGPL
|
| 323 |
+
- Fix a crash when using restored_client_free()
|
| 324 |
+
- API: Add sbservices_get_interface_orientation()
|
| 325 |
+
- Update man pages and code comments for documentation
|
| 326 |
+
- Minor cleanup
|
| 327 |
+
* API is UNSTABLE
|
| 328 |
+
|
| 329 |
+
Version 1.1.2
|
| 330 |
+
~~~~~~~~~~~~~
|
| 331 |
+
|
| 332 |
+
* Development release
|
| 333 |
+
* Changes:
|
| 334 |
+
- Add Python bindings generated by Cython
|
| 335 |
+
- Bump libplist requirement to latest 1.8
|
| 336 |
+
- Add support for OpenSSL with fallback to GNUTLS
|
| 337 |
+
- Improvements and various fixes for Win32 and OS X build
|
| 338 |
+
- Remove glib dependency
|
| 339 |
+
- Improve restored implementation
|
| 340 |
+
- Fix various memory leaks
|
| 341 |
+
- Fix support for iOS 5 and later
|
| 342 |
+
* SWIG Python Bindings are removed
|
| 343 |
+
* API is UNSTABLE
|
| 344 |
+
|
| 345 |
+
Version 1.1.1
|
| 346 |
+
~~~~~~~~~~~~~
|
| 347 |
+
|
| 348 |
+
* Development release
|
| 349 |
+
* Changes:
|
| 350 |
+
- Add new idevicebackup2 tool for full backup and restore support on iOS 4+
|
| 351 |
+
- Add a workaround for a bug in iOS 4.3 affecting lockdown_get_value() which
|
| 352 |
+
most prominently affected libgpod, gvfs, ideviceinfo and some other tools
|
| 353 |
+
- Read ProxyDeath message to preventing obsolete messages in device syslog
|
| 354 |
+
- Rework SWIG detection and includes
|
| 355 |
+
- Add new idevicedate tool to get or set the clock on iDevices
|
| 356 |
+
- API: Add mobilesync_clear_all_records_on_device()
|
| 357 |
+
- API: Change device_link_service_disconnect() to accept a message
|
| 358 |
+
- Add manpages for ideviceenterrecovery, idevicepair, idevicebackup2 and
|
| 359 |
+
idevicedate
|
| 360 |
+
- Add missing libgen.h include to silence compiler warnings
|
| 361 |
+
- Fix a segfault that might occour if locally stored certs could not be read
|
| 362 |
+
- Fix various memory leaks
|
| 363 |
+
- Update documentation
|
| 364 |
+
* Python Bindings will get refactored completely
|
| 365 |
+
* API is UNSTABLE
|
| 366 |
+
|
| 367 |
+
Version 1.1.0
|
| 368 |
+
~~~~~~~~~~~~~
|
| 369 |
+
|
| 370 |
+
* Development release
|
| 371 |
+
* Changes:
|
| 372 |
+
- Implement restoring backups using idevicebackup
|
| 373 |
+
- Allow connecting without pairing using "ideviceinfo -s"
|
| 374 |
+
- Add ideviceenterrecovery tool
|
| 375 |
+
- Add mobilesync service implementation
|
| 376 |
+
- Add restored service implementation for restore mode
|
| 377 |
+
- Add home_arrest service implementation for document sharing
|
| 378 |
+
- Add API afc_client_new_from_connection()
|
| 379 |
+
- Support to fetch wallpaper in sbservices
|
| 380 |
+
- Support for formatVersion 2 of iOS 4+ in sbservices
|
| 381 |
+
- Add new lockdownd domains to ideviceinfo
|
| 382 |
+
- Give the device time to prepare backup data to prevent abort
|
| 383 |
+
- Improve idevicebackup output
|
| 384 |
+
- notification_proxy fixes and new notification type
|
| 385 |
+
- Silence some 64bit compiler warnings
|
| 386 |
+
- Fix various memory leaks
|
| 387 |
+
- Update documentation
|
| 388 |
+
* Python Bindings will get refactored completely
|
| 389 |
+
* API is UNSTABLE
|
| 390 |
+
|
| 391 |
+
Version 1.0.7
|
| 392 |
+
~~~~~~~~~~~~~
|
| 393 |
+
|
| 394 |
+
* Maintenance release of stable series
|
| 395 |
+
* Changes:
|
| 396 |
+
- Fix SWIG 2.x detection
|
| 397 |
+
- Fix support for iOS 5 and later
|
| 398 |
+
- Flush output of idevicesyslog immediately
|
| 399 |
+
- Replace deprecated GNUTLS functions properly
|
| 400 |
+
- Fix segfaults in library and some tools
|
| 401 |
+
- Fix memory leaks
|
| 402 |
+
- Build fixes
|
| 403 |
+
|
| 404 |
+
Version 1.0.6
|
| 405 |
+
~~~~~~~~~~~~~
|
| 406 |
+
|
| 407 |
+
* Quick follow up release
|
| 408 |
+
* Changes:
|
| 409 |
+
- Add ideviceenterrecovery which was missing in last release by accident
|
| 410 |
+
|
| 411 |
+
Version 1.0.5
|
| 412 |
+
~~~~~~~~~~~~~
|
| 413 |
+
|
| 414 |
+
* Maintenance release of stable series
|
| 415 |
+
* Changes:
|
| 416 |
+
- Add a workaround for a bug in iOS 4.3 affecting lockdown_get_value() which
|
| 417 |
+
most prominently affected libgpod, gvfs, ideviceinfo and some other tools
|
| 418 |
+
- Read ProxyDeath message to preventing obsolete messages in device syslog
|
| 419 |
+
- Rework SWIG detection and includes
|
| 420 |
+
- Add manpages for ideviceenterrecovery and idevicepair
|
| 421 |
+
- Add missing libgen.h include to silence compiler warnings
|
| 422 |
+
|
| 423 |
+
Version 1.0.4
|
| 424 |
+
~~~~~~~~~~~~~
|
| 425 |
+
|
| 426 |
+
* Maintenance release of stable series
|
| 427 |
+
* Changes:
|
| 428 |
+
- Fix a possible crash in lockdownd_client_new_with_handshake()
|
| 429 |
+
- Do not not check for Swig/Python if --without-swig is set
|
| 430 |
+
- Fail with an error message if libgcrypt is not found
|
| 431 |
+
- Pass host certificate with GNUTLS correctly
|
| 432 |
+
- Fix connecting to iOS 4.2.1+ devices
|
| 433 |
+
|
| 434 |
+
Version 1.0.3
|
| 435 |
+
~~~~~~~~~~~~~
|
| 436 |
+
|
| 437 |
+
* Maintenance release of stable series
|
| 438 |
+
* Changes:
|
| 439 |
+
- Terminate idevicesyslog on receive errors (like device unplug)
|
| 440 |
+
- Bugfixes for idevicebackup tool
|
| 441 |
+
- Hopefully the last fixes for big endian machines
|
| 442 |
+
- Build fixes for FreeBSD Python support
|
| 443 |
+
- Fix build on Mac OS X
|
| 444 |
+
|
| 445 |
+
Version 1.0.2
|
| 446 |
+
~~~~~~~~~~~~~
|
| 447 |
+
|
| 448 |
+
* Maintenance release of stable series
|
| 449 |
+
* Changes:
|
| 450 |
+
- Backport new idevicepair tool to manage pairings
|
| 451 |
+
- Fix a bug causing bad backup data
|
| 452 |
+
- Silence 64bit compiler warnings
|
| 453 |
+
- Plug some memory leaks
|
| 454 |
+
|
| 455 |
+
Version 1.0.1
|
| 456 |
+
~~~~~~~~~~~~~
|
| 457 |
+
|
| 458 |
+
* Maintenance release of stable series
|
| 459 |
+
* Changes:
|
| 460 |
+
- Cleanup includes of files
|
| 461 |
+
- Use glib instead of netinet for endianess
|
| 462 |
+
- Fix installation_proxy not adding client options correctly
|
| 463 |
+
- idevicebackup: better handle broken or missing plist files
|
| 464 |
+
- Fix some memory leaks in pairing/handshake process
|
| 465 |
+
- Fix label not being used in lockdownd_client_new()
|
| 466 |
+
- Update AUTHORS, README and installation instructions
|
| 467 |
+
|
| 468 |
+
Version 1.0.0
|
| 469 |
+
~~~~~~~~~~~~~
|
| 470 |
+
|
| 471 |
+
* Changes:
|
| 472 |
+
- Update and fix documentation for full coverage
|
| 473 |
+
- Add man pages for tools
|
| 474 |
+
- Extend mobilebackup interface
|
| 475 |
+
- Add user data argument to notification callback function
|
| 476 |
+
- Fix broken Python bindings
|
| 477 |
+
- Add Python bindings for notification proxy interface
|
| 478 |
+
- Add screenshotr interface and tool
|
| 479 |
+
- Add mobile_image_mounter interface and tool
|
| 480 |
+
- Remove HAL fdi rules
|
| 481 |
+
|
| 482 |
+
Version 0.9.7 (RC1)
|
| 483 |
+
~~~~~~~~~~~~~~~~~~~
|
| 484 |
+
|
| 485 |
+
* Project is now called libimobiledevice due to legal reasons
|
| 486 |
+
* Changes:
|
| 487 |
+
- Project renamed to libimobiledevice
|
| 488 |
+
- Add soname versioning for future releases
|
| 489 |
+
- Fix regression causing never paired devices to not work by adding
|
| 490 |
+
auto-pairing for devices in lockdownd_client_new_with_handshake
|
| 491 |
+
- Add file_relay service implementation and dev test tool
|
| 492 |
+
- Minor device link service fixes
|
| 493 |
+
- New idevicebackup tool with support for full and incremental backups
|
| 494 |
+
- Add mobilebackup service implementation
|
| 495 |
+
|
| 496 |
+
Version 0.9.6
|
| 497 |
+
~~~~~~~~~~~~~
|
| 498 |
+
|
| 499 |
+
* Changes:
|
| 500 |
+
- Minor public API changes to prepare for 1.0 release:
|
| 501 |
+
* lockdownd_client_new -> lockdownd_client_new_with_handshake
|
| 502 |
+
* fooservice_recv -> fooservice_receive
|
| 503 |
+
* iphone_device_send/_recv -> iphone_connection_send/_receive
|
| 504 |
+
- Rename some code for consistency
|
| 505 |
+
- Refactor pairing to allow custom pair records
|
| 506 |
+
- Move SSL handling out of lockdownd code
|
| 507 |
+
- Refactor lockdown session handling code
|
| 508 |
+
- Remove debug mask support
|
| 509 |
+
- No longer do a full lockdown handshake on client_new
|
| 510 |
+
- Refactor debug code to be consistent and easier to use
|
| 511 |
+
- Run validate_pair by default during lockdown handshake
|
| 512 |
+
- Allow retrieving the type for lockdown query_type request
|
| 513 |
+
- Add new property_list_service and device_link_service abstractions
|
| 514 |
+
- Detect pairing failure due to having a password set on the device
|
| 515 |
+
- Implement lockdown phone activation and deactivation
|
| 516 |
+
- Fix iphoneinfo not printing values in key/value mode
|
| 517 |
+
- Implement lockdownd_unpair() request
|
| 518 |
+
- Add more notification ids and lockdown domains
|
| 519 |
+
- Implement label support for lockdown requests
|
| 520 |
+
- Add new installation_proxy interface
|
| 521 |
+
- Add new sbservices interface
|
| 522 |
+
- Implement lockdownd_validate_pair() request
|
| 523 |
+
- Add endian safety to AFC
|
| 524 |
+
- Make lockdown sessions without SSL work
|
| 525 |
+
- Fix linking on Mandriva Linux
|
| 526 |
+
- Minor bugfixes and documentation updates
|
| 527 |
+
|
| 528 |
+
Version 0.9.5
|
| 529 |
+
~~~~~~~~~~~~~
|
| 530 |
+
|
| 531 |
+
* Changes:
|
| 532 |
+
- Updated to the latest libplist 0.16 API
|
| 533 |
+
- Fixed various minor leaks and issues
|
| 534 |
+
- Updated Python bindings and module name
|
| 535 |
+
|
| 536 |
+
Version 0.9.4
|
| 537 |
+
~~~~~~~~~~~~~
|
| 538 |
+
|
| 539 |
+
* Changes:
|
| 540 |
+
- Update to libplist 0.15 API rework
|
| 541 |
+
- Update Python bindings
|
| 542 |
+
- Bufixes around usbmuxd daemon usage
|
| 543 |
+
- Use automake 1.11 silent rules if available
|
| 544 |
+
- Various bugfixes
|
| 545 |
+
|
| 546 |
+
Version 0.9.3
|
| 547 |
+
~~~~~~~~~~~~~
|
| 548 |
+
|
| 549 |
+
* Changes:
|
| 550 |
+
- Bump libplist requirement to 0.13 and remove deprecated code
|
| 551 |
+
|
| 552 |
+
Version 0.9.2
|
| 553 |
+
~~~~~~~~~~~~~
|
| 554 |
+
|
| 555 |
+
* Changes:
|
| 556 |
+
- Migrate to use the new usbmuxd daemon
|
| 557 |
+
- Refactor whole API
|
| 558 |
+
- Add iPhone 3GS support
|
| 559 |
+
- Add hard/symlink support for AFC
|
| 560 |
+
- New iphone_id tool to list connected devices and get the device
|
| 561 |
+
name
|
| 562 |
+
- iphoneinfo now allows plist/xml output and queries by
|
| 563 |
+
domain/key
|
| 564 |
+
- Fix a lot of bugs/crashes, compiler warnings and comments
|
| 565 |
+
|
| 566 |
+
Version 0.9.1
|
| 567 |
+
~~~~~~~~~~~~~
|
| 568 |
+
|
| 569 |
+
* Changes:
|
| 570 |
+
- Fix make distcheck
|
| 571 |
+
- Bump libplist requirement to 0.12 and remove deprecated code
|
| 572 |
+
- A bunch of autotools fixes
|
| 573 |
+
|
| 574 |
+
Version 0.9.0
|
| 575 |
+
~~~~~~~~~~~~~
|
| 576 |
+
|
| 577 |
+
* Changes:
|
| 578 |
+
- Fix pkg-config dependancies
|
| 579 |
+
- Fix Python binding generation
|
| 580 |
+
- AFC cleanup and improved error handling
|
| 581 |
+
- Add support for the notification proxy service
|
| 582 |
+
- Add tools to show device information and relay syslog
|
| 583 |
+
- More robust pairing implementation
|
| 584 |
+
- Remove libiphone-initconf, SSL implementation handles it at
|
| 585 |
+
runtime now
|
| 586 |
+
- Fix receive of plists larger than a packet
|
| 587 |
+
- Return an error if failed to start a service on the device
|
| 588 |
+
- Fix usb enumeration
|
| 589 |
+
- Fix udev rule to catch usb hubs, too
|
| 590 |
+
- Add large file support
|
| 591 |
+
- Move out plist handling into libplist and depend on it
|
| 592 |
+
- Add Python bindings
|
| 593 |
+
- Lots of bugfixes
|
| 594 |
+
|
| 595 |
+
Version 0.1.0
|
| 596 |
+
~~~~~~~~~~~~~
|
| 597 |
+
|
| 598 |
+
* Changes:
|
| 599 |
+
- Use udev to set usb configuration; iphone kmod is obsolete now
|
| 600 |
+
- Remove HAL mounting
|
| 601 |
+
- Bugfixes
|
| 602 |
+
|
README.md
CHANGED
|
@@ -1,10 +1,201 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# libimobiledevice
|
| 2 |
+
|
| 3 |
+
*A library to communicate with services on iOS devices using native protocols.*
|
| 4 |
+
|
| 5 |
+

|
| 6 |
+
|
| 7 |
+
## Features
|
| 8 |
+
|
| 9 |
+
libimobiledevice is a cross-platform software library that talks the protocols
|
| 10 |
+
to interact with iOS devices.
|
| 11 |
+
|
| 12 |
+
Unlike other projects, it does not depend on using any existing proprietary
|
| 13 |
+
libraries and does not require jailbreaking.
|
| 14 |
+
|
| 15 |
+
Some key features are:
|
| 16 |
+
|
| 17 |
+
- **Interface**: Implements many high-level interfaces for device services
|
| 18 |
+
- **Implementation**: Object oriented architecture and service abstraction layer
|
| 19 |
+
- **Cross-Platform:** Tested on Linux, macOS, Windows and Android platforms
|
| 20 |
+
- **Utilities**: Provides various command-line utilities for device services
|
| 21 |
+
- **SSL**: Allows choosing between OpenSSL, GnuTLS, or MbedTLS to handle SSL communication
|
| 22 |
+
- **Network**: Supports network connections with "WiFi sync" enabled devices
|
| 23 |
+
- **Python:** Provides Cython based bindings for Python
|
| 24 |
+
|
| 25 |
+
The implemented interfaces of many device service protocols allow applications
|
| 26 |
+
to:
|
| 27 |
+
|
| 28 |
+
* Access filesystem of a device
|
| 29 |
+
* Access documents of file sharing apps
|
| 30 |
+
* Retrieve information about a device and modify various settings
|
| 31 |
+
* Backup and restore the device in a native way compatible with iTunes
|
| 32 |
+
* Manage app icons arrangement on the device
|
| 33 |
+
* Install, remove, list and basically manage apps
|
| 34 |
+
* Activate a device using official servers
|
| 35 |
+
* Manage contacts, calendars, notes and bookmarks
|
| 36 |
+
* Retrieve and remove crashreports
|
| 37 |
+
* Retrieve various diagnostics information
|
| 38 |
+
* Establish a debug connection for app debugging
|
| 39 |
+
* Mount filesystem images
|
| 40 |
+
* Forward device notifications
|
| 41 |
+
* Manage device provisioning
|
| 42 |
+
* Take screenshots from the device screen (requires mounted developer image)
|
| 43 |
+
* Simulate changed geolocation of the device (requires mounted developer image)
|
| 44 |
+
* Relay the syslog of the device
|
| 45 |
+
* Expose a connection for WebKit remote debugging
|
| 46 |
+
|
| 47 |
+
... and much more.
|
| 48 |
+
|
| 49 |
+
The library is in development since August 2007 with the goal to bring support
|
| 50 |
+
for these devices to the Linux Desktop.
|
| 51 |
+
|
| 52 |
+
## Installation / Getting started
|
| 53 |
+
|
| 54 |
+
### Debian / Ubuntu Linux
|
| 55 |
+
|
| 56 |
+
First install all required dependencies and build tools:
|
| 57 |
+
```shell
|
| 58 |
+
sudo apt-get install \
|
| 59 |
+
build-essential \
|
| 60 |
+
pkg-config \
|
| 61 |
+
checkinstall \
|
| 62 |
+
git \
|
| 63 |
+
autoconf \
|
| 64 |
+
automake \
|
| 65 |
+
libtool-bin \
|
| 66 |
+
libplist-dev \
|
| 67 |
+
libusbmuxd-dev \
|
| 68 |
+
libimobiledevice-glue-dev \
|
| 69 |
+
libtatsu-dev \
|
| 70 |
+
libssl-dev \
|
| 71 |
+
usbmuxd
|
| 72 |
+
```
|
| 73 |
+
NOTE: [libtatsu](https://github.com/libimobiledevice/libtatsu) (and thus `libtatsu-dev`)
|
| 74 |
+
is a new library that was just published recently, you have to
|
| 75 |
+
[build it from source](https://github.com/libimobiledevice/libtatsu?tab=readme-ov-file#building).
|
| 76 |
+
|
| 77 |
+
If you want to optionally build the documentation or Python bindings use:
|
| 78 |
+
```shell
|
| 79 |
+
sudo apt-get install \
|
| 80 |
+
doxygen \
|
| 81 |
+
cython
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
Then clone the actual project repository:
|
| 85 |
+
```shell
|
| 86 |
+
git clone https://github.com/libimobiledevice/libimobiledevice.git
|
| 87 |
+
cd libimobiledevice
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
Now you can build and install it:
|
| 91 |
+
```shell
|
| 92 |
+
./autogen.sh
|
| 93 |
+
make
|
| 94 |
+
sudo make install
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
If you require a custom prefix or other option being passed to `./configure`
|
| 98 |
+
you can pass them directly to `./autogen.sh` like this:
|
| 99 |
+
```bash
|
| 100 |
+
./autogen.sh --prefix=/opt/local --enable-debug
|
| 101 |
+
make
|
| 102 |
+
sudo make install
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
By default, OpenSSL will be used as TLS/SSL library. If you prefer GnuTLS,
|
| 106 |
+
configure with `--with-gnutls` like this:
|
| 107 |
+
```bash
|
| 108 |
+
./autogen.sh --with-gnutls
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
MbedTLS is also supported and can be enabled by passing `--with-mbedtls` to
|
| 112 |
+
configure. If mbedTLS is not installed in a default location, you need to set
|
| 113 |
+
the environment variables `mbedtls_INCLUDES` to the path that contains the
|
| 114 |
+
MbedTLS headers and `mbedtls_LIBDIR` to set the library path. Optionally,
|
| 115 |
+
`mbedtls_LIBS` can be used to set the library names directly. Example:
|
| 116 |
+
```bash
|
| 117 |
+
./autogen.sh --with-mbedtls mbedtls_INCLUDES=/opt/local/include mbedtls_LIBDIR=/opt/local/lib
|
| 118 |
+
```
|
| 119 |
+
|
| 120 |
+
## Usage
|
| 121 |
+
|
| 122 |
+
Documentation about using the library in your application is not available yet.
|
| 123 |
+
The "hacker way" for now is to look at the implementation of the included
|
| 124 |
+
utilities.
|
| 125 |
+
|
| 126 |
+
### Utilities
|
| 127 |
+
|
| 128 |
+
The library bundles the following command-line utilities in the tools directory:
|
| 129 |
+
|
| 130 |
+
| Utility | Description |
|
| 131 |
+
| -------------------------- | ------------------------------------------------------------------ |
|
| 132 |
+
| `idevice_id` | List attached devices or print device name of given device |
|
| 133 |
+
| `idevicebackup` | Create or restore backup for devices (legacy) |
|
| 134 |
+
| `idevicebackup2` | Create or restore backups for devices running iOS 4 or later |
|
| 135 |
+
| `idevicebtlogger` | Capture Bluetooth HCI traffic from a device (requires log profile) |
|
| 136 |
+
| `idevicecrashreport` | Retrieve crash reports from a device |
|
| 137 |
+
| `idevicedate` | Display the current date or set it on a device |
|
| 138 |
+
| `idevicedebug` | Interact with the debugserver service of a device |
|
| 139 |
+
| `idevicedebugserverproxy` | Proxy a debugserver connection from a device for remote debugging |
|
| 140 |
+
| `idevicediagnostics` | Interact with the diagnostics interface of a device |
|
| 141 |
+
| `ideviceenterrecovery` | Make a device enter recovery mode |
|
| 142 |
+
| `ideviceimagemounter` | Mount disk images on the device |
|
| 143 |
+
| `ideviceinfo` | Show information about a connected device |
|
| 144 |
+
| `idevicename` | Display or set the device name |
|
| 145 |
+
| `idevicenotificationproxy` | Post or observe notifications on a device |
|
| 146 |
+
| `idevicepair` | Manage host pairings with devices and usbmuxd |
|
| 147 |
+
| `ideviceprovision` | Manage provisioning profiles on a device |
|
| 148 |
+
| `idevicescreenshot` | Gets a screenshot from the connected device |
|
| 149 |
+
| `idevicesetlocation` | Simulate location on device |
|
| 150 |
+
| `idevicesyslog` | Relay syslog of a connected device |
|
| 151 |
+
| `afcclient` | Interact with device filesystem via AFC/HouseArrest |
|
| 152 |
+
|
| 153 |
+
Please consult the usage information or manual pages of each utility for a
|
| 154 |
+
documentation of available command line options and usage examples like this:
|
| 155 |
+
```shell
|
| 156 |
+
ideviceinfo --help
|
| 157 |
+
man ideviceinfo
|
| 158 |
+
```
|
| 159 |
+
|
| 160 |
+
## Contributing
|
| 161 |
+
|
| 162 |
+
We welcome contributions from anyone and are grateful for every pull request!
|
| 163 |
+
|
| 164 |
+
If you'd like to contribute, please fork the `master` branch, change, commit and
|
| 165 |
+
send a pull request for review. Once approved it can be merged into the main
|
| 166 |
+
code base.
|
| 167 |
+
|
| 168 |
+
If you plan to contribute larger changes or a major refactoring, please create a
|
| 169 |
+
ticket first to discuss the idea upfront to ensure less effort for everyone.
|
| 170 |
+
|
| 171 |
+
Please make sure your contribution adheres to:
|
| 172 |
+
* Try to follow the code style of the project
|
| 173 |
+
* Commit messages should describe the change well without being too short
|
| 174 |
+
* Try to split larger changes into individual commits of a common domain
|
| 175 |
+
* Use your real name and a valid email address for your commits
|
| 176 |
+
|
| 177 |
+
We are still working on the guidelines so bear with us!
|
| 178 |
+
|
| 179 |
+
## Links
|
| 180 |
+
|
| 181 |
+
* Homepage: https://libimobiledevice.org/
|
| 182 |
+
* Repository: https://github.com/libimobiledevice/libimobiledevice.git
|
| 183 |
+
* Repository (Mirror): https://git.libimobiledevice.org/libimobiledevice.git
|
| 184 |
+
* Issue Tracker: https://github.com/libimobiledevice/libimobiledevice/issues
|
| 185 |
+
* Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel
|
| 186 |
+
* Twitter: https://twitter.com/libimobiledev
|
| 187 |
+
|
| 188 |
+
## License
|
| 189 |
+
|
| 190 |
+
This library and utilities are licensed under the [GNU Lesser General Public License v2.1](https://www.gnu.org/licenses/lgpl-2.1.en.html),
|
| 191 |
+
also included in the repository in the `COPYING` file.
|
| 192 |
+
|
| 193 |
+
## Credits
|
| 194 |
+
|
| 195 |
+
Apple, iPhone, iPad, iPod, iPod Touch, Apple TV, Apple Watch, Mac, iOS,
|
| 196 |
+
iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc.
|
| 197 |
+
|
| 198 |
+
This project is an independent software and has not been authorized, sponsored,
|
| 199 |
+
or otherwise approved by Apple Inc.
|
| 200 |
+
|
| 201 |
+
README Updated on: 2024-10-22
|
ac_pkg_cython.m4
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
AC_DEFUN([AC_PROG_CYTHON],[
|
| 3 |
+
AC_PATH_PROGS([CYTHON],[cython cython3])
|
| 4 |
+
if test -z "$CYTHON" ; then
|
| 5 |
+
AC_MSG_WARN([Unable to find 'cython' or 'cython3' program. You should look at https://cython.org or install your distribution specific cython package.])
|
| 6 |
+
CYTHON=false
|
| 7 |
+
elif test -n "$1" ; then
|
| 8 |
+
AC_MSG_CHECKING([for Cython version])
|
| 9 |
+
[cython_version=`$CYTHON --version 2>&1 | sed 's/Cython version \(.*\)$/\1/g'`]
|
| 10 |
+
AC_MSG_RESULT([$cython_version])
|
| 11 |
+
|
| 12 |
+
# Setup extra version string for parsing
|
| 13 |
+
[cython_version_stripped=`echo $cython_version | sed 's/\([0-9]\+\)\.\([0-9]\+\)[^\.]*\(\.\([0-9]\+\)\)\?.*/0\1.0\2.0\4/g'`]
|
| 14 |
+
if test -n "$cython_version" ; then
|
| 15 |
+
# Calculate the required version number components
|
| 16 |
+
[required=$1]
|
| 17 |
+
[required_major=`echo $required | sed 's/[^0-9].*//'`]
|
| 18 |
+
if test -z "$required_major" ; then
|
| 19 |
+
[required_major=0]
|
| 20 |
+
fi
|
| 21 |
+
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
|
| 22 |
+
[required_minor=`echo $required | sed 's/[^0-9].*//'`]
|
| 23 |
+
if test -z "$required_minor" ; then
|
| 24 |
+
[required_minor=0]
|
| 25 |
+
fi
|
| 26 |
+
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
|
| 27 |
+
[required_patch=`echo $required | sed 's/[^0-9].*//'`]
|
| 28 |
+
if test -z "$required_patch" ; then
|
| 29 |
+
[required_patch=0]
|
| 30 |
+
fi
|
| 31 |
+
|
| 32 |
+
# Calculate the available version number components
|
| 33 |
+
[available=$cython_version_stripped]
|
| 34 |
+
[available_major=`echo $available | sed 's/[^0-9].*//'`]
|
| 35 |
+
if test -z "$available_major" ; then
|
| 36 |
+
[available_major=0]
|
| 37 |
+
fi
|
| 38 |
+
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
|
| 39 |
+
[available_minor=`echo $available | sed 's/[^0-9].*//'`]
|
| 40 |
+
if test -z "$available_minor" ; then
|
| 41 |
+
[available_minor=0]
|
| 42 |
+
fi
|
| 43 |
+
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
|
| 44 |
+
[available_patch=`echo $available | sed 's/[^0-9].*//'`]
|
| 45 |
+
if test -z "$available_patch" ; then
|
| 46 |
+
[available_patch=0]
|
| 47 |
+
fi
|
| 48 |
+
|
| 49 |
+
if test $available_major -gt $required_major || \
|
| 50 |
+
( test $available_major -eq $required_major && \
|
| 51 |
+
test $available_minor -gt $required_minor ) || \
|
| 52 |
+
( test $available_major -eq $required_major && \
|
| 53 |
+
test $available_minor -eq $required_minor && \
|
| 54 |
+
test $available_patch -ge $required_patch ) ; then
|
| 55 |
+
|
| 56 |
+
AC_MSG_NOTICE([Cython executable is '$CYTHON'])
|
| 57 |
+
else
|
| 58 |
+
AC_MSG_WARN([Cython version >= $1 is required. You have $cython_version. You should look at http://www.cython.org])
|
| 59 |
+
CYTHON='echo "Error: Cython version >= $1 is required. You have '"$cython_version"'. You should look at http://www.cython.org" ; false'
|
| 60 |
+
fi
|
| 61 |
+
else
|
| 62 |
+
AC_MSG_WARN([Unable to determine Cython version])
|
| 63 |
+
CYTHON=false
|
| 64 |
+
fi
|
| 65 |
+
fi
|
| 66 |
+
AC_SUBST([CYTHON_LIB])
|
| 67 |
+
])
|
afc.c
ADDED
|
@@ -0,0 +1,1314 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* afc.c
|
| 3 |
+
* Contains functions for the built-in AFC client.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2014 Martin Szulecki All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2009-2014 Nikias Bassen. All Rights Reserved.
|
| 7 |
+
* Copyright (c) 2008 Zach C. All Rights Reserved.
|
| 8 |
+
*
|
| 9 |
+
* This library is free software; you can redistribute it and/or
|
| 10 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 11 |
+
* License as published by the Free Software Foundation; either
|
| 12 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This library is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 17 |
+
* Lesser General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 20 |
+
* License along with this library; if not, write to the Free Software
|
| 21 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 22 |
+
*/
|
| 23 |
+
|
| 24 |
+
#ifdef HAVE_CONFIG_H
|
| 25 |
+
#include <config.h>
|
| 26 |
+
#endif
|
| 27 |
+
#include <stdio.h>
|
| 28 |
+
#include <stdlib.h>
|
| 29 |
+
#include <string.h>
|
| 30 |
+
|
| 31 |
+
#ifndef _MSC_VER
|
| 32 |
+
#include <unistd.h>
|
| 33 |
+
#endif
|
| 34 |
+
|
| 35 |
+
#include "idevice.h"
|
| 36 |
+
#include "afc.h"
|
| 37 |
+
#include "common/debug.h"
|
| 38 |
+
#include "endianness.h"
|
| 39 |
+
|
| 40 |
+
/**
|
| 41 |
+
* Locks an AFC client, done for thread safety stuff
|
| 42 |
+
*
|
| 43 |
+
* @param client The AFC client connection to lock
|
| 44 |
+
*/
|
| 45 |
+
static void afc_lock(afc_client_t client)
|
| 46 |
+
{
|
| 47 |
+
debug_info("Locked");
|
| 48 |
+
mutex_lock(&client->mutex);
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
/**
|
| 52 |
+
* Unlocks an AFC client, done for thread safety stuff.
|
| 53 |
+
*
|
| 54 |
+
* @param client The AFC
|
| 55 |
+
*/
|
| 56 |
+
static void afc_unlock(afc_client_t client)
|
| 57 |
+
{
|
| 58 |
+
debug_info("Unlocked");
|
| 59 |
+
mutex_unlock(&client->mutex);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
/**
|
| 63 |
+
* Makes a connection to the AFC service on the device using the given
|
| 64 |
+
* connection.
|
| 65 |
+
*
|
| 66 |
+
* @param service_client A connected service client
|
| 67 |
+
* @param client Pointer that will be set to a newly allocated afc_client_t
|
| 68 |
+
* upon successful return.
|
| 69 |
+
*
|
| 70 |
+
* @return AFC_E_SUCCESS on success, AFC_E_INVALID_ARG if connection is
|
| 71 |
+
* invalid, or AFC_E_NO_MEM if there is a memory allocation problem.
|
| 72 |
+
*/
|
| 73 |
+
|
| 74 |
+
afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client)
|
| 75 |
+
{
|
| 76 |
+
if (!service_client)
|
| 77 |
+
return AFC_E_INVALID_ARG;
|
| 78 |
+
|
| 79 |
+
afc_client_t client_loc = (afc_client_t) malloc(sizeof(struct afc_client_private));
|
| 80 |
+
client_loc->parent = service_client;
|
| 81 |
+
client_loc->free_parent = 0;
|
| 82 |
+
|
| 83 |
+
/* allocate a packet */
|
| 84 |
+
client_loc->packet_extra = 1024;
|
| 85 |
+
client_loc->afc_packet = (AFCPacket *) malloc(sizeof(AFCPacket) + client_loc->packet_extra);
|
| 86 |
+
if (!client_loc->afc_packet) {
|
| 87 |
+
free(client_loc);
|
| 88 |
+
return AFC_E_NO_MEM;
|
| 89 |
+
}
|
| 90 |
+
client_loc->afc_packet->packet_num = 0;
|
| 91 |
+
client_loc->afc_packet->entire_length = 0;
|
| 92 |
+
client_loc->afc_packet->this_length = 0;
|
| 93 |
+
memcpy(client_loc->afc_packet->magic, AFC_MAGIC, AFC_MAGIC_LEN);
|
| 94 |
+
mutex_init(&client_loc->mutex);
|
| 95 |
+
|
| 96 |
+
*client = client_loc;
|
| 97 |
+
return AFC_E_SUCCESS;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t * client)
|
| 101 |
+
{
|
| 102 |
+
if (!device || !service || service->port == 0)
|
| 103 |
+
return AFC_E_INVALID_ARG;
|
| 104 |
+
|
| 105 |
+
service_client_t parent = NULL;
|
| 106 |
+
if (service_client_new(device, service, &parent) != SERVICE_E_SUCCESS) {
|
| 107 |
+
return AFC_E_MUX_ERROR;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
afc_error_t err = afc_client_new_with_service_client(parent, client);
|
| 111 |
+
if (err != AFC_E_SUCCESS) {
|
| 112 |
+
service_client_free(parent);
|
| 113 |
+
} else {
|
| 114 |
+
(*client)->free_parent = 1;
|
| 115 |
+
}
|
| 116 |
+
return err;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label)
|
| 120 |
+
{
|
| 121 |
+
int32_t err = AFC_E_UNKNOWN_ERROR;
|
| 122 |
+
service_client_factory_start_service(device, AFC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(afc_client_new), &err);
|
| 123 |
+
return err;
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
afc_error_t afc_client_free(afc_client_t client)
|
| 127 |
+
{
|
| 128 |
+
if (!client || !client->afc_packet)
|
| 129 |
+
return AFC_E_INVALID_ARG;
|
| 130 |
+
|
| 131 |
+
if (client->free_parent && client->parent) {
|
| 132 |
+
service_client_free(client->parent);
|
| 133 |
+
client->parent = NULL;
|
| 134 |
+
}
|
| 135 |
+
free(client->afc_packet);
|
| 136 |
+
mutex_destroy(&client->mutex);
|
| 137 |
+
free(client);
|
| 138 |
+
return AFC_E_SUCCESS;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
/**
|
| 142 |
+
* Dispatches an AFC packet over a client.
|
| 143 |
+
*
|
| 144 |
+
* @param client The client to send data through.
|
| 145 |
+
* @param operation The operation to perform.
|
| 146 |
+
* @param data The data to send together with the header.
|
| 147 |
+
* @param data_length The length of the data to send with the header.
|
| 148 |
+
* @param payload The data to send after the header has been sent.
|
| 149 |
+
* @param payload_length The length of data to send after the header.
|
| 150 |
+
* @param bytes_sent The total number of bytes actually sent.
|
| 151 |
+
*
|
| 152 |
+
* @return AFC_E_SUCCESS on success or an AFC_E_* error value.
|
| 153 |
+
*/
|
| 154 |
+
static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation, uint32_t data_length, const char* payload, uint32_t payload_length, uint32_t *bytes_sent)
|
| 155 |
+
{
|
| 156 |
+
uint32_t sent = 0;
|
| 157 |
+
|
| 158 |
+
if (!client || !client->parent || !client->afc_packet)
|
| 159 |
+
return AFC_E_INVALID_ARG;
|
| 160 |
+
|
| 161 |
+
*bytes_sent = 0;
|
| 162 |
+
|
| 163 |
+
if (!payload || !payload_length)
|
| 164 |
+
payload_length = 0;
|
| 165 |
+
|
| 166 |
+
client->afc_packet->packet_num++;
|
| 167 |
+
client->afc_packet->operation = operation;
|
| 168 |
+
client->afc_packet->entire_length = sizeof(AFCPacket) + data_length + payload_length;
|
| 169 |
+
client->afc_packet->this_length = sizeof(AFCPacket) + data_length;
|
| 170 |
+
|
| 171 |
+
debug_info("packet length = %i", client->afc_packet->this_length);
|
| 172 |
+
|
| 173 |
+
/* send AFC packet header and data */
|
| 174 |
+
AFCPacket_to_LE(client->afc_packet);
|
| 175 |
+
debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length);
|
| 176 |
+
sent = 0;
|
| 177 |
+
service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent);
|
| 178 |
+
AFCPacket_from_LE(client->afc_packet);
|
| 179 |
+
*bytes_sent += sent;
|
| 180 |
+
if (sent < sizeof(AFCPacket) + data_length) {
|
| 181 |
+
return AFC_E_SUCCESS;
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
sent = 0;
|
| 185 |
+
if (payload_length > 0) {
|
| 186 |
+
if (payload_length > 256) {
|
| 187 |
+
debug_info("packet payload follows (256/%u)", payload_length);
|
| 188 |
+
debug_buffer(payload, 256);
|
| 189 |
+
} else {
|
| 190 |
+
debug_info("packet payload follows");
|
| 191 |
+
debug_buffer(payload, payload_length);
|
| 192 |
+
}
|
| 193 |
+
service_send(client->parent, payload, payload_length, &sent);
|
| 194 |
+
}
|
| 195 |
+
*bytes_sent += sent;
|
| 196 |
+
if (sent < payload_length) {
|
| 197 |
+
return AFC_E_SUCCESS;
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
return AFC_E_SUCCESS;
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
/**
|
| 204 |
+
* Receives data through an AFC client and sets a variable to the received data.
|
| 205 |
+
*
|
| 206 |
+
* @param client The client to receive data on.
|
| 207 |
+
* @param bytes The char* to point to the newly-received data.
|
| 208 |
+
* @param bytes_recv How much data was received.
|
| 209 |
+
*
|
| 210 |
+
* @return AFC_E_SUCCESS on success or an AFC_E_* error value.
|
| 211 |
+
*/
|
| 212 |
+
static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t *bytes_recv)
|
| 213 |
+
{
|
| 214 |
+
AFCPacket header;
|
| 215 |
+
uint32_t entire_len = 0;
|
| 216 |
+
uint32_t this_len = 0;
|
| 217 |
+
uint32_t current_count = 0;
|
| 218 |
+
uint64_t param1 = -1;
|
| 219 |
+
char *buf = NULL;
|
| 220 |
+
uint32_t recv_len = 0;
|
| 221 |
+
|
| 222 |
+
if (bytes_recv) {
|
| 223 |
+
*bytes_recv = 0;
|
| 224 |
+
}
|
| 225 |
+
if (bytes) {
|
| 226 |
+
*bytes = NULL;
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
/* first, read the AFC header */
|
| 230 |
+
service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len);
|
| 231 |
+
AFCPacket_from_LE(&header);
|
| 232 |
+
if (recv_len == 0) {
|
| 233 |
+
debug_info("Just didn't get enough.");
|
| 234 |
+
return AFC_E_MUX_ERROR;
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
if (recv_len < sizeof(AFCPacket)) {
|
| 238 |
+
debug_info("Did not even get the AFCPacket header");
|
| 239 |
+
return AFC_E_MUX_ERROR;
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
/* check if it's a valid AFC header */
|
| 243 |
+
if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) {
|
| 244 |
+
debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!");
|
| 245 |
+
}
|
| 246 |
+
|
| 247 |
+
/* check if it has the correct packet number */
|
| 248 |
+
if (header.packet_num != client->afc_packet->packet_num) {
|
| 249 |
+
/* otherwise print a warning but do not abort */
|
| 250 |
+
debug_info("ERROR: Unexpected packet number (%lld != %lld) aborting.", header.packet_num, client->afc_packet->packet_num);
|
| 251 |
+
return AFC_E_OP_HEADER_INVALID;
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
/* then, read the attached packet */
|
| 255 |
+
if (header.this_length < sizeof(AFCPacket)) {
|
| 256 |
+
debug_info("Invalid AFCPacket header received!");
|
| 257 |
+
return AFC_E_OP_HEADER_INVALID;
|
| 258 |
+
}
|
| 259 |
+
if ((header.this_length == header.entire_length)
|
| 260 |
+
&& header.entire_length == sizeof(AFCPacket)) {
|
| 261 |
+
debug_info("Empty AFCPacket received!");
|
| 262 |
+
if (header.operation == AFC_OP_DATA) {
|
| 263 |
+
return AFC_E_SUCCESS;
|
| 264 |
+
}
|
| 265 |
+
return AFC_E_IO_ERROR;
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation);
|
| 269 |
+
|
| 270 |
+
entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket);
|
| 271 |
+
this_len = (uint32_t)header.this_length - sizeof(AFCPacket);
|
| 272 |
+
|
| 273 |
+
buf = (char*)malloc(entire_len);
|
| 274 |
+
if (this_len > 0) {
|
| 275 |
+
recv_len = 0;
|
| 276 |
+
service_receive(client->parent, buf, this_len, &recv_len);
|
| 277 |
+
if (recv_len <= 0) {
|
| 278 |
+
free(buf);
|
| 279 |
+
debug_info("Did not get packet contents!");
|
| 280 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 281 |
+
}
|
| 282 |
+
if (recv_len < this_len) {
|
| 283 |
+
free(buf);
|
| 284 |
+
debug_info("Could not receive this_len=%d bytes", this_len);
|
| 285 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 286 |
+
}
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
current_count = this_len;
|
| 290 |
+
|
| 291 |
+
if (entire_len > this_len) {
|
| 292 |
+
while (current_count < entire_len) {
|
| 293 |
+
recv_len = 0;
|
| 294 |
+
service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len);
|
| 295 |
+
if (recv_len <= 0) {
|
| 296 |
+
debug_info("Error receiving data (recv returned %d)", recv_len);
|
| 297 |
+
break;
|
| 298 |
+
}
|
| 299 |
+
current_count += recv_len;
|
| 300 |
+
}
|
| 301 |
+
if (current_count < entire_len) {
|
| 302 |
+
debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len);
|
| 303 |
+
}
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
if (current_count >= sizeof(uint64_t)) {
|
| 307 |
+
param1 = le64toh(*(uint64_t*)(buf));
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
debug_info("packet data size = %i", current_count);
|
| 311 |
+
if (current_count > 256) {
|
| 312 |
+
debug_info("packet data follows (256/%u)", current_count);
|
| 313 |
+
debug_buffer(buf, 256);
|
| 314 |
+
} else {
|
| 315 |
+
debug_info("packet data follows");
|
| 316 |
+
debug_buffer(buf, current_count);
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
/* check operation types */
|
| 320 |
+
if (header.operation == AFC_OP_STATUS) {
|
| 321 |
+
/* status response */
|
| 322 |
+
debug_info("got a status response, code=%lld", param1);
|
| 323 |
+
|
| 324 |
+
if (param1 != AFC_E_SUCCESS) {
|
| 325 |
+
/* error status */
|
| 326 |
+
/* free buffer */
|
| 327 |
+
free(buf);
|
| 328 |
+
return (afc_error_t)param1;
|
| 329 |
+
}
|
| 330 |
+
} else if (header.operation == AFC_OP_DATA) {
|
| 331 |
+
/* data response */
|
| 332 |
+
debug_info("got a data response");
|
| 333 |
+
} else if (header.operation == AFC_OP_FILE_OPEN_RES) {
|
| 334 |
+
/* file handle response */
|
| 335 |
+
debug_info("got a file handle response, handle=%lld", param1);
|
| 336 |
+
} else if (header.operation == AFC_OP_FILE_TELL_RES) {
|
| 337 |
+
/* tell response */
|
| 338 |
+
debug_info("got a tell response, position=%lld", param1);
|
| 339 |
+
} else {
|
| 340 |
+
/* unknown operation code received */
|
| 341 |
+
free(buf);
|
| 342 |
+
|
| 343 |
+
debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1);
|
| 344 |
+
#ifndef _WIN32
|
| 345 |
+
fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1);
|
| 346 |
+
#endif
|
| 347 |
+
|
| 348 |
+
return AFC_E_OP_NOT_SUPPORTED;
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
if (bytes) {
|
| 352 |
+
*bytes = buf;
|
| 353 |
+
} else {
|
| 354 |
+
free(buf);
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
*bytes_recv = current_count;
|
| 358 |
+
return AFC_E_SUCCESS;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
/**
|
| 362 |
+
* Returns counts of null characters within a string.
|
| 363 |
+
*/
|
| 364 |
+
static uint32_t count_nullspaces(const char *string, uint32_t number)
|
| 365 |
+
{
|
| 366 |
+
uint32_t i = 0, nulls = 0;
|
| 367 |
+
|
| 368 |
+
for (i = 0; i < number; i++) {
|
| 369 |
+
if (string[i] == '\0')
|
| 370 |
+
nulls++;
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
return nulls;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
/**
|
| 377 |
+
* Splits a string of tokens by null characters and returns each token in a
|
| 378 |
+
* char array/list.
|
| 379 |
+
*
|
| 380 |
+
* @param tokens The characters to split into a list.
|
| 381 |
+
* @param length The length of the tokens string.
|
| 382 |
+
*
|
| 383 |
+
* @return A char ** list with each token found in the string. The caller is
|
| 384 |
+
* responsible for freeing the memory.
|
| 385 |
+
*/
|
| 386 |
+
static char **make_strings_list(char *tokens, uint32_t length)
|
| 387 |
+
{
|
| 388 |
+
uint32_t nulls = 0, i = 0, j = 0;
|
| 389 |
+
char **list = NULL;
|
| 390 |
+
|
| 391 |
+
if (!tokens || !length)
|
| 392 |
+
return NULL;
|
| 393 |
+
|
| 394 |
+
nulls = count_nullspaces(tokens, length);
|
| 395 |
+
list = (char **) malloc(sizeof(char *) * (nulls + 1));
|
| 396 |
+
for (i = 0; i < nulls; i++) {
|
| 397 |
+
list[i] = strdup(tokens + j);
|
| 398 |
+
j += strlen(list[i]) + 1;
|
| 399 |
+
}
|
| 400 |
+
list[i] = NULL;
|
| 401 |
+
|
| 402 |
+
return list;
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
static plist_t *make_dictionary(char *tokens, size_t length)
|
| 406 |
+
{
|
| 407 |
+
size_t j = 0;
|
| 408 |
+
plist_t dict = NULL;
|
| 409 |
+
|
| 410 |
+
if (!tokens || !length)
|
| 411 |
+
return NULL;
|
| 412 |
+
|
| 413 |
+
dict = plist_new_dict();
|
| 414 |
+
|
| 415 |
+
while (j < length) {
|
| 416 |
+
size_t key_len = strnlen(tokens + j, length - j);
|
| 417 |
+
if (j + key_len >= length) {
|
| 418 |
+
plist_free(dict);
|
| 419 |
+
return NULL;
|
| 420 |
+
}
|
| 421 |
+
char* key = tokens + j;
|
| 422 |
+
j += key_len + 1;
|
| 423 |
+
|
| 424 |
+
if (j >= length) {
|
| 425 |
+
plist_free(dict);
|
| 426 |
+
return NULL;
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
size_t val_len = strnlen(tokens + j, length - j);
|
| 430 |
+
if (j + val_len >= length) {
|
| 431 |
+
plist_free(dict);
|
| 432 |
+
return NULL;
|
| 433 |
+
}
|
| 434 |
+
char* val = tokens + j;
|
| 435 |
+
j += val_len + 1;
|
| 436 |
+
|
| 437 |
+
char* endp = NULL;
|
| 438 |
+
unsigned long long u64val = strtoull(val, &endp, 10);
|
| 439 |
+
if (endp && *endp == '\0') {
|
| 440 |
+
plist_dict_set_item(dict, key, plist_new_uint(u64val));
|
| 441 |
+
} else {
|
| 442 |
+
plist_dict_set_item(dict, key, plist_new_string(val));
|
| 443 |
+
}
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
return dict;
|
| 447 |
+
}
|
| 448 |
+
|
| 449 |
+
static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len)
|
| 450 |
+
{
|
| 451 |
+
if (data_len > client->packet_extra) {
|
| 452 |
+
client->packet_extra = (data_len & ~8) + 8;
|
| 453 |
+
AFCPacket* newpkt = (AFCPacket*)realloc(client->afc_packet, sizeof(AFCPacket) + client->packet_extra);
|
| 454 |
+
if (!newpkt) {
|
| 455 |
+
return -1;
|
| 456 |
+
}
|
| 457 |
+
client->afc_packet = newpkt;
|
| 458 |
+
}
|
| 459 |
+
return 0;
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
#define AFC_PACKET_DATA_PTR ((char*)client->afc_packet + sizeof(AFCPacket))
|
| 463 |
+
|
| 464 |
+
afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information)
|
| 465 |
+
{
|
| 466 |
+
uint32_t bytes = 0;
|
| 467 |
+
char *data = NULL, **list_loc = NULL;
|
| 468 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 469 |
+
|
| 470 |
+
if (!client || !path || !directory_information || (directory_information && *directory_information))
|
| 471 |
+
return AFC_E_INVALID_ARG;
|
| 472 |
+
|
| 473 |
+
afc_lock(client);
|
| 474 |
+
|
| 475 |
+
uint32_t data_len = (uint32_t)strlen(path)+1;
|
| 476 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 477 |
+
afc_unlock(client);
|
| 478 |
+
debug_info("Failed to realloc packet buffer");
|
| 479 |
+
return AFC_E_NO_MEM;
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
/* Send the command */
|
| 483 |
+
memcpy(AFC_PACKET_DATA_PTR, path, data_len);
|
| 484 |
+
ret = afc_dispatch_packet(client, AFC_OP_READ_DIR, data_len, NULL, 0, &bytes);
|
| 485 |
+
if (ret != AFC_E_SUCCESS) {
|
| 486 |
+
afc_unlock(client);
|
| 487 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 488 |
+
}
|
| 489 |
+
/* Receive the data */
|
| 490 |
+
ret = afc_receive_data(client, &data, &bytes);
|
| 491 |
+
if (ret != AFC_E_SUCCESS) {
|
| 492 |
+
if (data)
|
| 493 |
+
free(data);
|
| 494 |
+
afc_unlock(client);
|
| 495 |
+
return ret;
|
| 496 |
+
}
|
| 497 |
+
/* Parse the data */
|
| 498 |
+
list_loc = make_strings_list(data, bytes);
|
| 499 |
+
if (data)
|
| 500 |
+
free(data);
|
| 501 |
+
|
| 502 |
+
afc_unlock(client);
|
| 503 |
+
*directory_information = list_loc;
|
| 504 |
+
|
| 505 |
+
return ret;
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
afc_error_t afc_get_device_info(afc_client_t client, char ***device_information)
|
| 509 |
+
{
|
| 510 |
+
uint32_t bytes = 0;
|
| 511 |
+
char *data = NULL, **list = NULL;
|
| 512 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 513 |
+
|
| 514 |
+
if (!client || !device_information)
|
| 515 |
+
return AFC_E_INVALID_ARG;
|
| 516 |
+
|
| 517 |
+
afc_lock(client);
|
| 518 |
+
|
| 519 |
+
/* Send the command */
|
| 520 |
+
ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes);
|
| 521 |
+
if (ret != AFC_E_SUCCESS) {
|
| 522 |
+
afc_unlock(client);
|
| 523 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 524 |
+
}
|
| 525 |
+
/* Receive the data */
|
| 526 |
+
ret = afc_receive_data(client, &data, &bytes);
|
| 527 |
+
if (ret != AFC_E_SUCCESS) {
|
| 528 |
+
if (data)
|
| 529 |
+
free(data);
|
| 530 |
+
afc_unlock(client);
|
| 531 |
+
return ret;
|
| 532 |
+
}
|
| 533 |
+
/* Parse the data */
|
| 534 |
+
list = make_strings_list(data, bytes);
|
| 535 |
+
if (data)
|
| 536 |
+
free(data);
|
| 537 |
+
|
| 538 |
+
afc_unlock(client);
|
| 539 |
+
|
| 540 |
+
*device_information = list;
|
| 541 |
+
|
| 542 |
+
return ret;
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information)
|
| 546 |
+
{
|
| 547 |
+
uint32_t bytes = 0;
|
| 548 |
+
char *data = NULL;
|
| 549 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 550 |
+
|
| 551 |
+
if (!client || !device_information)
|
| 552 |
+
return AFC_E_INVALID_ARG;
|
| 553 |
+
|
| 554 |
+
afc_lock(client);
|
| 555 |
+
|
| 556 |
+
/* Send the command */
|
| 557 |
+
ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes);
|
| 558 |
+
if (ret != AFC_E_SUCCESS) {
|
| 559 |
+
afc_unlock(client);
|
| 560 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 561 |
+
}
|
| 562 |
+
/* Receive the data */
|
| 563 |
+
ret = afc_receive_data(client, &data, &bytes);
|
| 564 |
+
if (ret != AFC_E_SUCCESS) {
|
| 565 |
+
if (data)
|
| 566 |
+
free(data);
|
| 567 |
+
afc_unlock(client);
|
| 568 |
+
return ret;
|
| 569 |
+
}
|
| 570 |
+
/* Parse the data */
|
| 571 |
+
*device_information = make_dictionary(data, bytes);
|
| 572 |
+
free(data);
|
| 573 |
+
|
| 574 |
+
afc_unlock(client);
|
| 575 |
+
|
| 576 |
+
return ret;
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value)
|
| 580 |
+
{
|
| 581 |
+
afc_error_t ret = AFC_E_INTERNAL_ERROR;
|
| 582 |
+
char **kvps, **ptr;
|
| 583 |
+
|
| 584 |
+
*value = NULL;
|
| 585 |
+
if (key == NULL)
|
| 586 |
+
return AFC_E_INVALID_ARG;
|
| 587 |
+
|
| 588 |
+
ret = afc_get_device_info(client, &kvps);
|
| 589 |
+
if (ret != AFC_E_SUCCESS)
|
| 590 |
+
return ret;
|
| 591 |
+
|
| 592 |
+
for (ptr = kvps; *ptr; ptr++) {
|
| 593 |
+
if (!strcmp(*ptr, key)) {
|
| 594 |
+
*value = strdup(*(ptr+1));
|
| 595 |
+
break;
|
| 596 |
+
}
|
| 597 |
+
}
|
| 598 |
+
for (ptr = kvps; *ptr; ptr++) {
|
| 599 |
+
free(*ptr);
|
| 600 |
+
}
|
| 601 |
+
free(kvps);
|
| 602 |
+
|
| 603 |
+
return ret;
|
| 604 |
+
}
|
| 605 |
+
|
| 606 |
+
afc_error_t afc_remove_path(afc_client_t client, const char *path)
|
| 607 |
+
{
|
| 608 |
+
uint32_t bytes = 0;
|
| 609 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 610 |
+
|
| 611 |
+
if (!client || !path || !client->afc_packet || !client->parent)
|
| 612 |
+
return AFC_E_INVALID_ARG;
|
| 613 |
+
|
| 614 |
+
afc_lock(client);
|
| 615 |
+
|
| 616 |
+
uint32_t data_len = (uint32_t)strlen(path)+1;
|
| 617 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 618 |
+
afc_unlock(client);
|
| 619 |
+
debug_info("Failed to realloc packet buffer");
|
| 620 |
+
return AFC_E_NO_MEM;
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
/* Send command */
|
| 624 |
+
memcpy(AFC_PACKET_DATA_PTR, path, data_len);
|
| 625 |
+
ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH, data_len, NULL, 0, &bytes);
|
| 626 |
+
if (ret != AFC_E_SUCCESS) {
|
| 627 |
+
afc_unlock(client);
|
| 628 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 629 |
+
}
|
| 630 |
+
/* Receive response */
|
| 631 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 632 |
+
|
| 633 |
+
/* special case; unknown error actually means directory not empty */
|
| 634 |
+
if (ret == AFC_E_UNKNOWN_ERROR)
|
| 635 |
+
ret = AFC_E_DIR_NOT_EMPTY;
|
| 636 |
+
|
| 637 |
+
afc_unlock(client);
|
| 638 |
+
|
| 639 |
+
return ret;
|
| 640 |
+
}
|
| 641 |
+
|
| 642 |
+
afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to)
|
| 643 |
+
{
|
| 644 |
+
if (!client || !from || !to || !client->afc_packet || !client->parent)
|
| 645 |
+
return AFC_E_INVALID_ARG;
|
| 646 |
+
|
| 647 |
+
uint32_t bytes = 0;
|
| 648 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 649 |
+
|
| 650 |
+
size_t from_len = strlen(from);
|
| 651 |
+
size_t to_len = strlen(to);
|
| 652 |
+
|
| 653 |
+
afc_lock(client);
|
| 654 |
+
|
| 655 |
+
uint32_t data_len = (uint32_t)(from_len+1 + to_len+1);
|
| 656 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 657 |
+
afc_unlock(client);
|
| 658 |
+
debug_info("Failed to realloc packet buffer");
|
| 659 |
+
return AFC_E_NO_MEM;
|
| 660 |
+
}
|
| 661 |
+
|
| 662 |
+
/* Send command */
|
| 663 |
+
memcpy(AFC_PACKET_DATA_PTR, from, from_len+1);
|
| 664 |
+
memcpy(AFC_PACKET_DATA_PTR + from_len+1, to, to_len+1);
|
| 665 |
+
ret = afc_dispatch_packet(client, AFC_OP_RENAME_PATH, data_len, NULL, 0, &bytes);
|
| 666 |
+
if (ret != AFC_E_SUCCESS) {
|
| 667 |
+
afc_unlock(client);
|
| 668 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 669 |
+
}
|
| 670 |
+
/* Receive response */
|
| 671 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 672 |
+
|
| 673 |
+
afc_unlock(client);
|
| 674 |
+
|
| 675 |
+
return ret;
|
| 676 |
+
}
|
| 677 |
+
|
| 678 |
+
afc_error_t afc_make_directory(afc_client_t client, const char *path)
|
| 679 |
+
{
|
| 680 |
+
uint32_t bytes = 0;
|
| 681 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 682 |
+
|
| 683 |
+
if (!client)
|
| 684 |
+
return AFC_E_INVALID_ARG;
|
| 685 |
+
|
| 686 |
+
afc_lock(client);
|
| 687 |
+
|
| 688 |
+
uint32_t data_len = (uint32_t)strlen(path)+1;
|
| 689 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 690 |
+
afc_unlock(client);
|
| 691 |
+
debug_info("Failed to realloc packet buffer");
|
| 692 |
+
return AFC_E_NO_MEM;
|
| 693 |
+
}
|
| 694 |
+
|
| 695 |
+
/* Send command */
|
| 696 |
+
memcpy(AFC_PACKET_DATA_PTR, path, data_len);
|
| 697 |
+
ret = afc_dispatch_packet(client, AFC_OP_MAKE_DIR, data_len, NULL, 0, &bytes);
|
| 698 |
+
if (ret != AFC_E_SUCCESS) {
|
| 699 |
+
afc_unlock(client);
|
| 700 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 701 |
+
}
|
| 702 |
+
/* Receive response */
|
| 703 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 704 |
+
|
| 705 |
+
afc_unlock(client);
|
| 706 |
+
|
| 707 |
+
return ret;
|
| 708 |
+
}
|
| 709 |
+
|
| 710 |
+
afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information)
|
| 711 |
+
{
|
| 712 |
+
char *received = NULL;
|
| 713 |
+
uint32_t bytes = 0;
|
| 714 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 715 |
+
|
| 716 |
+
if (!client || !path || !file_information)
|
| 717 |
+
return AFC_E_INVALID_ARG;
|
| 718 |
+
|
| 719 |
+
afc_lock(client);
|
| 720 |
+
|
| 721 |
+
uint32_t data_len = (uint32_t)strlen(path)+1;
|
| 722 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 723 |
+
afc_unlock(client);
|
| 724 |
+
debug_info("Failed to realloc packet buffer");
|
| 725 |
+
return AFC_E_NO_MEM;
|
| 726 |
+
}
|
| 727 |
+
|
| 728 |
+
/* Send command */
|
| 729 |
+
memcpy(AFC_PACKET_DATA_PTR, path, data_len);
|
| 730 |
+
ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
|
| 731 |
+
if (ret != AFC_E_SUCCESS) {
|
| 732 |
+
afc_unlock(client);
|
| 733 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 734 |
+
}
|
| 735 |
+
|
| 736 |
+
/* Receive data */
|
| 737 |
+
ret = afc_receive_data(client, &received, &bytes);
|
| 738 |
+
if (received) {
|
| 739 |
+
*file_information = make_strings_list(received, bytes);
|
| 740 |
+
free(received);
|
| 741 |
+
}
|
| 742 |
+
|
| 743 |
+
afc_unlock(client);
|
| 744 |
+
|
| 745 |
+
return ret;
|
| 746 |
+
}
|
| 747 |
+
|
| 748 |
+
afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information)
|
| 749 |
+
{
|
| 750 |
+
char *received = NULL;
|
| 751 |
+
uint32_t bytes = 0;
|
| 752 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 753 |
+
|
| 754 |
+
if (!client || !path || !file_information)
|
| 755 |
+
return AFC_E_INVALID_ARG;
|
| 756 |
+
|
| 757 |
+
afc_lock(client);
|
| 758 |
+
|
| 759 |
+
uint32_t data_len = (uint32_t)strlen(path)+1;
|
| 760 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 761 |
+
afc_unlock(client);
|
| 762 |
+
debug_info("Failed to realloc packet buffer");
|
| 763 |
+
return AFC_E_NO_MEM;
|
| 764 |
+
}
|
| 765 |
+
|
| 766 |
+
/* Send command */
|
| 767 |
+
memcpy(AFC_PACKET_DATA_PTR, path, data_len);
|
| 768 |
+
ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes);
|
| 769 |
+
if (ret != AFC_E_SUCCESS) {
|
| 770 |
+
afc_unlock(client);
|
| 771 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 772 |
+
}
|
| 773 |
+
|
| 774 |
+
/* Receive data */
|
| 775 |
+
ret = afc_receive_data(client, &received, &bytes);
|
| 776 |
+
if (received) {
|
| 777 |
+
*file_information = make_dictionary(received, bytes);
|
| 778 |
+
free(received);
|
| 779 |
+
}
|
| 780 |
+
|
| 781 |
+
afc_unlock(client);
|
| 782 |
+
|
| 783 |
+
return ret;
|
| 784 |
+
}
|
| 785 |
+
|
| 786 |
+
afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle)
|
| 787 |
+
{
|
| 788 |
+
if (!client || !client->parent || !client->afc_packet)
|
| 789 |
+
return AFC_E_INVALID_ARG;
|
| 790 |
+
|
| 791 |
+
//uint64_t file_mode_loc = htole64(file_mode);
|
| 792 |
+
uint32_t bytes = 0;
|
| 793 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 794 |
+
|
| 795 |
+
/* set handle to 0 so in case an error occurs, the handle is invalid */
|
| 796 |
+
*handle = 0;
|
| 797 |
+
|
| 798 |
+
afc_lock(client);
|
| 799 |
+
|
| 800 |
+
uint32_t data_len = (uint32_t)(strlen(filename)+1 + 8);
|
| 801 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 802 |
+
afc_unlock(client);
|
| 803 |
+
debug_info("Failed to realloc packet buffer");
|
| 804 |
+
return AFC_E_NO_MEM;
|
| 805 |
+
}
|
| 806 |
+
|
| 807 |
+
/* Send command */
|
| 808 |
+
//memcpy(AFC_PACKET_DATA_PTR, &file_mode_loc, 8);
|
| 809 |
+
*(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(file_mode);
|
| 810 |
+
memcpy(AFC_PACKET_DATA_PTR + 8, filename, data_len-8);
|
| 811 |
+
ret = afc_dispatch_packet(client, AFC_OP_FILE_OPEN, data_len, NULL, 0, &bytes);
|
| 812 |
+
if (ret != AFC_E_SUCCESS) {
|
| 813 |
+
debug_info("Didn't receive a response to the command");
|
| 814 |
+
afc_unlock(client);
|
| 815 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 816 |
+
}
|
| 817 |
+
/* Receive the data */
|
| 818 |
+
char* data = NULL;
|
| 819 |
+
ret = afc_receive_data(client, &data, &bytes);
|
| 820 |
+
if ((ret == AFC_E_SUCCESS) && (bytes > 0) && data) {
|
| 821 |
+
afc_unlock(client);
|
| 822 |
+
|
| 823 |
+
/* Get the file handle */
|
| 824 |
+
memcpy(handle, data, sizeof(uint64_t));
|
| 825 |
+
free(data);
|
| 826 |
+
return ret;
|
| 827 |
+
}
|
| 828 |
+
/* in case memory was allocated but no data received or an error occurred */
|
| 829 |
+
free(data);
|
| 830 |
+
|
| 831 |
+
debug_info("Didn't get any further data");
|
| 832 |
+
|
| 833 |
+
afc_unlock(client);
|
| 834 |
+
|
| 835 |
+
return ret;
|
| 836 |
+
}
|
| 837 |
+
|
| 838 |
+
afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read)
|
| 839 |
+
{
|
| 840 |
+
char *input = NULL;
|
| 841 |
+
uint32_t current_count = 0, bytes_loc = 0;
|
| 842 |
+
struct readinfo {
|
| 843 |
+
uint64_t handle;
|
| 844 |
+
uint64_t size;
|
| 845 |
+
};
|
| 846 |
+
afc_error_t ret = AFC_E_SUCCESS;
|
| 847 |
+
|
| 848 |
+
if (!client || !client->afc_packet || !client->parent || handle == 0)
|
| 849 |
+
return AFC_E_INVALID_ARG;
|
| 850 |
+
debug_info("called for length %i", length);
|
| 851 |
+
|
| 852 |
+
//uint32_t data_len = 8 + 8;
|
| 853 |
+
|
| 854 |
+
afc_lock(client);
|
| 855 |
+
|
| 856 |
+
/* Send the read command */
|
| 857 |
+
struct readinfo* readinfo = (struct readinfo*)(AFC_PACKET_DATA_PTR);
|
| 858 |
+
readinfo->handle = handle;
|
| 859 |
+
readinfo->size = htole64(length);
|
| 860 |
+
ret = afc_dispatch_packet(client, AFC_OP_FILE_READ, sizeof(struct readinfo), NULL, 0, &bytes_loc);
|
| 861 |
+
if (ret != AFC_E_SUCCESS) {
|
| 862 |
+
afc_unlock(client);
|
| 863 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 864 |
+
}
|
| 865 |
+
/* Receive the data */
|
| 866 |
+
ret = afc_receive_data(client, &input, &bytes_loc);
|
| 867 |
+
debug_info("afc_receive_data returned error: %d", ret);
|
| 868 |
+
debug_info("bytes returned: %i", bytes_loc);
|
| 869 |
+
if (ret != AFC_E_SUCCESS) {
|
| 870 |
+
afc_unlock(client);
|
| 871 |
+
return ret;
|
| 872 |
+
}
|
| 873 |
+
if (bytes_loc == 0) {
|
| 874 |
+
if (input)
|
| 875 |
+
free(input);
|
| 876 |
+
afc_unlock(client);
|
| 877 |
+
*bytes_read = current_count;
|
| 878 |
+
/* FIXME: check that's actually a success */
|
| 879 |
+
return ret;
|
| 880 |
+
}
|
| 881 |
+
if (input) {
|
| 882 |
+
debug_info("%d", bytes_loc);
|
| 883 |
+
memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc);
|
| 884 |
+
free(input);
|
| 885 |
+
input = NULL;
|
| 886 |
+
current_count += (bytes_loc > length) ? length : bytes_loc;
|
| 887 |
+
}
|
| 888 |
+
|
| 889 |
+
afc_unlock(client);
|
| 890 |
+
*bytes_read = current_count;
|
| 891 |
+
return ret;
|
| 892 |
+
}
|
| 893 |
+
|
| 894 |
+
afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written)
|
| 895 |
+
{
|
| 896 |
+
uint32_t current_count = 0;
|
| 897 |
+
uint32_t bytes_loc = 0;
|
| 898 |
+
afc_error_t ret = AFC_E_SUCCESS;
|
| 899 |
+
|
| 900 |
+
if (!client || !client->afc_packet || !client->parent || !bytes_written || (handle == 0))
|
| 901 |
+
return AFC_E_INVALID_ARG;
|
| 902 |
+
|
| 903 |
+
uint32_t data_len = 8;
|
| 904 |
+
|
| 905 |
+
afc_lock(client);
|
| 906 |
+
|
| 907 |
+
debug_info("Write length: %i", length);
|
| 908 |
+
|
| 909 |
+
*(uint64_t*)(AFC_PACKET_DATA_PTR) = handle;
|
| 910 |
+
ret = afc_dispatch_packet(client, AFC_OP_FILE_WRITE, data_len, data, length, &bytes_loc);
|
| 911 |
+
|
| 912 |
+
current_count += bytes_loc - (sizeof(AFCPacket) + 8);
|
| 913 |
+
|
| 914 |
+
if (ret != AFC_E_SUCCESS) {
|
| 915 |
+
afc_unlock(client);
|
| 916 |
+
*bytes_written = current_count;
|
| 917 |
+
return AFC_E_SUCCESS;
|
| 918 |
+
}
|
| 919 |
+
|
| 920 |
+
ret = afc_receive_data(client, NULL, &bytes_loc);
|
| 921 |
+
afc_unlock(client);
|
| 922 |
+
if (ret != AFC_E_SUCCESS) {
|
| 923 |
+
debug_info("Failed to receive reply (%d)", ret);
|
| 924 |
+
}
|
| 925 |
+
*bytes_written = current_count;
|
| 926 |
+
return ret;
|
| 927 |
+
}
|
| 928 |
+
|
| 929 |
+
afc_error_t afc_file_close(afc_client_t client, uint64_t handle)
|
| 930 |
+
{
|
| 931 |
+
uint32_t bytes = 0;
|
| 932 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 933 |
+
|
| 934 |
+
if (!client || (handle == 0))
|
| 935 |
+
return AFC_E_INVALID_ARG;
|
| 936 |
+
|
| 937 |
+
uint32_t data_len = 8;
|
| 938 |
+
|
| 939 |
+
afc_lock(client);
|
| 940 |
+
|
| 941 |
+
debug_info("File handle %i", handle);
|
| 942 |
+
|
| 943 |
+
/* Send command */
|
| 944 |
+
*(uint64_t*)(AFC_PACKET_DATA_PTR) = handle;
|
| 945 |
+
ret = afc_dispatch_packet(client, AFC_OP_FILE_CLOSE, data_len, NULL, 0, &bytes);
|
| 946 |
+
|
| 947 |
+
if (ret != AFC_E_SUCCESS) {
|
| 948 |
+
afc_unlock(client);
|
| 949 |
+
return AFC_E_UNKNOWN_ERROR;
|
| 950 |
+
}
|
| 951 |
+
|
| 952 |
+
/* Receive the response */
|
| 953 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 954 |
+
|
| 955 |
+
afc_unlock(client);
|
| 956 |
+
|
| 957 |
+
return ret;
|
| 958 |
+
}
|
| 959 |
+
|
| 960 |
+
afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation)
|
| 961 |
+
{
|
| 962 |
+
uint32_t bytes = 0;
|
| 963 |
+
struct lockinfo {
|
| 964 |
+
uint64_t handle;
|
| 965 |
+
uint64_t op;
|
| 966 |
+
};
|
| 967 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 968 |
+
|
| 969 |
+
if (!client || (handle == 0))
|
| 970 |
+
return AFC_E_INVALID_ARG;
|
| 971 |
+
|
| 972 |
+
afc_lock(client);
|
| 973 |
+
|
| 974 |
+
debug_info("file handle %i", handle);
|
| 975 |
+
|
| 976 |
+
/* Send command */
|
| 977 |
+
struct lockinfo* lockinfo = (struct lockinfo*)(AFC_PACKET_DATA_PTR);
|
| 978 |
+
lockinfo->handle = handle;
|
| 979 |
+
lockinfo->op = htole64(operation);
|
| 980 |
+
ret = afc_dispatch_packet(client, AFC_OP_FILE_LOCK, sizeof(struct lockinfo), NULL, 0, &bytes);
|
| 981 |
+
if (ret != AFC_E_SUCCESS) {
|
| 982 |
+
afc_unlock(client);
|
| 983 |
+
debug_info("could not send lock command");
|
| 984 |
+
return AFC_E_UNKNOWN_ERROR;
|
| 985 |
+
}
|
| 986 |
+
/* Receive the response */
|
| 987 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 988 |
+
|
| 989 |
+
afc_unlock(client);
|
| 990 |
+
|
| 991 |
+
return ret;
|
| 992 |
+
}
|
| 993 |
+
|
| 994 |
+
afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence)
|
| 995 |
+
{
|
| 996 |
+
uint32_t bytes = 0;
|
| 997 |
+
struct seekinfo {
|
| 998 |
+
uint64_t handle;
|
| 999 |
+
uint64_t whence;
|
| 1000 |
+
int64_t offset;
|
| 1001 |
+
};
|
| 1002 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 1003 |
+
|
| 1004 |
+
if (!client || (handle == 0))
|
| 1005 |
+
return AFC_E_INVALID_ARG;
|
| 1006 |
+
|
| 1007 |
+
afc_lock(client);
|
| 1008 |
+
|
| 1009 |
+
/* Send the command */
|
| 1010 |
+
struct seekinfo* seekinfo = (struct seekinfo*)(AFC_PACKET_DATA_PTR);
|
| 1011 |
+
seekinfo->handle = handle;
|
| 1012 |
+
seekinfo->whence = htole64(whence);
|
| 1013 |
+
seekinfo->offset = (int64_t)htole64(offset);
|
| 1014 |
+
ret = afc_dispatch_packet(client, AFC_OP_FILE_SEEK, sizeof(struct seekinfo), NULL, 0, &bytes);
|
| 1015 |
+
|
| 1016 |
+
if (ret != AFC_E_SUCCESS) {
|
| 1017 |
+
afc_unlock(client);
|
| 1018 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 1019 |
+
}
|
| 1020 |
+
/* Receive response */
|
| 1021 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 1022 |
+
|
| 1023 |
+
afc_unlock(client);
|
| 1024 |
+
|
| 1025 |
+
return ret;
|
| 1026 |
+
}
|
| 1027 |
+
|
| 1028 |
+
afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position)
|
| 1029 |
+
{
|
| 1030 |
+
char *buffer = NULL;
|
| 1031 |
+
uint32_t bytes = 0;
|
| 1032 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 1033 |
+
|
| 1034 |
+
if (!client || (handle == 0))
|
| 1035 |
+
return AFC_E_INVALID_ARG;
|
| 1036 |
+
|
| 1037 |
+
uint32_t data_len = 8;
|
| 1038 |
+
|
| 1039 |
+
afc_lock(client);
|
| 1040 |
+
|
| 1041 |
+
/* Send the command */
|
| 1042 |
+
*(uint64_t*)(AFC_PACKET_DATA_PTR) = handle;
|
| 1043 |
+
ret = afc_dispatch_packet(client, AFC_OP_FILE_TELL, data_len, NULL, 0, &bytes);
|
| 1044 |
+
if (ret != AFC_E_SUCCESS) {
|
| 1045 |
+
afc_unlock(client);
|
| 1046 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 1047 |
+
}
|
| 1048 |
+
|
| 1049 |
+
/* Receive the data */
|
| 1050 |
+
ret = afc_receive_data(client, &buffer, &bytes);
|
| 1051 |
+
if (bytes > 0 && buffer) {
|
| 1052 |
+
/* Get the position */
|
| 1053 |
+
memcpy(position, buffer, sizeof(uint64_t));
|
| 1054 |
+
*position = le64toh(*position);
|
| 1055 |
+
}
|
| 1056 |
+
free(buffer);
|
| 1057 |
+
|
| 1058 |
+
afc_unlock(client);
|
| 1059 |
+
|
| 1060 |
+
return ret;
|
| 1061 |
+
}
|
| 1062 |
+
|
| 1063 |
+
afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize)
|
| 1064 |
+
{
|
| 1065 |
+
uint32_t bytes = 0;
|
| 1066 |
+
struct truncinfo {
|
| 1067 |
+
uint64_t handle;
|
| 1068 |
+
uint64_t newsize;
|
| 1069 |
+
};
|
| 1070 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 1071 |
+
|
| 1072 |
+
if (!client || (handle == 0))
|
| 1073 |
+
return AFC_E_INVALID_ARG;
|
| 1074 |
+
|
| 1075 |
+
afc_lock(client);
|
| 1076 |
+
|
| 1077 |
+
/* Send command */
|
| 1078 |
+
struct truncinfo* truncinfo = (struct truncinfo*)(AFC_PACKET_DATA_PTR);
|
| 1079 |
+
truncinfo->handle = handle;
|
| 1080 |
+
truncinfo->newsize = htole64(newsize);
|
| 1081 |
+
ret = afc_dispatch_packet(client, AFC_OP_FILE_SET_SIZE, sizeof(struct truncinfo), NULL, 0, &bytes);
|
| 1082 |
+
|
| 1083 |
+
if (ret != AFC_E_SUCCESS) {
|
| 1084 |
+
afc_unlock(client);
|
| 1085 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 1086 |
+
}
|
| 1087 |
+
/* Receive response */
|
| 1088 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 1089 |
+
|
| 1090 |
+
afc_unlock(client);
|
| 1091 |
+
|
| 1092 |
+
return ret;
|
| 1093 |
+
}
|
| 1094 |
+
|
| 1095 |
+
afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize)
|
| 1096 |
+
{
|
| 1097 |
+
if (!client || !path || !client->afc_packet || !client->parent)
|
| 1098 |
+
return AFC_E_INVALID_ARG;
|
| 1099 |
+
|
| 1100 |
+
uint32_t bytes = 0;
|
| 1101 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 1102 |
+
|
| 1103 |
+
afc_lock(client);
|
| 1104 |
+
|
| 1105 |
+
uint32_t data_len = 8 + (uint32_t)(strlen(path)+1);
|
| 1106 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 1107 |
+
afc_unlock(client);
|
| 1108 |
+
debug_info("Failed to realloc packet buffer");
|
| 1109 |
+
return AFC_E_NO_MEM;
|
| 1110 |
+
}
|
| 1111 |
+
|
| 1112 |
+
/* Send command */
|
| 1113 |
+
*(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(newsize);
|
| 1114 |
+
memcpy(AFC_PACKET_DATA_PTR + 8, path, data_len-8);
|
| 1115 |
+
ret = afc_dispatch_packet(client, AFC_OP_TRUNCATE, data_len, NULL, 0, &bytes);
|
| 1116 |
+
if (ret != AFC_E_SUCCESS) {
|
| 1117 |
+
afc_unlock(client);
|
| 1118 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 1119 |
+
}
|
| 1120 |
+
/* Receive response */
|
| 1121 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 1122 |
+
|
| 1123 |
+
afc_unlock(client);
|
| 1124 |
+
|
| 1125 |
+
return ret;
|
| 1126 |
+
}
|
| 1127 |
+
|
| 1128 |
+
afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname)
|
| 1129 |
+
{
|
| 1130 |
+
if (!client || !target || !linkname || !client->afc_packet || !client->parent)
|
| 1131 |
+
return AFC_E_INVALID_ARG;
|
| 1132 |
+
|
| 1133 |
+
uint32_t bytes = 0;
|
| 1134 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 1135 |
+
|
| 1136 |
+
size_t target_len = strlen(target);
|
| 1137 |
+
size_t link_len = strlen(linkname);
|
| 1138 |
+
|
| 1139 |
+
afc_lock(client);
|
| 1140 |
+
|
| 1141 |
+
uint32_t data_len = 8 + target_len + 1 + link_len + 1;
|
| 1142 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 1143 |
+
afc_unlock(client);
|
| 1144 |
+
debug_info("Failed to realloc packet buffer");
|
| 1145 |
+
return AFC_E_NO_MEM;
|
| 1146 |
+
}
|
| 1147 |
+
|
| 1148 |
+
debug_info("link type: %lld", htole64(linktype));
|
| 1149 |
+
debug_info("target: %s, length:%d", target, target_len);
|
| 1150 |
+
debug_info("linkname: %s, length:%d", linkname, link_len);
|
| 1151 |
+
|
| 1152 |
+
/* Send command */
|
| 1153 |
+
*(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(linktype);
|
| 1154 |
+
memcpy(AFC_PACKET_DATA_PTR + 8, target, target_len + 1);
|
| 1155 |
+
memcpy(AFC_PACKET_DATA_PTR + 8 + target_len + 1, linkname, link_len + 1);
|
| 1156 |
+
ret = afc_dispatch_packet(client, AFC_OP_MAKE_LINK, data_len, NULL, 0, &bytes);
|
| 1157 |
+
if (ret != AFC_E_SUCCESS) {
|
| 1158 |
+
afc_unlock(client);
|
| 1159 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 1160 |
+
}
|
| 1161 |
+
/* Receive response */
|
| 1162 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 1163 |
+
|
| 1164 |
+
afc_unlock(client);
|
| 1165 |
+
|
| 1166 |
+
return ret;
|
| 1167 |
+
}
|
| 1168 |
+
|
| 1169 |
+
afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime)
|
| 1170 |
+
{
|
| 1171 |
+
if (!client || !path || !client->afc_packet || !client->parent)
|
| 1172 |
+
return AFC_E_INVALID_ARG;
|
| 1173 |
+
|
| 1174 |
+
uint32_t bytes = 0;
|
| 1175 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 1176 |
+
|
| 1177 |
+
afc_lock(client);
|
| 1178 |
+
|
| 1179 |
+
uint32_t data_len = 8 + strlen(path) + 1;
|
| 1180 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 1181 |
+
afc_unlock(client);
|
| 1182 |
+
debug_info("Failed to realloc packet buffer");
|
| 1183 |
+
return AFC_E_NO_MEM;
|
| 1184 |
+
}
|
| 1185 |
+
|
| 1186 |
+
/* Send command */
|
| 1187 |
+
*(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(mtime);
|
| 1188 |
+
memcpy(AFC_PACKET_DATA_PTR + 8, path, data_len-8);
|
| 1189 |
+
ret = afc_dispatch_packet(client, AFC_OP_SET_FILE_MOD_TIME, data_len, NULL, 0, &bytes);
|
| 1190 |
+
if (ret != AFC_E_SUCCESS) {
|
| 1191 |
+
afc_unlock(client);
|
| 1192 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 1193 |
+
}
|
| 1194 |
+
/* Receive response */
|
| 1195 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 1196 |
+
|
| 1197 |
+
afc_unlock(client);
|
| 1198 |
+
|
| 1199 |
+
return ret;
|
| 1200 |
+
}
|
| 1201 |
+
|
| 1202 |
+
afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path)
|
| 1203 |
+
{
|
| 1204 |
+
uint32_t bytes = 0;
|
| 1205 |
+
afc_error_t ret = AFC_E_UNKNOWN_ERROR;
|
| 1206 |
+
|
| 1207 |
+
if (!client || !path || !client->afc_packet || !client->parent)
|
| 1208 |
+
return AFC_E_INVALID_ARG;
|
| 1209 |
+
|
| 1210 |
+
afc_lock(client);
|
| 1211 |
+
|
| 1212 |
+
uint32_t data_len = strlen(path) + 1;
|
| 1213 |
+
if (_afc_check_packet_buffer(client, data_len) < 0) {
|
| 1214 |
+
afc_unlock(client);
|
| 1215 |
+
debug_info("Failed to realloc packet buffer");
|
| 1216 |
+
return AFC_E_NO_MEM;
|
| 1217 |
+
}
|
| 1218 |
+
|
| 1219 |
+
/* Send command */
|
| 1220 |
+
memcpy(AFC_PACKET_DATA_PTR, path, data_len);
|
| 1221 |
+
ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH_AND_CONTENTS, data_len, NULL, 0, &bytes);
|
| 1222 |
+
if (ret != AFC_E_SUCCESS) {
|
| 1223 |
+
afc_unlock(client);
|
| 1224 |
+
return AFC_E_NOT_ENOUGH_DATA;
|
| 1225 |
+
}
|
| 1226 |
+
/* Receive response */
|
| 1227 |
+
ret = afc_receive_data(client, NULL, &bytes);
|
| 1228 |
+
|
| 1229 |
+
afc_unlock(client);
|
| 1230 |
+
|
| 1231 |
+
return ret;
|
| 1232 |
+
}
|
| 1233 |
+
|
| 1234 |
+
afc_error_t afc_dictionary_free(char **dictionary)
|
| 1235 |
+
{
|
| 1236 |
+
int i = 0;
|
| 1237 |
+
|
| 1238 |
+
if (!dictionary)
|
| 1239 |
+
return AFC_E_INVALID_ARG;
|
| 1240 |
+
|
| 1241 |
+
for (i = 0; dictionary[i]; i++) {
|
| 1242 |
+
free(dictionary[i]);
|
| 1243 |
+
}
|
| 1244 |
+
free(dictionary);
|
| 1245 |
+
|
| 1246 |
+
return AFC_E_SUCCESS;
|
| 1247 |
+
}
|
| 1248 |
+
|
| 1249 |
+
const char* afc_strerror(afc_error_t err)
|
| 1250 |
+
{
|
| 1251 |
+
switch (err) {
|
| 1252 |
+
case AFC_E_SUCCESS:
|
| 1253 |
+
return "Success";
|
| 1254 |
+
case AFC_E_UNKNOWN_ERROR:
|
| 1255 |
+
return "Unknown Error";
|
| 1256 |
+
case AFC_E_OP_HEADER_INVALID:
|
| 1257 |
+
return "Operation header invalid";
|
| 1258 |
+
case AFC_E_NO_RESOURCES:
|
| 1259 |
+
return "No resources";
|
| 1260 |
+
case AFC_E_READ_ERROR:
|
| 1261 |
+
return "Read error";
|
| 1262 |
+
case AFC_E_WRITE_ERROR:
|
| 1263 |
+
return "Write error";
|
| 1264 |
+
case AFC_E_UNKNOWN_PACKET_TYPE:
|
| 1265 |
+
return "Unknown packet type";
|
| 1266 |
+
case AFC_E_INVALID_ARG:
|
| 1267 |
+
return "Invalid argument";
|
| 1268 |
+
case AFC_E_OBJECT_NOT_FOUND:
|
| 1269 |
+
return "Not found";
|
| 1270 |
+
case AFC_E_OBJECT_IS_DIR:
|
| 1271 |
+
return "Object is a directory";
|
| 1272 |
+
case AFC_E_PERM_DENIED:
|
| 1273 |
+
return "Permission denied";
|
| 1274 |
+
case AFC_E_SERVICE_NOT_CONNECTED:
|
| 1275 |
+
return "Service not connected";
|
| 1276 |
+
case AFC_E_OP_TIMEOUT:
|
| 1277 |
+
return "Timeout";
|
| 1278 |
+
case AFC_E_TOO_MUCH_DATA:
|
| 1279 |
+
return "Too much data";
|
| 1280 |
+
case AFC_E_END_OF_DATA:
|
| 1281 |
+
return "End of data";
|
| 1282 |
+
case AFC_E_OP_NOT_SUPPORTED:
|
| 1283 |
+
return "Operation not supported";
|
| 1284 |
+
case AFC_E_OBJECT_EXISTS:
|
| 1285 |
+
return "Object exists";
|
| 1286 |
+
case AFC_E_OBJECT_BUSY:
|
| 1287 |
+
return "Object busy";
|
| 1288 |
+
case AFC_E_NO_SPACE_LEFT:
|
| 1289 |
+
return "No space left on device";
|
| 1290 |
+
case AFC_E_OP_WOULD_BLOCK:
|
| 1291 |
+
return "Operation would block";
|
| 1292 |
+
case AFC_E_IO_ERROR:
|
| 1293 |
+
return "I/O error";
|
| 1294 |
+
case AFC_E_OP_INTERRUPTED:
|
| 1295 |
+
return "Operation interrupted";
|
| 1296 |
+
case AFC_E_OP_IN_PROGRESS:
|
| 1297 |
+
return "Operation on progress";
|
| 1298 |
+
case AFC_E_INTERNAL_ERROR:
|
| 1299 |
+
return "Internal error";
|
| 1300 |
+
case AFC_E_MUX_ERROR:
|
| 1301 |
+
return "MUX error";
|
| 1302 |
+
case AFC_E_NO_MEM:
|
| 1303 |
+
return "Out of memory";
|
| 1304 |
+
case AFC_E_NOT_ENOUGH_DATA:
|
| 1305 |
+
return "Not enough data";
|
| 1306 |
+
case AFC_E_DIR_NOT_EMPTY:
|
| 1307 |
+
return "Directory not empty";
|
| 1308 |
+
case AFC_E_FORCE_SIGNED_TYPE:
|
| 1309 |
+
return "Force signed type";
|
| 1310 |
+
default:
|
| 1311 |
+
break;
|
| 1312 |
+
}
|
| 1313 |
+
return "Unknown Error";
|
| 1314 |
+
}
|
afc.h
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* afc.h
|
| 3 |
+
* Defines and structs and the like for the built-in AFC client
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2014 Martin Szulecki All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2008 Zach C. All Rights Reserved.
|
| 7 |
+
*
|
| 8 |
+
* This library is free software; you can redistribute it and/or
|
| 9 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 10 |
+
* License as published by the Free Software Foundation; either
|
| 11 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 12 |
+
*
|
| 13 |
+
* This library is distributed in the hope that it will be useful,
|
| 14 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 15 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 16 |
+
* Lesser General Public License for more details.
|
| 17 |
+
*
|
| 18 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 19 |
+
* License along with this library; if not, write to the Free Software
|
| 20 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 21 |
+
*/
|
| 22 |
+
|
| 23 |
+
#ifndef __AFC_H
|
| 24 |
+
#define __AFC_H
|
| 25 |
+
|
| 26 |
+
#include <stdint.h>
|
| 27 |
+
|
| 28 |
+
#include "libimobiledevice/afc.h"
|
| 29 |
+
#include "service.h"
|
| 30 |
+
#include "endianness.h"
|
| 31 |
+
#include <libimobiledevice-glue/thread.h>
|
| 32 |
+
|
| 33 |
+
#define AFC_MAGIC "CFA6LPAA"
|
| 34 |
+
#define AFC_MAGIC_LEN (8)
|
| 35 |
+
|
| 36 |
+
typedef struct {
|
| 37 |
+
char magic[AFC_MAGIC_LEN];
|
| 38 |
+
uint64_t entire_length, this_length, packet_num, operation;
|
| 39 |
+
} AFCPacket;
|
| 40 |
+
|
| 41 |
+
#define AFCPacket_to_LE(x) \
|
| 42 |
+
(x)->entire_length = htole64((x)->entire_length); \
|
| 43 |
+
(x)->this_length = htole64((x)->this_length); \
|
| 44 |
+
(x)->packet_num = htole64((x)->packet_num); \
|
| 45 |
+
(x)->operation = htole64((x)->operation);
|
| 46 |
+
|
| 47 |
+
#define AFCPacket_from_LE(x) \
|
| 48 |
+
(x)->entire_length = le64toh((x)->entire_length); \
|
| 49 |
+
(x)->this_length = le64toh((x)->this_length); \
|
| 50 |
+
(x)->packet_num = le64toh((x)->packet_num); \
|
| 51 |
+
(x)->operation = le64toh((x)->operation);
|
| 52 |
+
|
| 53 |
+
struct afc_client_private {
|
| 54 |
+
service_client_t parent;
|
| 55 |
+
AFCPacket *afc_packet;
|
| 56 |
+
uint32_t packet_extra;
|
| 57 |
+
mutex_t mutex;
|
| 58 |
+
int free_parent;
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
/* AFC Operations */
|
| 62 |
+
enum {
|
| 63 |
+
AFC_OP_INVALID = 0x00000000, /* Invalid */
|
| 64 |
+
AFC_OP_STATUS = 0x00000001, /* Status */
|
| 65 |
+
AFC_OP_DATA = 0x00000002, /* Data */
|
| 66 |
+
AFC_OP_READ_DIR = 0x00000003, /* ReadDir */
|
| 67 |
+
AFC_OP_READ_FILE = 0x00000004, /* ReadFile */
|
| 68 |
+
AFC_OP_WRITE_FILE = 0x00000005, /* WriteFile */
|
| 69 |
+
AFC_OP_WRITE_PART = 0x00000006, /* WritePart */
|
| 70 |
+
AFC_OP_TRUNCATE = 0x00000007, /* TruncateFile */
|
| 71 |
+
AFC_OP_REMOVE_PATH = 0x00000008, /* RemovePath */
|
| 72 |
+
AFC_OP_MAKE_DIR = 0x00000009, /* MakeDir */
|
| 73 |
+
AFC_OP_GET_FILE_INFO = 0x0000000A, /* GetFileInfo */
|
| 74 |
+
AFC_OP_GET_DEVINFO = 0x0000000B, /* GetDeviceInfo */
|
| 75 |
+
AFC_OP_WRITE_FILE_ATOM = 0x0000000C, /* WriteFileAtomic (tmp file+rename) */
|
| 76 |
+
AFC_OP_FILE_OPEN = 0x0000000D, /* FileRefOpen */
|
| 77 |
+
AFC_OP_FILE_OPEN_RES = 0x0000000E, /* FileRefOpenResult */
|
| 78 |
+
AFC_OP_FILE_READ = 0x0000000F, /* FileRefRead */
|
| 79 |
+
AFC_OP_FILE_WRITE = 0x00000010, /* FileRefWrite */
|
| 80 |
+
AFC_OP_FILE_SEEK = 0x00000011, /* FileRefSeek */
|
| 81 |
+
AFC_OP_FILE_TELL = 0x00000012, /* FileRefTell */
|
| 82 |
+
AFC_OP_FILE_TELL_RES = 0x00000013, /* FileRefTellResult */
|
| 83 |
+
AFC_OP_FILE_CLOSE = 0x00000014, /* FileRefClose */
|
| 84 |
+
AFC_OP_FILE_SET_SIZE = 0x00000015, /* FileRefSetFileSize (ftruncate) */
|
| 85 |
+
AFC_OP_GET_CON_INFO = 0x00000016, /* GetConnectionInfo */
|
| 86 |
+
AFC_OP_SET_CON_OPTIONS = 0x00000017, /* SetConnectionOptions */
|
| 87 |
+
AFC_OP_RENAME_PATH = 0x00000018, /* RenamePath */
|
| 88 |
+
AFC_OP_SET_FS_BS = 0x00000019, /* SetFSBlockSize (0x800000) */
|
| 89 |
+
AFC_OP_SET_SOCKET_BS = 0x0000001A, /* SetSocketBlockSize (0x800000) */
|
| 90 |
+
AFC_OP_FILE_LOCK = 0x0000001B, /* FileRefLock */
|
| 91 |
+
AFC_OP_MAKE_LINK = 0x0000001C, /* MakeLink */
|
| 92 |
+
AFC_OP_GET_FILE_HASH = 0x0000001D, /* GetFileHash */
|
| 93 |
+
AFC_OP_SET_FILE_MOD_TIME = 0x0000001E, /* SetModTime */
|
| 94 |
+
AFC_OP_GET_FILE_HASH_RANGE = 0x0000001F, /* GetFileHashWithRange */
|
| 95 |
+
/* iOS 6+ */
|
| 96 |
+
AFC_OP_FILE_SET_IMMUTABLE_HINT = 0x00000020, /* FileRefSetImmutableHint */
|
| 97 |
+
AFC_OP_GET_SIZE_OF_PATH_CONTENTS = 0x00000021, /* GetSizeOfPathContents */
|
| 98 |
+
AFC_OP_REMOVE_PATH_AND_CONTENTS = 0x00000022, /* RemovePathAndContents */
|
| 99 |
+
AFC_OP_DIR_OPEN = 0x00000023, /* DirectoryEnumeratorRefOpen */
|
| 100 |
+
AFC_OP_DIR_OPEN_RESULT = 0x00000024, /* DirectoryEnumeratorRefOpenResult */
|
| 101 |
+
AFC_OP_DIR_READ = 0x00000025, /* DirectoryEnumeratorRefRead */
|
| 102 |
+
AFC_OP_DIR_CLOSE = 0x00000026, /* DirectoryEnumeratorRefClose */
|
| 103 |
+
/* iOS 7+ */
|
| 104 |
+
AFC_OP_FILE_READ_OFFSET = 0x00000027, /* FileRefReadWithOffset */
|
| 105 |
+
AFC_OP_FILE_WRITE_OFFSET = 0x00000028 /* FileRefWriteWithOffset */
|
| 106 |
+
};
|
| 107 |
+
|
| 108 |
+
afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client);
|
| 109 |
+
|
| 110 |
+
#endif
|
afc.pxi
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cdef extern from "libimobiledevice/afc.h":
|
| 2 |
+
cdef struct afc_client_private:
|
| 3 |
+
pass
|
| 4 |
+
ctypedef afc_client_private *afc_client_t
|
| 5 |
+
ctypedef enum afc_error_t:
|
| 6 |
+
AFC_E_SUCCESS = 0
|
| 7 |
+
AFC_E_UNKNOWN_ERROR = 1
|
| 8 |
+
AFC_E_OP_HEADER_INVALID = 2
|
| 9 |
+
AFC_E_NO_RESOURCES = 3
|
| 10 |
+
AFC_E_READ_ERROR = 4
|
| 11 |
+
AFC_E_WRITE_ERROR = 5
|
| 12 |
+
AFC_E_UNKNOWN_PACKET_TYPE = 6
|
| 13 |
+
AFC_E_INVALID_ARG = 7
|
| 14 |
+
AFC_E_OBJECT_NOT_FOUND = 8
|
| 15 |
+
AFC_E_OBJECT_IS_DIR = 9
|
| 16 |
+
AFC_E_PERM_DENIED = 10
|
| 17 |
+
AFC_E_SERVICE_NOT_CONNECTED = 11
|
| 18 |
+
AFC_E_OP_TIMEOUT = 12
|
| 19 |
+
AFC_E_TOO_MUCH_DATA = 13
|
| 20 |
+
AFC_E_END_OF_DATA = 14
|
| 21 |
+
AFC_E_OP_NOT_SUPPORTED = 15
|
| 22 |
+
AFC_E_OBJECT_EXISTS = 16
|
| 23 |
+
AFC_E_OBJECT_BUSY = 17
|
| 24 |
+
AFC_E_NO_SPACE_LEFT = 18
|
| 25 |
+
AFC_E_OP_WOULD_BLOCK = 19
|
| 26 |
+
AFC_E_IO_ERROR = 20
|
| 27 |
+
AFC_E_OP_INTERRUPTED = 21
|
| 28 |
+
AFC_E_OP_IN_PROGRESS = 22
|
| 29 |
+
AFC_E_INTERNAL_ERROR = 23
|
| 30 |
+
AFC_E_MUX_ERROR = 30
|
| 31 |
+
AFC_E_NO_MEM = 31
|
| 32 |
+
AFC_E_NOT_ENOUGH_DATA = 32
|
| 33 |
+
AFC_E_DIR_NOT_EMPTY = 33
|
| 34 |
+
ctypedef enum afc_file_mode_t:
|
| 35 |
+
AFC_FOPEN_RDONLY = 0x00000001
|
| 36 |
+
AFC_FOPEN_RW = 0x00000002
|
| 37 |
+
AFC_FOPEN_WRONLY = 0x00000003
|
| 38 |
+
AFC_FOPEN_WR = 0x00000004
|
| 39 |
+
AFC_FOPEN_APPEND = 0x00000005
|
| 40 |
+
AFC_FOPEN_RDAPPEND = 0x00000006
|
| 41 |
+
ctypedef enum afc_link_type_t:
|
| 42 |
+
AFC_HARDLINK = 1
|
| 43 |
+
AFC_SYMLINK = 2
|
| 44 |
+
ctypedef enum afc_lock_op_t:
|
| 45 |
+
AFC_LOCK_SH = 1 | 4
|
| 46 |
+
AFC_LOCK_EX = 2 | 4
|
| 47 |
+
AFC_LOCK_UN = 8 | 4
|
| 48 |
+
|
| 49 |
+
afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, afc_client_t *client)
|
| 50 |
+
afc_error_t afc_client_free(afc_client_t client)
|
| 51 |
+
afc_error_t afc_get_device_info(afc_client_t client, char ***infos)
|
| 52 |
+
afc_error_t afc_read_directory(afc_client_t client, char *dir, char ***list)
|
| 53 |
+
afc_error_t afc_get_file_info(afc_client_t client, char *filename, char ***infolist)
|
| 54 |
+
afc_error_t afc_remove_path(afc_client_t client, char *path)
|
| 55 |
+
afc_error_t afc_remove_path_and_contents(afc_client_t client, char *path)
|
| 56 |
+
afc_error_t afc_rename_path(afc_client_t client, char *f, char *to)
|
| 57 |
+
afc_error_t afc_make_directory(afc_client_t client, char *dir)
|
| 58 |
+
afc_error_t afc_truncate(afc_client_t client, char *path, uint64_t newsize)
|
| 59 |
+
afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, char *target, char *linkname)
|
| 60 |
+
afc_error_t afc_set_file_time(afc_client_t client, char *path, uint64_t mtime)
|
| 61 |
+
|
| 62 |
+
afc_error_t afc_file_open(afc_client_t client, char *filename, afc_file_mode_t file_mode, uint64_t *handle)
|
| 63 |
+
afc_error_t afc_file_close(afc_client_t client, uint64_t handle)
|
| 64 |
+
afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation)
|
| 65 |
+
afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read)
|
| 66 |
+
afc_error_t afc_file_write(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_written)
|
| 67 |
+
afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence)
|
| 68 |
+
afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position)
|
| 69 |
+
afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize)
|
| 70 |
+
|
| 71 |
+
LOCK_SH = AFC_LOCK_SH
|
| 72 |
+
LOCK_EX = AFC_LOCK_EX
|
| 73 |
+
LOCK_UN = AFC_LOCK_UN
|
| 74 |
+
|
| 75 |
+
cdef class AfcError(BaseError):
|
| 76 |
+
def __init__(self, *args, **kwargs):
|
| 77 |
+
self._lookup_table = {
|
| 78 |
+
AFC_E_SUCCESS: "Success",
|
| 79 |
+
AFC_E_UNKNOWN_ERROR: "Unknown error",
|
| 80 |
+
AFC_E_OP_HEADER_INVALID: "OP header invalid",
|
| 81 |
+
AFC_E_NO_RESOURCES: "No resources",
|
| 82 |
+
AFC_E_READ_ERROR: "Read error",
|
| 83 |
+
AFC_E_WRITE_ERROR: "Write error",
|
| 84 |
+
AFC_E_UNKNOWN_PACKET_TYPE: "Unknown packet type",
|
| 85 |
+
AFC_E_INVALID_ARG: "Invalid argument",
|
| 86 |
+
AFC_E_OBJECT_NOT_FOUND: "Object not found",
|
| 87 |
+
AFC_E_OBJECT_IS_DIR: "Object is directory",
|
| 88 |
+
AFC_E_PERM_DENIED: "Permission denied",
|
| 89 |
+
AFC_E_SERVICE_NOT_CONNECTED: "Service not connected",
|
| 90 |
+
AFC_E_OP_TIMEOUT: "OP timeout",
|
| 91 |
+
AFC_E_TOO_MUCH_DATA: "Too much data",
|
| 92 |
+
AFC_E_END_OF_DATA: "End of data",
|
| 93 |
+
AFC_E_OP_NOT_SUPPORTED: "OP not supported",
|
| 94 |
+
AFC_E_OBJECT_EXISTS: "Object exists",
|
| 95 |
+
AFC_E_OBJECT_BUSY: "Object busy",
|
| 96 |
+
AFC_E_NO_SPACE_LEFT: "No space left",
|
| 97 |
+
AFC_E_OP_WOULD_BLOCK: "OP would block",
|
| 98 |
+
AFC_E_IO_ERROR: "IO error",
|
| 99 |
+
AFC_E_OP_INTERRUPTED: "OP interrupted",
|
| 100 |
+
AFC_E_OP_IN_PROGRESS: "OP in progress",
|
| 101 |
+
AFC_E_INTERNAL_ERROR: "Internal error",
|
| 102 |
+
AFC_E_MUX_ERROR: "MUX error",
|
| 103 |
+
AFC_E_NO_MEM: "No memory",
|
| 104 |
+
AFC_E_NOT_ENOUGH_DATA: "Not enough data",
|
| 105 |
+
AFC_E_DIR_NOT_EMPTY: "Directory not empty"
|
| 106 |
+
}
|
| 107 |
+
BaseError.__init__(self, *args, **kwargs)
|
| 108 |
+
|
| 109 |
+
# forward declaration of AfcClient
|
| 110 |
+
cdef class AfcClient(BaseService)
|
| 111 |
+
|
| 112 |
+
cdef class AfcFile(Base):
|
| 113 |
+
cdef uint64_t _c_handle
|
| 114 |
+
cdef AfcClient _client
|
| 115 |
+
cdef bytes _filename
|
| 116 |
+
|
| 117 |
+
def __init__(self, *args, **kwargs):
|
| 118 |
+
raise TypeError("AfcFile cannot be instantiated")
|
| 119 |
+
|
| 120 |
+
def __enter__(self):
|
| 121 |
+
return self
|
| 122 |
+
|
| 123 |
+
def __exit__(self, type, value, traceback):
|
| 124 |
+
self.close()
|
| 125 |
+
|
| 126 |
+
cpdef close(self):
|
| 127 |
+
self.handle_error(afc_file_close(self._client._c_client, self._c_handle))
|
| 128 |
+
|
| 129 |
+
cpdef lock(self, int operation):
|
| 130 |
+
self.handle_error(afc_file_lock(self._client._c_client, self._c_handle, <afc_lock_op_t>operation))
|
| 131 |
+
|
| 132 |
+
cpdef seek(self, int64_t offset, int whence):
|
| 133 |
+
self.handle_error(afc_file_seek(self._client._c_client, self._c_handle, offset, whence))
|
| 134 |
+
|
| 135 |
+
cpdef uint64_t tell(self):
|
| 136 |
+
cdef uint64_t position
|
| 137 |
+
self.handle_error(afc_file_tell(self._client._c_client, self._c_handle, &position))
|
| 138 |
+
return position
|
| 139 |
+
|
| 140 |
+
cpdef truncate(self, uint64_t newsize):
|
| 141 |
+
self.handle_error(afc_file_truncate(self._client._c_client, self._c_handle, newsize))
|
| 142 |
+
|
| 143 |
+
cpdef bytes read(self, uint32_t size):
|
| 144 |
+
cdef:
|
| 145 |
+
uint32_t bytes_read
|
| 146 |
+
char* c_data = <char *>malloc(size)
|
| 147 |
+
bytes result
|
| 148 |
+
try:
|
| 149 |
+
self.handle_error(afc_file_read(self._client._c_client, self._c_handle, c_data, size, &bytes_read))
|
| 150 |
+
result = c_data[:bytes_read]
|
| 151 |
+
return result
|
| 152 |
+
except BaseError, e:
|
| 153 |
+
raise
|
| 154 |
+
finally:
|
| 155 |
+
free(c_data)
|
| 156 |
+
|
| 157 |
+
cpdef uint32_t write(self, bytes data):
|
| 158 |
+
cdef:
|
| 159 |
+
uint32_t bytes_written
|
| 160 |
+
char* c_data = data
|
| 161 |
+
try:
|
| 162 |
+
self.handle_error(afc_file_write(self._client._c_client, self._c_handle, c_data, len(data), &bytes_written))
|
| 163 |
+
except BaseError, e:
|
| 164 |
+
raise
|
| 165 |
+
|
| 166 |
+
return bytes_written
|
| 167 |
+
|
| 168 |
+
cdef inline BaseError _error(self, int16_t ret):
|
| 169 |
+
return AfcError(ret)
|
| 170 |
+
|
| 171 |
+
cdef class AfcClient(BaseService):
|
| 172 |
+
__service_name__ = "com.apple.afc"
|
| 173 |
+
cdef afc_client_t _c_client
|
| 174 |
+
|
| 175 |
+
def __cinit__(self, iDevice device = None, LockdownServiceDescriptor descriptor = None, *args, **kwargs):
|
| 176 |
+
if (device is not None and descriptor is not None):
|
| 177 |
+
self.handle_error(afc_client_new(device._c_dev, descriptor._c_service_descriptor, &(self._c_client)))
|
| 178 |
+
|
| 179 |
+
def __dealloc__(self):
|
| 180 |
+
cdef afc_error_t err
|
| 181 |
+
if self._c_client is not NULL:
|
| 182 |
+
err = afc_client_free(self._c_client)
|
| 183 |
+
self.handle_error(err)
|
| 184 |
+
|
| 185 |
+
cdef BaseError _error(self, int16_t ret):
|
| 186 |
+
return AfcError(ret)
|
| 187 |
+
|
| 188 |
+
cpdef list get_device_info(self):
|
| 189 |
+
cdef:
|
| 190 |
+
afc_error_t err
|
| 191 |
+
char** infos = NULL
|
| 192 |
+
bytes info
|
| 193 |
+
int i = 0
|
| 194 |
+
list result = []
|
| 195 |
+
err = afc_get_device_info(self._c_client, &infos)
|
| 196 |
+
try:
|
| 197 |
+
self.handle_error(err)
|
| 198 |
+
except BaseError, e:
|
| 199 |
+
raise
|
| 200 |
+
finally:
|
| 201 |
+
if infos != NULL:
|
| 202 |
+
while infos[i]:
|
| 203 |
+
info = infos[i]
|
| 204 |
+
result.append(info)
|
| 205 |
+
free(infos[i])
|
| 206 |
+
i = i + 1
|
| 207 |
+
free(infos)
|
| 208 |
+
|
| 209 |
+
return result
|
| 210 |
+
|
| 211 |
+
cpdef list read_directory(self, bytes directory):
|
| 212 |
+
cdef:
|
| 213 |
+
afc_error_t err
|
| 214 |
+
char** dir_list = NULL
|
| 215 |
+
bytes f
|
| 216 |
+
int i = 0
|
| 217 |
+
list result = []
|
| 218 |
+
err = afc_read_directory(self._c_client, directory, &dir_list)
|
| 219 |
+
try:
|
| 220 |
+
self.handle_error(err)
|
| 221 |
+
except BaseError, e:
|
| 222 |
+
raise
|
| 223 |
+
finally:
|
| 224 |
+
if dir_list != NULL:
|
| 225 |
+
while dir_list[i]:
|
| 226 |
+
f = dir_list[i]
|
| 227 |
+
result.append(f)
|
| 228 |
+
free(dir_list[i])
|
| 229 |
+
i = i + 1
|
| 230 |
+
free(dir_list)
|
| 231 |
+
|
| 232 |
+
return result
|
| 233 |
+
|
| 234 |
+
cpdef AfcFile open(self, bytes filename, bytes mode=b'r'):
|
| 235 |
+
cdef:
|
| 236 |
+
afc_file_mode_t c_mode
|
| 237 |
+
uint64_t handle
|
| 238 |
+
AfcFile f
|
| 239 |
+
if mode == b'r':
|
| 240 |
+
c_mode = AFC_FOPEN_RDONLY
|
| 241 |
+
elif mode == b'r+':
|
| 242 |
+
c_mode = AFC_FOPEN_RW
|
| 243 |
+
elif mode == b'w':
|
| 244 |
+
c_mode = AFC_FOPEN_WRONLY
|
| 245 |
+
elif mode == b'w+':
|
| 246 |
+
c_mode = AFC_FOPEN_WR
|
| 247 |
+
elif mode == b'a':
|
| 248 |
+
c_mode = AFC_FOPEN_APPEND
|
| 249 |
+
elif mode == b'a+':
|
| 250 |
+
c_mode = AFC_FOPEN_RDAPPEND
|
| 251 |
+
else:
|
| 252 |
+
raise ValueError("mode string must be 'r', 'r+', 'w', 'w+', 'a', or 'a+'")
|
| 253 |
+
|
| 254 |
+
self.handle_error(afc_file_open(self._c_client, filename, c_mode, &handle))
|
| 255 |
+
f = AfcFile.__new__(AfcFile)
|
| 256 |
+
f._c_handle = handle
|
| 257 |
+
f._client = self
|
| 258 |
+
f._filename = filename
|
| 259 |
+
|
| 260 |
+
return f
|
| 261 |
+
|
| 262 |
+
cpdef list get_file_info(self, bytes path):
|
| 263 |
+
cdef:
|
| 264 |
+
list result = []
|
| 265 |
+
char** c_result = NULL
|
| 266 |
+
int i = 0
|
| 267 |
+
bytes info
|
| 268 |
+
try:
|
| 269 |
+
self.handle_error(afc_get_file_info(self._c_client, path, &c_result))
|
| 270 |
+
except BaseError, e:
|
| 271 |
+
raise
|
| 272 |
+
finally:
|
| 273 |
+
if c_result != NULL:
|
| 274 |
+
while c_result[i]:
|
| 275 |
+
info = c_result[i]
|
| 276 |
+
result.append(info)
|
| 277 |
+
free(c_result[i])
|
| 278 |
+
i = i + 1
|
| 279 |
+
free(c_result)
|
| 280 |
+
|
| 281 |
+
return result
|
| 282 |
+
|
| 283 |
+
cpdef remove_path(self, bytes path):
|
| 284 |
+
self.handle_error(afc_remove_path(self._c_client, path))
|
| 285 |
+
|
| 286 |
+
cpdef remove_path_and_contents(self, bytes path):
|
| 287 |
+
self.handle_error(afc_remove_path_and_contents(self._c_client, path))
|
| 288 |
+
|
| 289 |
+
cpdef rename_path(self, bytes f, bytes t):
|
| 290 |
+
self.handle_error(afc_rename_path(self._c_client, f, t))
|
| 291 |
+
|
| 292 |
+
cpdef make_directory(self, bytes d):
|
| 293 |
+
self.handle_error(afc_make_directory(self._c_client, d))
|
| 294 |
+
|
| 295 |
+
cpdef truncate(self, bytes path, uint64_t newsize):
|
| 296 |
+
self.handle_error(afc_truncate(self._c_client, path, newsize))
|
| 297 |
+
|
| 298 |
+
cpdef link(self, bytes source, bytes link_name):
|
| 299 |
+
self.handle_error(afc_make_link(self._c_client, AFC_HARDLINK, source, link_name))
|
| 300 |
+
|
| 301 |
+
cpdef symlink(self, bytes source, bytes link_name):
|
| 302 |
+
self.handle_error(afc_make_link(self._c_client, AFC_SYMLINK, source, link_name))
|
| 303 |
+
|
| 304 |
+
cpdef set_file_time(self, bytes path, uint64_t mtime):
|
| 305 |
+
self.handle_error(afc_set_file_time(self._c_client, path, mtime))
|
| 306 |
+
|
| 307 |
+
cdef class Afc2Client(AfcClient):
|
| 308 |
+
__service_name__ = "com.apple.afc2"
|
| 309 |
+
|
| 310 |
+
cpdef AfcFile open(self, bytes filename, bytes mode=b'r'):
|
| 311 |
+
cdef:
|
| 312 |
+
afc_file_mode_t c_mode
|
| 313 |
+
uint64_t handle
|
| 314 |
+
AfcFile f
|
| 315 |
+
if mode == b'r':
|
| 316 |
+
c_mode = AFC_FOPEN_RDONLY
|
| 317 |
+
elif mode == b'r+':
|
| 318 |
+
c_mode = AFC_FOPEN_RW
|
| 319 |
+
elif mode == b'w':
|
| 320 |
+
c_mode = AFC_FOPEN_WRONLY
|
| 321 |
+
elif mode == b'w+':
|
| 322 |
+
c_mode = AFC_FOPEN_WR
|
| 323 |
+
elif mode == b'a':
|
| 324 |
+
c_mode = AFC_FOPEN_APPEND
|
| 325 |
+
elif mode == b'a+':
|
| 326 |
+
c_mode = AFC_FOPEN_RDAPPEND
|
| 327 |
+
else:
|
| 328 |
+
raise ValueError("mode string must be 'r', 'r+', 'w', 'w+', 'a', or 'a+'")
|
| 329 |
+
|
| 330 |
+
self.handle_error(afc_file_open(self._c_client, filename, c_mode, &handle))
|
| 331 |
+
f = AfcFile.__new__(AfcFile)
|
| 332 |
+
f._c_handle = handle
|
| 333 |
+
f._client = <AfcClient>self
|
| 334 |
+
f._filename = filename
|
| 335 |
+
|
| 336 |
+
return f
|
| 337 |
+
|
afcclient.c
ADDED
|
@@ -0,0 +1,1630 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* afcclient.c
|
| 3 |
+
* Utility to interact with AFC/HoustArrest service on the device
|
| 4 |
+
*
|
| 5 |
+
* Inspired by https://github.com/emonti/afcclient
|
| 6 |
+
* But entirely rewritten from scratch.
|
| 7 |
+
*
|
| 8 |
+
* Copyright (c) 2023 Nikias Bassen, All Rights Reserved.
|
| 9 |
+
*
|
| 10 |
+
* This library is free software; you can redistribute it and/or
|
| 11 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 12 |
+
* License as published by the Free Software Foundation; either
|
| 13 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 14 |
+
*
|
| 15 |
+
* This library is distributed in the hope that it will be useful,
|
| 16 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 17 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 18 |
+
* Lesser General Public License for more details.
|
| 19 |
+
*
|
| 20 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 21 |
+
* License along with this library; if not, write to the Free Software
|
| 22 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 23 |
+
*/
|
| 24 |
+
|
| 25 |
+
#ifdef HAVE_CONFIG_H
|
| 26 |
+
#include <config.h>
|
| 27 |
+
#endif
|
| 28 |
+
|
| 29 |
+
#define TOOL_NAME "afcclient"
|
| 30 |
+
|
| 31 |
+
#include <stdio.h>
|
| 32 |
+
#include <string.h>
|
| 33 |
+
#include <errno.h>
|
| 34 |
+
#include <stdlib.h>
|
| 35 |
+
#include <getopt.h>
|
| 36 |
+
#include <signal.h>
|
| 37 |
+
#include <ctype.h>
|
| 38 |
+
#include <unistd.h>
|
| 39 |
+
#include <dirent.h>
|
| 40 |
+
#include <time.h>
|
| 41 |
+
#include <sys/stat.h>
|
| 42 |
+
|
| 43 |
+
#ifdef _WIN32
|
| 44 |
+
#include <windows.h>
|
| 45 |
+
#include <sys/time.h>
|
| 46 |
+
#include <conio.h>
|
| 47 |
+
#define sleep(x) Sleep(x*1000)
|
| 48 |
+
#define S_IFMT 0170000 /* [XSI] type of file mask */
|
| 49 |
+
#define S_IFIFO 0010000 /* [XSI] named pipe (fifo) */
|
| 50 |
+
#define S_IFCHR 0020000 /* [XSI] character special */
|
| 51 |
+
#define S_IFBLK 0060000 /* [XSI] block special */
|
| 52 |
+
#define S_IFLNK 0120000 /* [XSI] symbolic link */
|
| 53 |
+
#define S_IFSOCK 0140000 /* [XSI] socket */
|
| 54 |
+
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) /* block special */
|
| 55 |
+
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) /* char special */
|
| 56 |
+
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) /* fifo or socket */
|
| 57 |
+
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* symbolic link */
|
| 58 |
+
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* socket */
|
| 59 |
+
#else
|
| 60 |
+
#include <sys/time.h>
|
| 61 |
+
#include <termios.h>
|
| 62 |
+
#endif
|
| 63 |
+
|
| 64 |
+
#ifdef HAVE_READLINE
|
| 65 |
+
#include <readline/readline.h>
|
| 66 |
+
#include <readline/history.h>
|
| 67 |
+
#endif
|
| 68 |
+
|
| 69 |
+
#include <libimobiledevice/libimobiledevice.h>
|
| 70 |
+
#include <libimobiledevice/lockdown.h>
|
| 71 |
+
#include <libimobiledevice/house_arrest.h>
|
| 72 |
+
#include <libimobiledevice/afc.h>
|
| 73 |
+
#include <plist/plist.h>
|
| 74 |
+
|
| 75 |
+
#include <libimobiledevice-glue/termcolors.h>
|
| 76 |
+
#include <libimobiledevice-glue/utils.h>
|
| 77 |
+
|
| 78 |
+
#undef st_mtime
|
| 79 |
+
#undef st_birthtime
|
| 80 |
+
struct afc_file_stat {
|
| 81 |
+
uint16_t st_mode;
|
| 82 |
+
uint16_t st_nlink;
|
| 83 |
+
uint64_t st_size;
|
| 84 |
+
uint64_t st_mtime;
|
| 85 |
+
uint64_t st_birthtime;
|
| 86 |
+
uint32_t st_blocks;
|
| 87 |
+
};
|
| 88 |
+
|
| 89 |
+
static char* udid = NULL;
|
| 90 |
+
static int connected = 0;
|
| 91 |
+
static int use_network = 0;
|
| 92 |
+
static idevice_subscription_context_t context = NULL;
|
| 93 |
+
static char* curdir = NULL;
|
| 94 |
+
static size_t curdir_len = 0;
|
| 95 |
+
|
| 96 |
+
static int file_exists(const char* path)
|
| 97 |
+
{
|
| 98 |
+
struct stat tst;
|
| 99 |
+
#ifdef _WIN32
|
| 100 |
+
return (stat(path, &tst) == 0);
|
| 101 |
+
#else
|
| 102 |
+
return (lstat(path, &tst) == 0);
|
| 103 |
+
#endif
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
static int is_directory(const char* path)
|
| 107 |
+
{
|
| 108 |
+
struct stat tst;
|
| 109 |
+
#ifdef _WIN32
|
| 110 |
+
return (stat(path, &tst) == 0) && S_ISDIR(tst.st_mode);
|
| 111 |
+
#else
|
| 112 |
+
return (lstat(path, &tst) == 0) && S_ISDIR(tst.st_mode);
|
| 113 |
+
#endif
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
static void print_usage(int argc, char **argv, int is_error)
|
| 117 |
+
{
|
| 118 |
+
char *name = strrchr(argv[0], '/');
|
| 119 |
+
fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
|
| 120 |
+
fprintf(is_error ? stderr : stdout,
|
| 121 |
+
"\n"
|
| 122 |
+
"Interact with AFC/HouseArrest service on a connected device.\n"
|
| 123 |
+
"\n"
|
| 124 |
+
"OPTIONS:\n"
|
| 125 |
+
" -u, --udid UDID target specific device by UDID\n"
|
| 126 |
+
" -n, --network connect to network device (not recommended!)\n"
|
| 127 |
+
" --container <appid> Access container of given app\n"
|
| 128 |
+
" --documents <appid> Access Documents directory of given app\n"
|
| 129 |
+
" -h, --help prints usage information\n" \
|
| 130 |
+
" -d, --debug enable communication debugging\n" \
|
| 131 |
+
" -v, --version prints version information\n" \
|
| 132 |
+
"\n"
|
| 133 |
+
);
|
| 134 |
+
fprintf(is_error ? stderr : stdout,
|
| 135 |
+
"\n" \
|
| 136 |
+
"Homepage: <" PACKAGE_URL ">\n"
|
| 137 |
+
"Bug Reports: <" PACKAGE_BUGREPORT ">\n"
|
| 138 |
+
);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
#ifndef HAVE_READLINE
|
| 142 |
+
#ifdef _WIN32
|
| 143 |
+
#define BS_CC '\b'
|
| 144 |
+
#else
|
| 145 |
+
#define BS_CC 0x7f
|
| 146 |
+
#define getch getchar
|
| 147 |
+
#endif
|
| 148 |
+
static void get_input(char *buf, int maxlen)
|
| 149 |
+
{
|
| 150 |
+
int len = 0;
|
| 151 |
+
int c;
|
| 152 |
+
|
| 153 |
+
while ((c = getch())) {
|
| 154 |
+
if ((c == '\r') || (c == '\n')) {
|
| 155 |
+
break;
|
| 156 |
+
}
|
| 157 |
+
if (isprint(c)) {
|
| 158 |
+
if (len < maxlen-1)
|
| 159 |
+
buf[len++] = c;
|
| 160 |
+
} else if (c == BS_CC) {
|
| 161 |
+
if (len > 0) {
|
| 162 |
+
fputs("\b \b", stdout);
|
| 163 |
+
len--;
|
| 164 |
+
}
|
| 165 |
+
}
|
| 166 |
+
}
|
| 167 |
+
buf[len] = 0;
|
| 168 |
+
}
|
| 169 |
+
#endif
|
| 170 |
+
|
| 171 |
+
#define OPT_DOCUMENTS 1
|
| 172 |
+
#define OPT_CONTAINER 2
|
| 173 |
+
|
| 174 |
+
int stop_requested = 0;
|
| 175 |
+
|
| 176 |
+
static void handle_signal(int sig)
|
| 177 |
+
{
|
| 178 |
+
stop_requested++;
|
| 179 |
+
#ifdef _WIN32
|
| 180 |
+
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
| 181 |
+
#else
|
| 182 |
+
kill(getpid(), SIGINT);
|
| 183 |
+
#endif
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
static void handle_help(afc_client_t afc, int argc, char** argv)
|
| 187 |
+
{
|
| 188 |
+
printf("Available commands:\n");
|
| 189 |
+
printf("help - print list of available commands\n");
|
| 190 |
+
printf("devinfo - print device information\n");
|
| 191 |
+
printf("info PATH - print file attributes of file at PATH\n");
|
| 192 |
+
printf("ls [-l] PATH - print directory contents of PATH\n");
|
| 193 |
+
printf("mv OLD NEW - rename file OLD to NEW\n");
|
| 194 |
+
printf("mkdir PATH - create directory at PATH\n");
|
| 195 |
+
printf("ln [-s] FILE [LINK] - create a (symbolic) link to file named LINKNAME\n");
|
| 196 |
+
printf(" NOTE: This feature has been disabled in newer versions of iOS.\n");
|
| 197 |
+
printf("rm PATH - remove item at PATH\n");
|
| 198 |
+
printf("get [-rf] PATH [LOCALPATH] - transfer file at PATH from device to LOCALPATH\n");
|
| 199 |
+
printf("put [-rf] LOCALPATH [PATH] - transfer local file at LOCALPATH to device at PATH\n");
|
| 200 |
+
printf("\n");
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
static const char* path_get_basename(const char* path)
|
| 204 |
+
{
|
| 205 |
+
const char *p = strrchr(path, '/');
|
| 206 |
+
return p ? p + 1 : path;
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
|
| 210 |
+
{
|
| 211 |
+
/* Perform the carry for the later subtraction by updating y. */
|
| 212 |
+
if (x->tv_usec < y->tv_usec) {
|
| 213 |
+
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
|
| 214 |
+
y->tv_usec -= 1000000 * nsec;
|
| 215 |
+
y->tv_sec += nsec;
|
| 216 |
+
}
|
| 217 |
+
if (x->tv_usec - y->tv_usec > 1000000) {
|
| 218 |
+
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
|
| 219 |
+
y->tv_usec += 1000000 * nsec;
|
| 220 |
+
y->tv_sec -= nsec;
|
| 221 |
+
}
|
| 222 |
+
/* Compute the time remaining to wait.
|
| 223 |
+
tv_usec is certainly positive. */
|
| 224 |
+
result->tv_sec = x->tv_sec - y->tv_sec;
|
| 225 |
+
result->tv_usec = x->tv_usec - y->tv_usec;
|
| 226 |
+
/* Return 1 if result is negative. */
|
| 227 |
+
return x->tv_sec < y->tv_sec;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
struct str_item {
|
| 231 |
+
size_t len;
|
| 232 |
+
char* str;
|
| 233 |
+
};
|
| 234 |
+
|
| 235 |
+
static char* get_absolute_path(const char *path)
|
| 236 |
+
{
|
| 237 |
+
if (*path == '/') {
|
| 238 |
+
return strdup(path);
|
| 239 |
+
} else {
|
| 240 |
+
size_t len = curdir_len + 1 + strlen(path) + 1;
|
| 241 |
+
char* result = (char*)malloc(len);
|
| 242 |
+
if (!strcmp(curdir, "/")) {
|
| 243 |
+
snprintf(result, len, "/%s", path);
|
| 244 |
+
} else {
|
| 245 |
+
snprintf(result, len, "%s/%s", curdir, path);
|
| 246 |
+
}
|
| 247 |
+
return result;
|
| 248 |
+
}
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
static char* get_realpath(const char* path)
|
| 252 |
+
{
|
| 253 |
+
if (!path) return NULL;
|
| 254 |
+
|
| 255 |
+
int is_absolute = 0;
|
| 256 |
+
if (*path == '/') {
|
| 257 |
+
is_absolute = 1;
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
const char* p = path;
|
| 261 |
+
if (is_absolute) {
|
| 262 |
+
while (*p == '/') p++;
|
| 263 |
+
}
|
| 264 |
+
if (*p == '\0') {
|
| 265 |
+
return strdup("/");
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
int c_count = 1;
|
| 269 |
+
const char* start = p;
|
| 270 |
+
const char* end = p;
|
| 271 |
+
struct str_item* comps = NULL;
|
| 272 |
+
|
| 273 |
+
while (*p) {
|
| 274 |
+
if (*p == '/') {
|
| 275 |
+
p++;
|
| 276 |
+
end = p-1;
|
| 277 |
+
while (*p == '/') p++;
|
| 278 |
+
if (*p == '\0') break;
|
| 279 |
+
struct str_item* newcomps = (struct str_item*)realloc(comps, sizeof(struct str_item)*c_count);
|
| 280 |
+
if (!newcomps) {
|
| 281 |
+
free(comps);
|
| 282 |
+
printf("%s: out of memory?!\n", __func__);
|
| 283 |
+
return NULL;
|
| 284 |
+
}
|
| 285 |
+
comps = newcomps;
|
| 286 |
+
char *comp = (char*)malloc(end-start+1);
|
| 287 |
+
strncpy(comp, start, end-start);
|
| 288 |
+
comp[end-start] = '\0';
|
| 289 |
+
comps[c_count-1].len = end-start;
|
| 290 |
+
comps[c_count-1].str = comp;
|
| 291 |
+
c_count++;
|
| 292 |
+
start = p;
|
| 293 |
+
end = p;
|
| 294 |
+
}
|
| 295 |
+
p++;
|
| 296 |
+
}
|
| 297 |
+
if (p > start) {
|
| 298 |
+
if (start == end) {
|
| 299 |
+
end = p;
|
| 300 |
+
}
|
| 301 |
+
struct str_item* newcomps = (struct str_item*)realloc(comps, sizeof(struct str_item)*c_count);
|
| 302 |
+
if (!newcomps) {
|
| 303 |
+
free(comps);
|
| 304 |
+
printf("%s: out of memory?!\n", __func__);
|
| 305 |
+
return NULL;
|
| 306 |
+
}
|
| 307 |
+
comps = newcomps;
|
| 308 |
+
char *comp = (char*)malloc(end-start+1);
|
| 309 |
+
strncpy(comp, start, end-start);
|
| 310 |
+
comp[end-start] = '\0';
|
| 311 |
+
comps[c_count-1].len = end-start;
|
| 312 |
+
comps[c_count-1].str = comp;
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
struct str_item* comps_final = (struct str_item*)malloc(sizeof(struct str_item)*(c_count+1));
|
| 316 |
+
int o = 1;
|
| 317 |
+
if (is_absolute) {
|
| 318 |
+
comps_final[0].len = 1;
|
| 319 |
+
comps_final[0].str = (char*)"/";
|
| 320 |
+
} else {
|
| 321 |
+
comps_final[0].len = curdir_len;
|
| 322 |
+
comps_final[0].str = curdir;
|
| 323 |
+
}
|
| 324 |
+
size_t o_len = comps_final[0].len;
|
| 325 |
+
|
| 326 |
+
for (int i = 0; i < c_count; i++) {
|
| 327 |
+
if (!strcmp(comps[i].str, "..")) {
|
| 328 |
+
o--;
|
| 329 |
+
continue;
|
| 330 |
+
} else if (!strcmp(comps[i].str, ".")) {
|
| 331 |
+
continue;
|
| 332 |
+
}
|
| 333 |
+
o_len += comps[i].len;
|
| 334 |
+
comps_final[o].str = comps[i].str;
|
| 335 |
+
comps_final[o].len = comps[i].len;
|
| 336 |
+
o++;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
o_len += o;
|
| 340 |
+
char* result = (char*)malloc(o_len);
|
| 341 |
+
char* presult = result;
|
| 342 |
+
for (int i = 0; i < o; i++) {
|
| 343 |
+
if (i > 0 && strcmp(comps_final[i-1].str, "/") != 0) {
|
| 344 |
+
*presult = '/';
|
| 345 |
+
presult++;
|
| 346 |
+
}
|
| 347 |
+
strncpy(presult, comps_final[i].str, comps_final[i].len);
|
| 348 |
+
presult+=comps_final[i].len;
|
| 349 |
+
*presult = '\0';
|
| 350 |
+
}
|
| 351 |
+
if (presult == result) {
|
| 352 |
+
*presult = '/';
|
| 353 |
+
presult++;
|
| 354 |
+
*presult = 0;
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
for (int i = 0; i < c_count; i++) {
|
| 358 |
+
free(comps[i].str);
|
| 359 |
+
}
|
| 360 |
+
free(comps);
|
| 361 |
+
free(comps_final);
|
| 362 |
+
|
| 363 |
+
return result;
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
static void handle_devinfo(afc_client_t afc, int argc, char** argv)
|
| 367 |
+
{
|
| 368 |
+
plist_t info = NULL;
|
| 369 |
+
afc_error_t err = afc_get_device_info_plist(afc, &info);
|
| 370 |
+
if (err == AFC_E_SUCCESS && info) {
|
| 371 |
+
if (argc > 0 && !strcmp(argv[0], "--plain")) {
|
| 372 |
+
plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE);
|
| 373 |
+
} else {
|
| 374 |
+
plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE);
|
| 375 |
+
}
|
| 376 |
+
} else {
|
| 377 |
+
printf("Error: Failed to get device info: %s (%d)\n", afc_strerror(err), err);
|
| 378 |
+
}
|
| 379 |
+
plist_free(info);
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
static int get_file_info_stat(afc_client_t afc, const char* path, struct afc_file_stat *stbuf)
|
| 383 |
+
{
|
| 384 |
+
plist_t info = NULL;
|
| 385 |
+
afc_error_t ret = afc_get_file_info_plist(afc, path, &info);
|
| 386 |
+
memset(stbuf, 0, sizeof(struct afc_file_stat));
|
| 387 |
+
if (ret != AFC_E_SUCCESS) {
|
| 388 |
+
return -1;
|
| 389 |
+
} else if (!info) {
|
| 390 |
+
return -1;
|
| 391 |
+
}
|
| 392 |
+
stbuf->st_size = plist_dict_get_uint(info, "st_size");
|
| 393 |
+
stbuf->st_blocks = plist_dict_get_uint(info, "st_blocks");
|
| 394 |
+
const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
|
| 395 |
+
if (s_ifmt) {
|
| 396 |
+
if (!strcmp(s_ifmt, "S_IFREG")) {
|
| 397 |
+
stbuf->st_mode = S_IFREG;
|
| 398 |
+
} else if (!strcmp(s_ifmt, "S_IFDIR")) {
|
| 399 |
+
stbuf->st_mode = S_IFDIR;
|
| 400 |
+
} else if (!strcmp(s_ifmt, "S_IFLNK")) {
|
| 401 |
+
stbuf->st_mode = S_IFLNK;
|
| 402 |
+
} else if (!strcmp(s_ifmt, "S_IFBLK")) {
|
| 403 |
+
stbuf->st_mode = S_IFBLK;
|
| 404 |
+
} else if (!strcmp(s_ifmt, "S_IFCHR")) {
|
| 405 |
+
stbuf->st_mode = S_IFCHR;
|
| 406 |
+
} else if (!strcmp(s_ifmt, "S_IFIFO")) {
|
| 407 |
+
stbuf->st_mode = S_IFIFO;
|
| 408 |
+
} else if (!strcmp(s_ifmt, "S_IFSOCK")) {
|
| 409 |
+
stbuf->st_mode = S_IFSOCK;
|
| 410 |
+
}
|
| 411 |
+
}
|
| 412 |
+
stbuf->st_nlink = plist_dict_get_uint(info, "st_nlink");
|
| 413 |
+
stbuf->st_mtime = (time_t)(plist_dict_get_uint(info, "st_mtime") / 1000000000);
|
| 414 |
+
/* available on iOS 7+ */
|
| 415 |
+
stbuf->st_birthtime = (time_t)(plist_dict_get_uint(info, "st_birthtime") / 1000000000);
|
| 416 |
+
plist_free(info);
|
| 417 |
+
return 0;
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
static void handle_file_info(afc_client_t afc, int argc, char** argv)
|
| 421 |
+
{
|
| 422 |
+
if (argc < 1) {
|
| 423 |
+
printf("Error: Missing PATH.\n");
|
| 424 |
+
return;
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
plist_t info = NULL;
|
| 428 |
+
char* abspath = get_absolute_path(argv[0]);
|
| 429 |
+
if (!abspath) {
|
| 430 |
+
printf("Error: Invalid argument\n");
|
| 431 |
+
return;
|
| 432 |
+
}
|
| 433 |
+
afc_error_t err = afc_get_file_info_plist(afc, abspath, &info);
|
| 434 |
+
if (err == AFC_E_SUCCESS && info) {
|
| 435 |
+
if (argc > 1 && !strcmp(argv[1], "--plain")) {
|
| 436 |
+
plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE);
|
| 437 |
+
} else {
|
| 438 |
+
plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE);
|
| 439 |
+
}
|
| 440 |
+
} else {
|
| 441 |
+
printf("Error: Failed to get file info for %s: %s (%d)\n", argv[0], afc_strerror(err), err);
|
| 442 |
+
}
|
| 443 |
+
plist_free(info);
|
| 444 |
+
free(abspath);
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
static void print_file_info(afc_client_t afc, const char* path, int list_verbose)
|
| 448 |
+
{
|
| 449 |
+
struct afc_file_stat st;
|
| 450 |
+
get_file_info_stat(afc, path, &st);
|
| 451 |
+
if (list_verbose) {
|
| 452 |
+
char timebuf[64];
|
| 453 |
+
time_t t = st.st_mtime;
|
| 454 |
+
if (S_ISDIR(st.st_mode)) {
|
| 455 |
+
printf("drwxr-xr-x");
|
| 456 |
+
} else if (S_ISLNK(st.st_mode)) {
|
| 457 |
+
printf("lrwxrwxrwx");
|
| 458 |
+
} else {
|
| 459 |
+
if (S_ISFIFO(st.st_mode)) {
|
| 460 |
+
printf("f");
|
| 461 |
+
} else if (S_ISBLK(st.st_mode)) {
|
| 462 |
+
printf("b");
|
| 463 |
+
} else if (S_ISCHR(st.st_mode)) {
|
| 464 |
+
printf("c");
|
| 465 |
+
} else if (S_ISSOCK(st.st_mode)) {
|
| 466 |
+
printf("s");
|
| 467 |
+
} else {
|
| 468 |
+
printf("-");
|
| 469 |
+
}
|
| 470 |
+
printf("rw-r--r--");
|
| 471 |
+
}
|
| 472 |
+
printf(" ");
|
| 473 |
+
printf("%4d", st.st_nlink);
|
| 474 |
+
printf(" ");
|
| 475 |
+
printf("mobile");
|
| 476 |
+
printf(" ");
|
| 477 |
+
printf("mobile");
|
| 478 |
+
printf(" ");
|
| 479 |
+
printf("%10lld", (long long)st.st_size);
|
| 480 |
+
printf(" ");
|
| 481 |
+
#ifdef _WIN32
|
| 482 |
+
strftime(timebuf, 64, "%d %b %Y %H:%M:%S", localtime(&t));
|
| 483 |
+
#else
|
| 484 |
+
strftime(timebuf, 64, "%d %h %Y %H:%M:%S", localtime(&t));
|
| 485 |
+
#endif
|
| 486 |
+
printf("%s", timebuf);
|
| 487 |
+
printf(" ");
|
| 488 |
+
}
|
| 489 |
+
if (S_ISDIR(st.st_mode)) {
|
| 490 |
+
cprintf(FG_CYAN);
|
| 491 |
+
} else if (S_ISLNK(st.st_mode)) {
|
| 492 |
+
cprintf(FG_MAGENTA);
|
| 493 |
+
} else if (S_ISREG(st.st_mode)) {
|
| 494 |
+
cprintf(FG_DEFAULT);
|
| 495 |
+
} else {
|
| 496 |
+
cprintf(FG_YELLOW);
|
| 497 |
+
}
|
| 498 |
+
cprintf("%s" COLOR_RESET "\n", path_get_basename(path));
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
static void handle_list(afc_client_t afc, int argc, char** argv)
|
| 502 |
+
{
|
| 503 |
+
const char* path = NULL;
|
| 504 |
+
int list_verbose = 0;
|
| 505 |
+
if (argc < 1) {
|
| 506 |
+
path = curdir;
|
| 507 |
+
} else {
|
| 508 |
+
if (!strcmp(argv[0], "-l")) {
|
| 509 |
+
list_verbose = 1;
|
| 510 |
+
if (argc == 2) {
|
| 511 |
+
path = argv[1];
|
| 512 |
+
} else {
|
| 513 |
+
path = curdir;
|
| 514 |
+
}
|
| 515 |
+
} else {
|
| 516 |
+
path = argv[0];
|
| 517 |
+
}
|
| 518 |
+
}
|
| 519 |
+
char* abspath = get_absolute_path(path);
|
| 520 |
+
if (!abspath) {
|
| 521 |
+
printf("Error: Invalid argument\n");
|
| 522 |
+
return;
|
| 523 |
+
}
|
| 524 |
+
int abspath_is_root = strcmp(abspath, "/") == 0;
|
| 525 |
+
size_t abspath_len = (abspath_is_root) ? 0 : strlen(abspath);
|
| 526 |
+
char** entries = NULL;
|
| 527 |
+
afc_error_t err = afc_read_directory(afc, abspath, &entries);
|
| 528 |
+
if (err == AFC_E_READ_ERROR) {
|
| 529 |
+
print_file_info(afc, abspath, list_verbose);
|
| 530 |
+
return;
|
| 531 |
+
} else if (err != AFC_E_SUCCESS) {
|
| 532 |
+
printf("Error: Failed to list '%s': %s (%d)\n", path, afc_strerror(err), err);
|
| 533 |
+
free(abspath);
|
| 534 |
+
return;
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
char** p = entries;
|
| 538 |
+
while (p && *p) {
|
| 539 |
+
if (strcmp(".", *p) == 0 || strcmp("..", *p) == 0) {
|
| 540 |
+
p++;
|
| 541 |
+
continue;
|
| 542 |
+
}
|
| 543 |
+
size_t len = abspath_len + 1 + strlen(*p) + 1;
|
| 544 |
+
char* testpath = (char*)malloc(len);
|
| 545 |
+
if (abspath_is_root) {
|
| 546 |
+
snprintf(testpath, len, "/%s", *p);
|
| 547 |
+
} else {
|
| 548 |
+
snprintf(testpath, len, "%s/%s", abspath, *p);
|
| 549 |
+
}
|
| 550 |
+
print_file_info(afc, testpath, list_verbose);
|
| 551 |
+
free(testpath);
|
| 552 |
+
p++;
|
| 553 |
+
}
|
| 554 |
+
afc_dictionary_free(entries);
|
| 555 |
+
free(abspath);
|
| 556 |
+
}
|
| 557 |
+
|
| 558 |
+
static void handle_rename(afc_client_t afc, int argc, char** argv)
|
| 559 |
+
{
|
| 560 |
+
if (argc != 2) {
|
| 561 |
+
printf("Error: Invalid number of arguments\n");
|
| 562 |
+
return;
|
| 563 |
+
}
|
| 564 |
+
char* srcpath = get_absolute_path(argv[0]);
|
| 565 |
+
if (!srcpath) {
|
| 566 |
+
printf("Error: Invalid argument\n");
|
| 567 |
+
return;
|
| 568 |
+
}
|
| 569 |
+
char* dstpath = get_absolute_path(argv[1]);
|
| 570 |
+
if (!dstpath) {
|
| 571 |
+
free(srcpath);
|
| 572 |
+
printf("Error: Invalid argument\n");
|
| 573 |
+
return;
|
| 574 |
+
}
|
| 575 |
+
afc_error_t err = afc_rename_path(afc, srcpath, dstpath);
|
| 576 |
+
if (err != AFC_E_SUCCESS) {
|
| 577 |
+
printf("Error: Failed to rename '%s' -> '%s': %s (%d)\n", argv[0], argv[1], afc_strerror(err), err);
|
| 578 |
+
}
|
| 579 |
+
free(srcpath);
|
| 580 |
+
free(dstpath);
|
| 581 |
+
}
|
| 582 |
+
|
| 583 |
+
static void handle_mkdir(afc_client_t afc, int argc, char** argv)
|
| 584 |
+
{
|
| 585 |
+
for (int i = 0; i < argc; i++) {
|
| 586 |
+
char* abspath = get_absolute_path(argv[i]);
|
| 587 |
+
if (!abspath) {
|
| 588 |
+
printf("Error: Invalid argument '%s'\n", argv[i]);
|
| 589 |
+
continue;
|
| 590 |
+
}
|
| 591 |
+
afc_error_t err = afc_make_directory(afc, abspath);
|
| 592 |
+
if (err != AFC_E_SUCCESS) {
|
| 593 |
+
printf("Error: Failed to create directory '%s': %s (%d)\n", argv[i], afc_strerror(err), err);
|
| 594 |
+
}
|
| 595 |
+
free(abspath);
|
| 596 |
+
}
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
static void handle_link(afc_client_t afc, int argc, char** argv)
|
| 600 |
+
{
|
| 601 |
+
if (argc < 2) {
|
| 602 |
+
printf("Error: Invalid number of arguments\n");
|
| 603 |
+
return;
|
| 604 |
+
}
|
| 605 |
+
afc_link_type_t link_type = AFC_HARDLINK;
|
| 606 |
+
if (!strcmp(argv[0], "-s")) {
|
| 607 |
+
argc--;
|
| 608 |
+
argv++;
|
| 609 |
+
link_type = AFC_SYMLINK;
|
| 610 |
+
}
|
| 611 |
+
if (argc < 1 || argc > 2) {
|
| 612 |
+
printf("Error: Invalid number of arguments\n");
|
| 613 |
+
return;
|
| 614 |
+
}
|
| 615 |
+
const char *link_name = (argc == 1) ? path_get_basename(argv[0]) : argv[1];
|
| 616 |
+
char* abs_link_name = get_absolute_path(link_name);
|
| 617 |
+
if (!abs_link_name) {
|
| 618 |
+
printf("Error: Invalid argument\n");
|
| 619 |
+
return;
|
| 620 |
+
}
|
| 621 |
+
afc_error_t err = afc_make_link(afc, link_type, argv[0], link_name);
|
| 622 |
+
if (err != AFC_E_SUCCESS) {
|
| 623 |
+
printf("Error: Failed to create %s link for '%s' at '%s': %s (%d)\n", (link_type == AFC_HARDLINK) ? "hard" : "symbolic", argv[0], link_name, afc_strerror(err), err);
|
| 624 |
+
}
|
| 625 |
+
}
|
| 626 |
+
|
| 627 |
+
static int ask_yesno(const char* prompt)
|
| 628 |
+
{
|
| 629 |
+
int ret = 0;
|
| 630 |
+
#ifdef HAVE_READLINE
|
| 631 |
+
char* result = readline(prompt);
|
| 632 |
+
if (result && result[0] == 'y') {
|
| 633 |
+
ret = 1;
|
| 634 |
+
}
|
| 635 |
+
#else
|
| 636 |
+
char cmdbuf[2] = {0, };
|
| 637 |
+
printf("%s", prompt);
|
| 638 |
+
fflush(stdout);
|
| 639 |
+
get_input(cmdbuf, sizeof(cmdbuf));
|
| 640 |
+
if (cmdbuf[0] == 'y') {
|
| 641 |
+
ret = 1;
|
| 642 |
+
}
|
| 643 |
+
#endif
|
| 644 |
+
#ifdef HAVE_READLINE
|
| 645 |
+
free(result);
|
| 646 |
+
#endif
|
| 647 |
+
return ret;
|
| 648 |
+
}
|
| 649 |
+
|
| 650 |
+
static void handle_remove(afc_client_t afc, int argc, char** argv)
|
| 651 |
+
{
|
| 652 |
+
int recursive = 0;
|
| 653 |
+
int force = 0;
|
| 654 |
+
int i = 0;
|
| 655 |
+
for (i = 0; i < argc; i++) {
|
| 656 |
+
if (!strcmp(argv[i], "--")) {
|
| 657 |
+
i++;
|
| 658 |
+
break;
|
| 659 |
+
} else if (!strcmp(argv[i], "-r")) {
|
| 660 |
+
recursive = 1;
|
| 661 |
+
} else if (!strcmp(argv[i], "-f")) {
|
| 662 |
+
force = 1;
|
| 663 |
+
} else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) {
|
| 664 |
+
recursive = 1;
|
| 665 |
+
force = 1;
|
| 666 |
+
} else {
|
| 667 |
+
break;
|
| 668 |
+
}
|
| 669 |
+
}
|
| 670 |
+
if (recursive && !force) {
|
| 671 |
+
if (!ask_yesno("WARNING: This operation will remove all contents of the given path(s). Continue? [y/N] ")) {
|
| 672 |
+
printf("Aborted.\n");
|
| 673 |
+
return;
|
| 674 |
+
}
|
| 675 |
+
}
|
| 676 |
+
for ( ; i < argc; i++) {
|
| 677 |
+
char* abspath = get_absolute_path(argv[i]);
|
| 678 |
+
if (!abspath) {
|
| 679 |
+
printf("Error: Invalid argument '%s'\n", argv[i]);
|
| 680 |
+
continue;
|
| 681 |
+
}
|
| 682 |
+
afc_error_t err;
|
| 683 |
+
if (recursive) {
|
| 684 |
+
err = afc_remove_path_and_contents(afc, abspath);
|
| 685 |
+
} else {
|
| 686 |
+
err = afc_remove_path(afc, abspath);
|
| 687 |
+
}
|
| 688 |
+
if (err != AFC_E_SUCCESS) {
|
| 689 |
+
printf("Error: Failed to remove '%s': %s (%d)\n", argv[i], afc_strerror(err), err);
|
| 690 |
+
}
|
| 691 |
+
free(abspath);
|
| 692 |
+
}
|
| 693 |
+
}
|
| 694 |
+
|
| 695 |
+
static uint8_t get_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint64_t file_size, uint8_t force_overwrite)
|
| 696 |
+
{
|
| 697 |
+
uint64_t fh = 0;
|
| 698 |
+
afc_error_t err = afc_file_open(afc, srcpath, AFC_FOPEN_RDONLY, &fh);
|
| 699 |
+
if (err != AFC_E_SUCCESS) {
|
| 700 |
+
printf("Error: Failed to open file '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
|
| 701 |
+
return 0;
|
| 702 |
+
}
|
| 703 |
+
if (file_exists(dstpath) && !force_overwrite) {
|
| 704 |
+
printf("Error: Failed to overwrite existing file without '-f' option: %s\n", dstpath);
|
| 705 |
+
return 0;
|
| 706 |
+
}
|
| 707 |
+
FILE *f = fopen(dstpath, "wb");
|
| 708 |
+
if (!f) {
|
| 709 |
+
printf("Error: Failed to open local file '%s': %s\n", dstpath, strerror(errno));
|
| 710 |
+
return 0;
|
| 711 |
+
}
|
| 712 |
+
struct timeval t1;
|
| 713 |
+
struct timeval t2;
|
| 714 |
+
struct timeval tdiff;
|
| 715 |
+
size_t bufsize = 0x100000;
|
| 716 |
+
char *buf = malloc(bufsize);
|
| 717 |
+
size_t total = 0;
|
| 718 |
+
int progress = 0;
|
| 719 |
+
int lastprog = 0;
|
| 720 |
+
if (file_size > 0x400000) {
|
| 721 |
+
progress = 1;
|
| 722 |
+
gettimeofday(&t1, NULL);
|
| 723 |
+
}
|
| 724 |
+
uint8_t succeed = 1;
|
| 725 |
+
while (err == AFC_E_SUCCESS) {
|
| 726 |
+
uint32_t bytes_read = 0;
|
| 727 |
+
size_t chunk = 0;
|
| 728 |
+
err = afc_file_read(afc, fh, buf, bufsize, &bytes_read);
|
| 729 |
+
if (bytes_read == 0) {
|
| 730 |
+
break;
|
| 731 |
+
}
|
| 732 |
+
while (chunk < bytes_read) {
|
| 733 |
+
size_t wr = fwrite(buf + chunk, 1, bytes_read - chunk, f);
|
| 734 |
+
if (wr == 0) {
|
| 735 |
+
if (progress) {
|
| 736 |
+
printf("\n");
|
| 737 |
+
}
|
| 738 |
+
printf("Error: Failed to write to local file\n");
|
| 739 |
+
succeed = 0;
|
| 740 |
+
break;
|
| 741 |
+
}
|
| 742 |
+
chunk += wr;
|
| 743 |
+
}
|
| 744 |
+
total += chunk;
|
| 745 |
+
if (progress) {
|
| 746 |
+
int prog = (int) ((double) total / (double) file_size * 100.0f);
|
| 747 |
+
if (prog > lastprog) {
|
| 748 |
+
gettimeofday(&t2, NULL);
|
| 749 |
+
timeval_subtract(&tdiff, &t2, &t1);
|
| 750 |
+
double time_in_sec = (double) tdiff.tv_sec + (double) tdiff.tv_usec / 1000000;
|
| 751 |
+
printf("\r%d%% (%0.1f MB/s) ", prog, (double) total / 1048576.0f / time_in_sec);
|
| 752 |
+
fflush(stdout);
|
| 753 |
+
lastprog = prog;
|
| 754 |
+
}
|
| 755 |
+
}
|
| 756 |
+
}
|
| 757 |
+
if (progress) {
|
| 758 |
+
printf("\n");
|
| 759 |
+
}
|
| 760 |
+
if (err != AFC_E_SUCCESS) {
|
| 761 |
+
printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
|
| 762 |
+
succeed = 0;
|
| 763 |
+
}
|
| 764 |
+
free(buf);
|
| 765 |
+
fclose(f);
|
| 766 |
+
afc_file_close(afc, fh);
|
| 767 |
+
return succeed;
|
| 768 |
+
}
|
| 769 |
+
|
| 770 |
+
static int __mkdir(const char* path)
|
| 771 |
+
{
|
| 772 |
+
#ifdef _WIN32
|
| 773 |
+
return mkdir(path);
|
| 774 |
+
#else
|
| 775 |
+
return mkdir(path, 0755);
|
| 776 |
+
#endif
|
| 777 |
+
}
|
| 778 |
+
|
| 779 |
+
static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_get)
|
| 780 |
+
{
|
| 781 |
+
plist_t info = NULL;
|
| 782 |
+
uint64_t file_size = 0;
|
| 783 |
+
afc_error_t err = afc_get_file_info_plist(afc, srcpath, &info);
|
| 784 |
+
if (err == AFC_E_OBJECT_NOT_FOUND) {
|
| 785 |
+
printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
|
| 786 |
+
return 0;
|
| 787 |
+
}
|
| 788 |
+
uint8_t is_dir = 0;
|
| 789 |
+
if (info) {
|
| 790 |
+
file_size = plist_dict_get_uint(info, "st_size");
|
| 791 |
+
const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
|
| 792 |
+
is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
|
| 793 |
+
plist_free(info);
|
| 794 |
+
}
|
| 795 |
+
uint8_t succeed = 1;
|
| 796 |
+
if (is_dir) {
|
| 797 |
+
if (!recursive_get) {
|
| 798 |
+
printf("Error: Failed to get a directory without '-r' option: %s\n", srcpath);
|
| 799 |
+
return 0;
|
| 800 |
+
}
|
| 801 |
+
char **entries = NULL;
|
| 802 |
+
err = afc_read_directory(afc, srcpath, &entries);
|
| 803 |
+
if (err != AFC_E_SUCCESS) {
|
| 804 |
+
printf("Error: Failed to list '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
|
| 805 |
+
return 0;
|
| 806 |
+
}
|
| 807 |
+
char **p = entries;
|
| 808 |
+
size_t srcpath_len = strlen(srcpath);
|
| 809 |
+
uint8_t srcpath_is_root = strcmp(srcpath, "/") == 0;
|
| 810 |
+
// if directory exists, check force_overwrite flag
|
| 811 |
+
if (is_directory(dstpath)) {
|
| 812 |
+
if (!force_overwrite) {
|
| 813 |
+
printf("Error: Failed to write into existing directory without '-f': %s\n", dstpath);
|
| 814 |
+
return 0;
|
| 815 |
+
}
|
| 816 |
+
} else if (__mkdir(dstpath) != 0) {
|
| 817 |
+
printf("Error: Failed to create directory '%s': %s\n", dstpath, strerror(errno));
|
| 818 |
+
afc_dictionary_free(entries);
|
| 819 |
+
return 0;
|
| 820 |
+
}
|
| 821 |
+
while (p && *p) {
|
| 822 |
+
if (strcmp(".", *p) == 0 || strcmp("..", *p) == 0) {
|
| 823 |
+
p++;
|
| 824 |
+
continue;
|
| 825 |
+
}
|
| 826 |
+
size_t len = srcpath_is_root ? (strlen(*p) + 2) : (srcpath_len + 1 + strlen(*p) + 1);
|
| 827 |
+
char *testpath = (char *) malloc(len);
|
| 828 |
+
if (srcpath_is_root) {
|
| 829 |
+
snprintf(testpath, len, "/%s", *p);
|
| 830 |
+
} else {
|
| 831 |
+
snprintf(testpath, len, "%s/%s", srcpath, *p);
|
| 832 |
+
}
|
| 833 |
+
uint8_t dst_is_root = strcmp(srcpath, "/") == 0;
|
| 834 |
+
size_t dst_len = dst_is_root ? (strlen(*p) + 2) : (strlen(dstpath) + 1 + strlen(*p) + 1);
|
| 835 |
+
char *newdst = (char *) malloc(dst_len);
|
| 836 |
+
if (dst_is_root) {
|
| 837 |
+
snprintf(newdst, dst_len, "/%s", *p);
|
| 838 |
+
} else {
|
| 839 |
+
snprintf(newdst, dst_len, "%s/%s", dstpath, *p);
|
| 840 |
+
}
|
| 841 |
+
if (!get_file(afc, testpath, newdst, force_overwrite, recursive_get)) {
|
| 842 |
+
succeed = 0;
|
| 843 |
+
break;
|
| 844 |
+
}
|
| 845 |
+
free(testpath);
|
| 846 |
+
free(newdst);
|
| 847 |
+
p++;
|
| 848 |
+
}
|
| 849 |
+
afc_dictionary_free(entries);
|
| 850 |
+
} else {
|
| 851 |
+
succeed = get_single_file(afc, srcpath, dstpath, file_size, force_overwrite);
|
| 852 |
+
}
|
| 853 |
+
return succeed;
|
| 854 |
+
}
|
| 855 |
+
|
| 856 |
+
static void handle_get(afc_client_t afc, int argc, char **argv)
|
| 857 |
+
{
|
| 858 |
+
if (argc < 1) {
|
| 859 |
+
printf("Error: Invalid number of arguments\n");
|
| 860 |
+
return;
|
| 861 |
+
}
|
| 862 |
+
uint8_t force_overwrite = 0, recursive_get = 0;
|
| 863 |
+
char *srcpath = NULL;
|
| 864 |
+
char *dstpath = NULL;
|
| 865 |
+
int i = 0;
|
| 866 |
+
for ( ; i < argc; i++) {
|
| 867 |
+
if (!strcmp(argv[i], "--")) {
|
| 868 |
+
i++;
|
| 869 |
+
break;
|
| 870 |
+
} else if (!strcmp(argv[i], "-r")) {
|
| 871 |
+
recursive_get = 1;
|
| 872 |
+
} else if (!strcmp(argv[i], "-f")) {
|
| 873 |
+
force_overwrite = 1;
|
| 874 |
+
} else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) {
|
| 875 |
+
recursive_get = 1;
|
| 876 |
+
force_overwrite = 1;
|
| 877 |
+
} else {
|
| 878 |
+
break;
|
| 879 |
+
}
|
| 880 |
+
}
|
| 881 |
+
if (argc - i == 1) {
|
| 882 |
+
char *tmp = strdup(argv[i]);
|
| 883 |
+
size_t src_len = strlen(tmp);
|
| 884 |
+
if (src_len > 1 && tmp[src_len - 1] == '/') {
|
| 885 |
+
tmp[src_len - 1] = '\0';
|
| 886 |
+
}
|
| 887 |
+
srcpath = get_absolute_path(tmp);
|
| 888 |
+
dstpath = strdup(path_get_basename(tmp));
|
| 889 |
+
free(tmp);
|
| 890 |
+
} else if (argc - i == 2) {
|
| 891 |
+
char *tmp = strdup(argv[i]);
|
| 892 |
+
size_t src_len = strlen(tmp);
|
| 893 |
+
if (src_len > 1 && tmp[src_len - 1] == '/') {
|
| 894 |
+
tmp[src_len - 1] = '\0';
|
| 895 |
+
}
|
| 896 |
+
srcpath = get_absolute_path(tmp);
|
| 897 |
+
dstpath = strdup(argv[i + 1]);
|
| 898 |
+
size_t dst_len = strlen(dstpath);
|
| 899 |
+
if (dst_len > 1 && dstpath[dst_len - 1] == '/') {
|
| 900 |
+
dstpath[dst_len - 1] = '\0';
|
| 901 |
+
}
|
| 902 |
+
free(tmp);
|
| 903 |
+
} else {
|
| 904 |
+
printf("Error: Invalid number of arguments\n");
|
| 905 |
+
return;
|
| 906 |
+
}
|
| 907 |
+
|
| 908 |
+
// target is a directory, put file under this target
|
| 909 |
+
if (is_directory(dstpath)) {
|
| 910 |
+
const char *basen = path_get_basename(srcpath);
|
| 911 |
+
uint8_t dst_is_root = strcmp(dstpath, "/") == 0;
|
| 912 |
+
size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1);
|
| 913 |
+
char *newdst = (char *) malloc(len);
|
| 914 |
+
if (dst_is_root) {
|
| 915 |
+
snprintf(newdst, len, "/%s", basen);
|
| 916 |
+
} else {
|
| 917 |
+
snprintf(newdst, len, "%s/%s", dstpath, basen);
|
| 918 |
+
}
|
| 919 |
+
get_file(afc, srcpath, newdst, force_overwrite, recursive_get);
|
| 920 |
+
free(srcpath);
|
| 921 |
+
free(newdst);
|
| 922 |
+
free(dstpath);
|
| 923 |
+
} else {
|
| 924 |
+
// target is not a dir or does not exist, just try to create or rewrite it
|
| 925 |
+
get_file(afc, srcpath, dstpath, force_overwrite, recursive_get);
|
| 926 |
+
free(srcpath);
|
| 927 |
+
free(dstpath);
|
| 928 |
+
}
|
| 929 |
+
}
|
| 930 |
+
|
| 931 |
+
static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite)
|
| 932 |
+
{
|
| 933 |
+
plist_t info = NULL;
|
| 934 |
+
afc_error_t ret = afc_get_file_info_plist(afc, dstpath, &info);
|
| 935 |
+
// file exists, only overwrite with '-f' option was set
|
| 936 |
+
if (ret == AFC_E_SUCCESS && info) {
|
| 937 |
+
plist_free(info);
|
| 938 |
+
if (!force_overwrite) {
|
| 939 |
+
printf("Error: Failed to write into existing file without '-f' option: %s\n", dstpath);
|
| 940 |
+
return 0;
|
| 941 |
+
}
|
| 942 |
+
}
|
| 943 |
+
FILE *f = fopen(srcpath, "rb");
|
| 944 |
+
if (!f) {
|
| 945 |
+
printf("Error: Failed to open local file '%s': %s\n", srcpath, strerror(errno));
|
| 946 |
+
return 0;
|
| 947 |
+
}
|
| 948 |
+
struct timeval t1;
|
| 949 |
+
struct timeval t2;
|
| 950 |
+
struct timeval tdiff;
|
| 951 |
+
struct stat fst;
|
| 952 |
+
int progress = 0;
|
| 953 |
+
size_t bufsize = 0x100000;
|
| 954 |
+
char *buf = malloc(bufsize);
|
| 955 |
+
|
| 956 |
+
fstat(fileno(f), &fst);
|
| 957 |
+
if (fst.st_size >= 0x400000) {
|
| 958 |
+
progress = 1;
|
| 959 |
+
gettimeofday(&t1, NULL);
|
| 960 |
+
}
|
| 961 |
+
size_t total = 0;
|
| 962 |
+
int lastprog = 0;
|
| 963 |
+
uint64_t fh = 0;
|
| 964 |
+
afc_error_t err = afc_file_open(afc, dstpath, AFC_FOPEN_RW, &fh);
|
| 965 |
+
uint8_t succeed = 1;
|
| 966 |
+
while (err == AFC_E_SUCCESS) {
|
| 967 |
+
uint32_t bytes_read = fread(buf, 1, bufsize, f);
|
| 968 |
+
if (bytes_read == 0) {
|
| 969 |
+
if (!feof(f)) {
|
| 970 |
+
if (progress) {
|
| 971 |
+
printf("\n");
|
| 972 |
+
}
|
| 973 |
+
printf("Error: Failed to read from local file\n");
|
| 974 |
+
succeed = 0;
|
| 975 |
+
}
|
| 976 |
+
break;
|
| 977 |
+
}
|
| 978 |
+
uint32_t chunk = 0;
|
| 979 |
+
while (chunk < bytes_read) {
|
| 980 |
+
uint32_t bytes_written = 0;
|
| 981 |
+
err = afc_file_write(afc, fh, buf + chunk, bytes_read - chunk, &bytes_written);
|
| 982 |
+
if (err != AFC_E_SUCCESS) {
|
| 983 |
+
if (progress) {
|
| 984 |
+
printf("\n");
|
| 985 |
+
}
|
| 986 |
+
printf("Error: Failed to write to device file\n");
|
| 987 |
+
succeed = 0;
|
| 988 |
+
break;
|
| 989 |
+
}
|
| 990 |
+
chunk += bytes_written;
|
| 991 |
+
}
|
| 992 |
+
total += chunk;
|
| 993 |
+
if (progress) {
|
| 994 |
+
int prog = (int) ((double) total / (double) fst.st_size * 100.0f);
|
| 995 |
+
if (prog > lastprog) {
|
| 996 |
+
gettimeofday(&t2, NULL);
|
| 997 |
+
timeval_subtract(&tdiff, &t2, &t1);
|
| 998 |
+
double time_in_sec = (double) tdiff.tv_sec + (double) tdiff.tv_usec / 1000000;
|
| 999 |
+
printf("\r%d%% (%0.1f MB/s) ", prog, (double) total / 1048576.0f / time_in_sec);
|
| 1000 |
+
fflush(stdout);
|
| 1001 |
+
lastprog = prog;
|
| 1002 |
+
}
|
| 1003 |
+
}
|
| 1004 |
+
}
|
| 1005 |
+
free(buf);
|
| 1006 |
+
afc_file_close(afc, fh);
|
| 1007 |
+
fclose(f);
|
| 1008 |
+
return succeed;
|
| 1009 |
+
}
|
| 1010 |
+
|
| 1011 |
+
static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_put)
|
| 1012 |
+
{
|
| 1013 |
+
if (is_directory(srcpath)) {
|
| 1014 |
+
if (!recursive_put) {
|
| 1015 |
+
printf("Error: Failed to put directory without '-r' option: %s\n", srcpath);
|
| 1016 |
+
return 0;
|
| 1017 |
+
}
|
| 1018 |
+
plist_t info = NULL;
|
| 1019 |
+
afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info);
|
| 1020 |
+
//create if target directory does not exist
|
| 1021 |
+
plist_free(info);
|
| 1022 |
+
info = NULL;
|
| 1023 |
+
if (err == AFC_E_OBJECT_NOT_FOUND) {
|
| 1024 |
+
err = afc_make_directory(afc, dstpath);
|
| 1025 |
+
if (err != AFC_E_SUCCESS) {
|
| 1026 |
+
printf("Error: Failed to create directory '%s': %s (%d)\n", dstpath, afc_strerror(err), err);
|
| 1027 |
+
return 0;
|
| 1028 |
+
}
|
| 1029 |
+
} else if (!force_overwrite) {
|
| 1030 |
+
printf("Error: Failed to put existing directory without '-f' option: %s\n", dstpath);
|
| 1031 |
+
return 0;
|
| 1032 |
+
}
|
| 1033 |
+
afc_get_file_info_plist(afc, dstpath, &info);
|
| 1034 |
+
uint8_t is_dir = 0;
|
| 1035 |
+
if (info) {
|
| 1036 |
+
const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
|
| 1037 |
+
is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
|
| 1038 |
+
plist_free(info);
|
| 1039 |
+
}
|
| 1040 |
+
if (!is_dir) {
|
| 1041 |
+
printf("Error: Failed to create or access directory: '%s'\n", dstpath);
|
| 1042 |
+
return 0;
|
| 1043 |
+
}
|
| 1044 |
+
|
| 1045 |
+
// walk dir recursively to put files
|
| 1046 |
+
DIR *cur_dir = opendir(srcpath);
|
| 1047 |
+
if (cur_dir) {
|
| 1048 |
+
struct dirent *ep;
|
| 1049 |
+
while ((ep = readdir(cur_dir))) {
|
| 1050 |
+
if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) {
|
| 1051 |
+
continue;
|
| 1052 |
+
}
|
| 1053 |
+
char *fpath = string_build_path(srcpath, ep->d_name, NULL);
|
| 1054 |
+
if (fpath) {
|
| 1055 |
+
uint8_t dst_is_root = strcmp(dstpath, "/") == 0;
|
| 1056 |
+
size_t len = dst_is_root ? (strlen(ep->d_name) + 2) : (strlen(dstpath) + 1 + strlen(ep->d_name) + 1);
|
| 1057 |
+
char *newdst = (char *) malloc(len);
|
| 1058 |
+
if (dst_is_root) {
|
| 1059 |
+
snprintf(newdst, len, "/%s", ep->d_name);
|
| 1060 |
+
} else {
|
| 1061 |
+
snprintf(newdst, len, "%s/%s", dstpath, ep->d_name);
|
| 1062 |
+
}
|
| 1063 |
+
if (!put_file(afc, fpath, newdst, force_overwrite, recursive_put)) {
|
| 1064 |
+
free(newdst);
|
| 1065 |
+
free(fpath);
|
| 1066 |
+
return 0;
|
| 1067 |
+
}
|
| 1068 |
+
free(newdst);
|
| 1069 |
+
free(fpath);
|
| 1070 |
+
}
|
| 1071 |
+
}
|
| 1072 |
+
closedir(cur_dir);
|
| 1073 |
+
} else {
|
| 1074 |
+
printf("Error: Failed to visit directory: '%s': %s\n", srcpath, strerror(errno));
|
| 1075 |
+
return 0;
|
| 1076 |
+
}
|
| 1077 |
+
} else {
|
| 1078 |
+
return put_single_file(afc, srcpath, dstpath, force_overwrite);
|
| 1079 |
+
}
|
| 1080 |
+
return 1;
|
| 1081 |
+
}
|
| 1082 |
+
|
| 1083 |
+
static void handle_put(afc_client_t afc, int argc, char **argv)
|
| 1084 |
+
{
|
| 1085 |
+
if (argc < 1) {
|
| 1086 |
+
printf("Error: Invalid number of arguments\n");
|
| 1087 |
+
return;
|
| 1088 |
+
}
|
| 1089 |
+
int i = 0;
|
| 1090 |
+
uint8_t force_overwrite = 0, recursive_put = 0;
|
| 1091 |
+
for ( ; i < argc; i++) {
|
| 1092 |
+
if (!strcmp(argv[i], "--")) {
|
| 1093 |
+
i++;
|
| 1094 |
+
break;
|
| 1095 |
+
} else if (!strcmp(argv[i], "-r")) {
|
| 1096 |
+
recursive_put = 1;
|
| 1097 |
+
} else if (!strcmp(argv[i], "-f")) {
|
| 1098 |
+
force_overwrite = 1;
|
| 1099 |
+
} else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) {
|
| 1100 |
+
recursive_put = 1;
|
| 1101 |
+
force_overwrite = 1;
|
| 1102 |
+
} else {
|
| 1103 |
+
break;
|
| 1104 |
+
}
|
| 1105 |
+
}
|
| 1106 |
+
if (i >= argc) {
|
| 1107 |
+
printf("Error: Invalid number of arguments\n");
|
| 1108 |
+
return;
|
| 1109 |
+
}
|
| 1110 |
+
char *srcpath = strdup(argv[i]);
|
| 1111 |
+
size_t src_len = strlen(srcpath);
|
| 1112 |
+
if (src_len > 1 && srcpath[src_len - 1] == '/') {
|
| 1113 |
+
srcpath[src_len - 1] = '\0';
|
| 1114 |
+
}
|
| 1115 |
+
char *dstpath = NULL;
|
| 1116 |
+
if (argc - i == 1) {
|
| 1117 |
+
dstpath = get_absolute_path(path_get_basename(srcpath));
|
| 1118 |
+
} else if (argc - i == 2) {
|
| 1119 |
+
char *tmp = strdup(argv[i + 1]);
|
| 1120 |
+
size_t dst_len = strlen(tmp);
|
| 1121 |
+
if (dst_len > 1 && tmp[dst_len - 1] == '/') {
|
| 1122 |
+
tmp[dst_len - 1] = '\0';
|
| 1123 |
+
}
|
| 1124 |
+
dstpath = get_absolute_path(tmp);
|
| 1125 |
+
free(tmp);
|
| 1126 |
+
} else {
|
| 1127 |
+
printf("Error: Invalid number of arguments\n");
|
| 1128 |
+
return;
|
| 1129 |
+
}
|
| 1130 |
+
plist_t info = NULL;
|
| 1131 |
+
afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info);
|
| 1132 |
+
// target does not exist, put directly
|
| 1133 |
+
if (err == AFC_E_OBJECT_NOT_FOUND) {
|
| 1134 |
+
put_file(afc, srcpath, dstpath, force_overwrite, recursive_put);
|
| 1135 |
+
free(srcpath);
|
| 1136 |
+
free(dstpath);
|
| 1137 |
+
} else {
|
| 1138 |
+
uint8_t is_dir = 0;
|
| 1139 |
+
if (info) {
|
| 1140 |
+
const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
|
| 1141 |
+
is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
|
| 1142 |
+
plist_free(info);
|
| 1143 |
+
}
|
| 1144 |
+
// target is a directory, try to put under this directory
|
| 1145 |
+
if (is_dir) {
|
| 1146 |
+
const char *basen = path_get_basename(srcpath);
|
| 1147 |
+
uint8_t dst_is_root = strcmp(dstpath, "/") == 0;
|
| 1148 |
+
size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1);
|
| 1149 |
+
char *newdst = (char *) malloc(len);
|
| 1150 |
+
if (dst_is_root) {
|
| 1151 |
+
snprintf(newdst, len, "/%s", basen);
|
| 1152 |
+
} else {
|
| 1153 |
+
snprintf(newdst, len, "%s/%s", dstpath, basen);
|
| 1154 |
+
}
|
| 1155 |
+
free(dstpath);
|
| 1156 |
+
dstpath = get_absolute_path(newdst);
|
| 1157 |
+
free(newdst);
|
| 1158 |
+
put_file(afc, srcpath, dstpath, force_overwrite, recursive_put);
|
| 1159 |
+
} else {
|
| 1160 |
+
//target is common file, rewrite it
|
| 1161 |
+
put_file(afc, srcpath, dstpath, force_overwrite, recursive_put);
|
| 1162 |
+
}
|
| 1163 |
+
free(srcpath);
|
| 1164 |
+
free(dstpath);
|
| 1165 |
+
}
|
| 1166 |
+
}
|
| 1167 |
+
|
| 1168 |
+
static void handle_pwd(afc_client_t afc, int argc, char** argv)
|
| 1169 |
+
{
|
| 1170 |
+
printf("%s\n", curdir);
|
| 1171 |
+
}
|
| 1172 |
+
|
| 1173 |
+
static void handle_cd(afc_client_t afc, int argc, char** argv)
|
| 1174 |
+
{
|
| 1175 |
+
if (argc != 1) {
|
| 1176 |
+
printf("Error: Invalid number of arguments\n");
|
| 1177 |
+
return;
|
| 1178 |
+
}
|
| 1179 |
+
|
| 1180 |
+
if (!strcmp(argv[0], ".")) {
|
| 1181 |
+
return;
|
| 1182 |
+
}
|
| 1183 |
+
|
| 1184 |
+
if (!strcmp(argv[0], "..")) {
|
| 1185 |
+
if (!strcmp(curdir, "/")) {
|
| 1186 |
+
return;
|
| 1187 |
+
}
|
| 1188 |
+
char *p = strrchr(curdir, '/');
|
| 1189 |
+
if (!p) {
|
| 1190 |
+
strcpy(curdir, "/");
|
| 1191 |
+
return;
|
| 1192 |
+
}
|
| 1193 |
+
if (p == curdir) {
|
| 1194 |
+
*(p+1) = '\0';
|
| 1195 |
+
} else {
|
| 1196 |
+
*p = '\0';
|
| 1197 |
+
}
|
| 1198 |
+
return;
|
| 1199 |
+
}
|
| 1200 |
+
|
| 1201 |
+
char* path = get_realpath(argv[0]);
|
| 1202 |
+
int is_dir = 0;
|
| 1203 |
+
plist_t info = NULL;
|
| 1204 |
+
afc_error_t err = afc_get_file_info_plist(afc, path, &info);
|
| 1205 |
+
if (err == AFC_E_SUCCESS && info) {
|
| 1206 |
+
const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL);
|
| 1207 |
+
is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR"));
|
| 1208 |
+
plist_free(info);
|
| 1209 |
+
} else {
|
| 1210 |
+
printf("Error: Failed to get file info for %s: %s (%d)\n", path, afc_strerror(err), err);
|
| 1211 |
+
free(path);
|
| 1212 |
+
return;
|
| 1213 |
+
}
|
| 1214 |
+
|
| 1215 |
+
if (!is_dir) {
|
| 1216 |
+
printf("Error: '%s' is not a valid directory\n", path);
|
| 1217 |
+
free(path);
|
| 1218 |
+
return;
|
| 1219 |
+
}
|
| 1220 |
+
|
| 1221 |
+
free(curdir);
|
| 1222 |
+
curdir = path;
|
| 1223 |
+
curdir_len = strlen(curdir);
|
| 1224 |
+
}
|
| 1225 |
+
|
| 1226 |
+
static void parse_cmdline(int* p_argc, char*** p_argv, const char* cmdline)
|
| 1227 |
+
{
|
| 1228 |
+
char **argv = NULL;
|
| 1229 |
+
int argc = 0;
|
| 1230 |
+
size_t maxlen = strlen(cmdline);
|
| 1231 |
+
const char* pos = cmdline;
|
| 1232 |
+
const char* qpos = NULL;
|
| 1233 |
+
char *tmpbuf = NULL;
|
| 1234 |
+
int tmplen = 0;
|
| 1235 |
+
int is_error = 0;
|
| 1236 |
+
|
| 1237 |
+
/* skip initial whitespace */
|
| 1238 |
+
while (isspace(*pos)) pos++;
|
| 1239 |
+
maxlen -= (pos - cmdline);
|
| 1240 |
+
|
| 1241 |
+
tmpbuf = (char*)malloc(maxlen+1);
|
| 1242 |
+
|
| 1243 |
+
while (!is_error) {
|
| 1244 |
+
if (*pos == '\\') {
|
| 1245 |
+
pos++;
|
| 1246 |
+
switch (*pos) {
|
| 1247 |
+
case '"':
|
| 1248 |
+
case '\'':
|
| 1249 |
+
case '\\':
|
| 1250 |
+
case ' ':
|
| 1251 |
+
tmpbuf[tmplen++] = *pos;
|
| 1252 |
+
pos++;
|
| 1253 |
+
break;
|
| 1254 |
+
default:
|
| 1255 |
+
printf("Error: Invalid escape sequence\n");
|
| 1256 |
+
is_error++;
|
| 1257 |
+
break;
|
| 1258 |
+
}
|
| 1259 |
+
} else if (*pos == '"' || *pos == '\'') {
|
| 1260 |
+
if (!qpos) {
|
| 1261 |
+
qpos = pos;
|
| 1262 |
+
} else {
|
| 1263 |
+
qpos = NULL;
|
| 1264 |
+
}
|
| 1265 |
+
pos++;
|
| 1266 |
+
} else if (*pos == '\0' || (!qpos && isspace(*pos))) {
|
| 1267 |
+
tmpbuf[tmplen] = '\0';
|
| 1268 |
+
if (*pos == '\0' && qpos) {
|
| 1269 |
+
printf("Error: Unmatched `%c`\n", *qpos);
|
| 1270 |
+
is_error++;
|
| 1271 |
+
break;
|
| 1272 |
+
}
|
| 1273 |
+
char** new_argv = (char**)realloc(argv, (argc+1)*sizeof(char*));
|
| 1274 |
+
if (new_argv == NULL) {
|
| 1275 |
+
printf("Error: Out of memory?!\n");
|
| 1276 |
+
is_error++;
|
| 1277 |
+
break;
|
| 1278 |
+
}
|
| 1279 |
+
argv = new_argv;
|
| 1280 |
+
/* shrink buffer to actual argument size */
|
| 1281 |
+
argv[argc] = (char*)realloc(tmpbuf, tmplen+1);
|
| 1282 |
+
if (!argv[argc]) {
|
| 1283 |
+
printf("Error: Out of memory?!\n");
|
| 1284 |
+
is_error++;
|
| 1285 |
+
break;
|
| 1286 |
+
}
|
| 1287 |
+
argc++;
|
| 1288 |
+
tmpbuf = NULL;
|
| 1289 |
+
if (*pos == '\0') {
|
| 1290 |
+
break;
|
| 1291 |
+
}
|
| 1292 |
+
maxlen -= tmplen;
|
| 1293 |
+
tmpbuf = (char*)malloc(maxlen+1);
|
| 1294 |
+
tmplen = 0;
|
| 1295 |
+
while (isspace(*pos)) pos++;
|
| 1296 |
+
} else {
|
| 1297 |
+
tmpbuf[tmplen++] = *pos;
|
| 1298 |
+
pos++;
|
| 1299 |
+
}
|
| 1300 |
+
}
|
| 1301 |
+
if (tmpbuf) {
|
| 1302 |
+
free(tmpbuf);
|
| 1303 |
+
}
|
| 1304 |
+
if (is_error) {
|
| 1305 |
+
int i;
|
| 1306 |
+
for (i = 0; argv && i < argc; i++) free(argv[i]);
|
| 1307 |
+
free(argv);
|
| 1308 |
+
return;
|
| 1309 |
+
}
|
| 1310 |
+
|
| 1311 |
+
*p_argv = argv;
|
| 1312 |
+
*p_argc = argc;
|
| 1313 |
+
}
|
| 1314 |
+
|
| 1315 |
+
static int process_args(afc_client_t afc, int argc, char** argv)
|
| 1316 |
+
{
|
| 1317 |
+
if (!strcmp(argv[0], "q") || !strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
|
| 1318 |
+
return -1;
|
| 1319 |
+
}
|
| 1320 |
+
else if (!strcmp(argv[0], "help")) {
|
| 1321 |
+
handle_help(afc, argc, argv);
|
| 1322 |
+
}
|
| 1323 |
+
else if (!strcmp(argv[0], "devinfo") || !strcmp(argv[0], "deviceinfo")) {
|
| 1324 |
+
handle_devinfo(afc, argc-1, argv+1);
|
| 1325 |
+
}
|
| 1326 |
+
else if (!strcmp(argv[0], "info")) {
|
| 1327 |
+
handle_file_info(afc, argc-1, argv+1);
|
| 1328 |
+
}
|
| 1329 |
+
else if (!strcmp(argv[0], "ls") || !strcmp(argv[0], "list")) {
|
| 1330 |
+
handle_list(afc, argc-1, argv+1);
|
| 1331 |
+
}
|
| 1332 |
+
else if (!strcmp(argv[0], "mv") || !strcmp(argv[0], "rename")) {
|
| 1333 |
+
handle_rename(afc, argc-1, argv+1);
|
| 1334 |
+
}
|
| 1335 |
+
else if (!strcmp(argv[0], "mkdir")) {
|
| 1336 |
+
handle_mkdir(afc, argc-1, argv+1);
|
| 1337 |
+
}
|
| 1338 |
+
else if (!strcmp(argv[0], "ln")) {
|
| 1339 |
+
handle_link(afc, argc-1, argv+1);
|
| 1340 |
+
}
|
| 1341 |
+
else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove")) {
|
| 1342 |
+
handle_remove(afc, argc-1, argv+1);
|
| 1343 |
+
}
|
| 1344 |
+
else if (!strcmp(argv[0], "get")) {
|
| 1345 |
+
handle_get(afc, argc-1, argv+1);
|
| 1346 |
+
}
|
| 1347 |
+
else if (!strcmp(argv[0], "put")) {
|
| 1348 |
+
handle_put(afc, argc-1, argv+1);
|
| 1349 |
+
}
|
| 1350 |
+
else if (!strcmp(argv[0], "pwd")) {
|
| 1351 |
+
handle_pwd(afc, argc-1, argv+1);
|
| 1352 |
+
}
|
| 1353 |
+
else if (!strcmp(argv[0], "cd")) {
|
| 1354 |
+
handle_cd(afc, argc-1, argv+1);
|
| 1355 |
+
}
|
| 1356 |
+
else {
|
| 1357 |
+
printf("Unknown command '%s'. Type 'help' to get a list of available commands.\n", argv[0]);
|
| 1358 |
+
}
|
| 1359 |
+
return 0;
|
| 1360 |
+
}
|
| 1361 |
+
|
| 1362 |
+
static void start_cmdline(afc_client_t afc)
|
| 1363 |
+
{
|
| 1364 |
+
while (!stop_requested) {
|
| 1365 |
+
int argc = 0;
|
| 1366 |
+
char **argv = NULL;
|
| 1367 |
+
char prompt[128];
|
| 1368 |
+
int plen = curdir_len;
|
| 1369 |
+
char *ppath = curdir;
|
| 1370 |
+
int plim = (int)(sizeof(prompt)/2)-8;
|
| 1371 |
+
if (plen > plim) {
|
| 1372 |
+
ppath = curdir + (plen - plim);
|
| 1373 |
+
plen = plim;
|
| 1374 |
+
}
|
| 1375 |
+
snprintf(prompt, 128, FG_BLACK BG_LIGHT_GRAY "afc:" COLOR_RESET FG_BRIGHT_YELLOW BG_BLUE "%.*s" COLOR_RESET " > ", plen, ppath);
|
| 1376 |
+
#ifdef HAVE_READLINE
|
| 1377 |
+
char* cmd = readline(prompt);
|
| 1378 |
+
if (!cmd || !*cmd) {
|
| 1379 |
+
free(cmd);
|
| 1380 |
+
continue;
|
| 1381 |
+
}
|
| 1382 |
+
add_history(cmd);
|
| 1383 |
+
parse_cmdline(&argc, &argv, cmd);
|
| 1384 |
+
#else
|
| 1385 |
+
char cmdbuf[4096];
|
| 1386 |
+
printf("%s", prompt);
|
| 1387 |
+
fflush(stdout);
|
| 1388 |
+
get_input(cmdbuf, sizeof(cmdbuf));
|
| 1389 |
+
parse_cmdline(&argc, &argv, cmdbuf);
|
| 1390 |
+
#endif
|
| 1391 |
+
#ifdef HAVE_READLINE
|
| 1392 |
+
free(cmd);
|
| 1393 |
+
#endif
|
| 1394 |
+
/* process arguments */
|
| 1395 |
+
if (argv && argv[0]) {
|
| 1396 |
+
if (process_args(afc, argc, argv) < 0) {
|
| 1397 |
+
break;
|
| 1398 |
+
}
|
| 1399 |
+
}
|
| 1400 |
+
}
|
| 1401 |
+
}
|
| 1402 |
+
|
| 1403 |
+
static void device_event_cb(const idevice_event_t* event, void* userdata)
|
| 1404 |
+
{
|
| 1405 |
+
if (use_network && event->conn_type != CONNECTION_NETWORK) {
|
| 1406 |
+
return;
|
| 1407 |
+
} else if (!use_network && event->conn_type != CONNECTION_USBMUXD) {
|
| 1408 |
+
return;
|
| 1409 |
+
}
|
| 1410 |
+
if (event->event == IDEVICE_DEVICE_ADD) {
|
| 1411 |
+
if (!udid) {
|
| 1412 |
+
udid = strdup(event->udid);
|
| 1413 |
+
}
|
| 1414 |
+
if (strcmp(udid, event->udid) == 0) {
|
| 1415 |
+
connected = 1;
|
| 1416 |
+
}
|
| 1417 |
+
} else if (event->event == IDEVICE_DEVICE_REMOVE) {
|
| 1418 |
+
if (strcmp(udid, event->udid) == 0) {
|
| 1419 |
+
connected = 0;
|
| 1420 |
+
printf("\n[disconnected]\n");
|
| 1421 |
+
handle_signal(SIGINT);
|
| 1422 |
+
}
|
| 1423 |
+
}
|
| 1424 |
+
}
|
| 1425 |
+
|
| 1426 |
+
int main(int argc, char** argv)
|
| 1427 |
+
{
|
| 1428 |
+
const char* appid = NULL;
|
| 1429 |
+
int ret = 0;
|
| 1430 |
+
idevice_t device = NULL;
|
| 1431 |
+
lockdownd_client_t lockdown = NULL;
|
| 1432 |
+
lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
|
| 1433 |
+
lockdownd_service_descriptor_t service = NULL;
|
| 1434 |
+
afc_client_t afc = NULL;
|
| 1435 |
+
house_arrest_client_t house_arrest = NULL;
|
| 1436 |
+
const char* service_name = AFC_SERVICE_NAME;
|
| 1437 |
+
int use_container = 0;
|
| 1438 |
+
|
| 1439 |
+
int c = 0;
|
| 1440 |
+
const struct option longopts[] = {
|
| 1441 |
+
{ "udid", required_argument, NULL, 'u' },
|
| 1442 |
+
{ "network", no_argument, NULL, 'n' },
|
| 1443 |
+
{ "help", no_argument, NULL, 'h' },
|
| 1444 |
+
{ "debug", no_argument, NULL, 'd' },
|
| 1445 |
+
{ "version", no_argument, NULL, 'v' },
|
| 1446 |
+
{ "documents", required_argument, NULL, OPT_DOCUMENTS },
|
| 1447 |
+
{ "container", required_argument, NULL, OPT_CONTAINER },
|
| 1448 |
+
{ NULL, 0, NULL, 0}
|
| 1449 |
+
};
|
| 1450 |
+
|
| 1451 |
+
signal(SIGTERM, handle_signal);
|
| 1452 |
+
#ifndef _WIN32
|
| 1453 |
+
signal(SIGQUIT, handle_signal);
|
| 1454 |
+
signal(SIGPIPE, SIG_IGN);
|
| 1455 |
+
#endif
|
| 1456 |
+
|
| 1457 |
+
while ((c = getopt_long(argc, argv, "du:nhv", longopts, NULL)) != -1) {
|
| 1458 |
+
switch (c) {
|
| 1459 |
+
case 'd':
|
| 1460 |
+
idevice_set_debug_level(1);
|
| 1461 |
+
break;
|
| 1462 |
+
case 'u':
|
| 1463 |
+
if (!*optarg) {
|
| 1464 |
+
fprintf(stderr, "ERROR: UDID must not be empty!\n");
|
| 1465 |
+
print_usage(argc, argv, 1);
|
| 1466 |
+
return 2;
|
| 1467 |
+
}
|
| 1468 |
+
udid = strdup(optarg);
|
| 1469 |
+
break;
|
| 1470 |
+
case 'n':
|
| 1471 |
+
use_network = 1;
|
| 1472 |
+
break;
|
| 1473 |
+
case 'h':
|
| 1474 |
+
print_usage(argc, argv, 0);
|
| 1475 |
+
return 0;
|
| 1476 |
+
case 'v':
|
| 1477 |
+
printf("%s %s", TOOL_NAME, PACKAGE_VERSION);
|
| 1478 |
+
#ifdef HAVE_READLINE
|
| 1479 |
+
printf(" (readline)");
|
| 1480 |
+
#endif
|
| 1481 |
+
printf("\n");
|
| 1482 |
+
return 0;
|
| 1483 |
+
case OPT_DOCUMENTS:
|
| 1484 |
+
if (!*optarg) {
|
| 1485 |
+
fprintf(stderr, "ERROR: '--documents' requires a non-empty app ID!\n");
|
| 1486 |
+
print_usage(argc, argv, 1);
|
| 1487 |
+
return 2;
|
| 1488 |
+
}
|
| 1489 |
+
appid = optarg;
|
| 1490 |
+
use_container = 0;
|
| 1491 |
+
break;
|
| 1492 |
+
case OPT_CONTAINER:
|
| 1493 |
+
if (!*optarg) {
|
| 1494 |
+
fprintf(stderr, "ERROR: '--container' requires a not-empty app ID!\n");
|
| 1495 |
+
print_usage(argc, argv, 1);
|
| 1496 |
+
return 2;
|
| 1497 |
+
}
|
| 1498 |
+
appid = optarg;
|
| 1499 |
+
use_container = 1;
|
| 1500 |
+
break;
|
| 1501 |
+
default:
|
| 1502 |
+
print_usage(argc, argv, 1);
|
| 1503 |
+
return 2;
|
| 1504 |
+
}
|
| 1505 |
+
}
|
| 1506 |
+
|
| 1507 |
+
argc -= optind;
|
| 1508 |
+
argv += optind;
|
| 1509 |
+
|
| 1510 |
+
int num = 0;
|
| 1511 |
+
idevice_info_t *devices = NULL;
|
| 1512 |
+
idevice_get_device_list_extended(&devices, &num);
|
| 1513 |
+
int count = 0;
|
| 1514 |
+
for (int i = 0; i < num; i++) {
|
| 1515 |
+
if (devices[i]->conn_type == CONNECTION_NETWORK && use_network) {
|
| 1516 |
+
count++;
|
| 1517 |
+
} else if (devices[i]->conn_type == CONNECTION_USBMUXD) {
|
| 1518 |
+
count++;
|
| 1519 |
+
}
|
| 1520 |
+
}
|
| 1521 |
+
idevice_device_list_extended_free(devices);
|
| 1522 |
+
if (count == 0) {
|
| 1523 |
+
fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to be available.\n");
|
| 1524 |
+
return 1;
|
| 1525 |
+
}
|
| 1526 |
+
|
| 1527 |
+
idevice_events_subscribe(&context, device_event_cb, NULL);
|
| 1528 |
+
|
| 1529 |
+
while (!connected && !stop_requested) {
|
| 1530 |
+
#ifdef _WIN32
|
| 1531 |
+
Sleep(100);
|
| 1532 |
+
#else
|
| 1533 |
+
usleep(100000);
|
| 1534 |
+
#endif
|
| 1535 |
+
}
|
| 1536 |
+
if (stop_requested) {
|
| 1537 |
+
return 0;
|
| 1538 |
+
}
|
| 1539 |
+
|
| 1540 |
+
ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
|
| 1541 |
+
if (ret != IDEVICE_E_SUCCESS) {
|
| 1542 |
+
if (udid) {
|
| 1543 |
+
fprintf(stderr, "ERROR: Device %s not found!\n", udid);
|
| 1544 |
+
} else {
|
| 1545 |
+
fprintf(stderr, "ERROR: No device found!\n");
|
| 1546 |
+
}
|
| 1547 |
+
return 1;
|
| 1548 |
+
}
|
| 1549 |
+
|
| 1550 |
+
do {
|
| 1551 |
+
if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) {
|
| 1552 |
+
fprintf(stderr, "ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(ldret), ldret);
|
| 1553 |
+
ret = 1;
|
| 1554 |
+
break;
|
| 1555 |
+
}
|
| 1556 |
+
|
| 1557 |
+
if (appid) {
|
| 1558 |
+
service_name = HOUSE_ARREST_SERVICE_NAME;
|
| 1559 |
+
}
|
| 1560 |
+
|
| 1561 |
+
ldret = lockdownd_start_service(lockdown, service_name, &service);
|
| 1562 |
+
if (ldret != LOCKDOWN_E_SUCCESS) {
|
| 1563 |
+
fprintf(stderr, "ERROR: Failed to start service %s: %s (%d)\n", service_name, lockdownd_strerror(ldret), ldret);
|
| 1564 |
+
ret = 1;
|
| 1565 |
+
break;
|
| 1566 |
+
}
|
| 1567 |
+
|
| 1568 |
+
if (appid) {
|
| 1569 |
+
house_arrest_client_new(device, service, &house_arrest);
|
| 1570 |
+
if (!house_arrest) {
|
| 1571 |
+
fprintf(stderr, "Could not start document sharing service!\n");
|
| 1572 |
+
ret = 1;
|
| 1573 |
+
break;
|
| 1574 |
+
}
|
| 1575 |
+
|
| 1576 |
+
if (house_arrest_send_command(house_arrest, use_container ? "VendContainer": "VendDocuments", appid) != HOUSE_ARREST_E_SUCCESS) {
|
| 1577 |
+
fprintf(stderr, "Could not send house_arrest command!\n");
|
| 1578 |
+
ret = 1;
|
| 1579 |
+
break;
|
| 1580 |
+
}
|
| 1581 |
+
|
| 1582 |
+
plist_t dict = NULL;
|
| 1583 |
+
if (house_arrest_get_result(house_arrest, &dict) != HOUSE_ARREST_E_SUCCESS) {
|
| 1584 |
+
fprintf(stderr, "Could not get result from document sharing service!\n");
|
| 1585 |
+
break;
|
| 1586 |
+
}
|
| 1587 |
+
plist_t node = plist_dict_get_item(dict, "Error");
|
| 1588 |
+
if (node) {
|
| 1589 |
+
char *str = NULL;
|
| 1590 |
+
plist_get_string_val(node, &str);
|
| 1591 |
+
fprintf(stderr, "ERROR: %s\n", str);
|
| 1592 |
+
if (str && !strcmp(str, "InstallationLookupFailed")) {
|
| 1593 |
+
fprintf(stderr, "The App '%s' is either not present on the device, or the 'UIFileSharingEnabled' key is not set in its Info.plist. Starting with iOS 8.3 this key is mandatory to allow access to an app's Documents folder.\n", appid);
|
| 1594 |
+
}
|
| 1595 |
+
free(str);
|
| 1596 |
+
plist_free(dict);
|
| 1597 |
+
break;
|
| 1598 |
+
}
|
| 1599 |
+
plist_free(dict);
|
| 1600 |
+
afc_client_new_from_house_arrest_client(house_arrest, &afc);
|
| 1601 |
+
} else {
|
| 1602 |
+
afc_client_new(device, service, &afc);
|
| 1603 |
+
}
|
| 1604 |
+
lockdownd_service_descriptor_free(service);
|
| 1605 |
+
lockdownd_client_free(lockdown);
|
| 1606 |
+
lockdown = NULL;
|
| 1607 |
+
|
| 1608 |
+
curdir = strdup("/");
|
| 1609 |
+
curdir_len = 1;
|
| 1610 |
+
|
| 1611 |
+
if (argc > 0) {
|
| 1612 |
+
// command line mode
|
| 1613 |
+
process_args(afc, argc, argv);
|
| 1614 |
+
} else {
|
| 1615 |
+
// interactive mode
|
| 1616 |
+
start_cmdline(afc);
|
| 1617 |
+
}
|
| 1618 |
+
|
| 1619 |
+
} while (0);
|
| 1620 |
+
|
| 1621 |
+
if (afc) {
|
| 1622 |
+
afc_client_free(afc);
|
| 1623 |
+
}
|
| 1624 |
+
if (lockdown) {
|
| 1625 |
+
lockdownd_client_free(lockdown);
|
| 1626 |
+
}
|
| 1627 |
+
idevice_free(device);
|
| 1628 |
+
|
| 1629 |
+
return ret;
|
| 1630 |
+
}
|
as-compiler-flag.m4
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
dnl as-compiler-flag.m4 0.1.0
|
| 2 |
+
|
| 3 |
+
dnl autostars m4 macro for detection of compiler flags
|
| 4 |
+
|
| 5 |
+
dnl David Schleef <ds@schleef.org>
|
| 6 |
+
|
| 7 |
+
dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $
|
| 8 |
+
|
| 9 |
+
dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED])
|
| 10 |
+
dnl Tries to compile with the given CFLAGS.
|
| 11 |
+
dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags,
|
| 12 |
+
dnl and ACTION-IF-NOT-ACCEPTED otherwise.
|
| 13 |
+
|
| 14 |
+
AC_DEFUN([AS_COMPILER_FLAG],
|
| 15 |
+
[
|
| 16 |
+
AC_MSG_CHECKING([to see if compiler understands $1])
|
| 17 |
+
|
| 18 |
+
save_CFLAGS="$CFLAGS"
|
| 19 |
+
CFLAGS="$CFLAGS $1"
|
| 20 |
+
|
| 21 |
+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])], [flag_ok=yes], [flag_ok=no])
|
| 22 |
+
CFLAGS="$save_CFLAGS"
|
| 23 |
+
|
| 24 |
+
if test "X$flag_ok" = Xyes ; then
|
| 25 |
+
m4_ifvaln([$2],[$2])
|
| 26 |
+
true
|
| 27 |
+
else
|
| 28 |
+
m4_ifvaln([$3],[$3])
|
| 29 |
+
true
|
| 30 |
+
fi
|
| 31 |
+
AC_MSG_RESULT([$flag_ok])
|
| 32 |
+
])
|
| 33 |
+
|
| 34 |
+
dnl AS_COMPILER_FLAGS(VAR, FLAGS)
|
| 35 |
+
dnl Tries to compile with the given CFLAGS.
|
| 36 |
+
|
| 37 |
+
AC_DEFUN([AS_COMPILER_FLAGS],
|
| 38 |
+
[
|
| 39 |
+
list=$2
|
| 40 |
+
flags_supported=""
|
| 41 |
+
flags_unsupported=""
|
| 42 |
+
AC_MSG_CHECKING([for supported compiler flags])
|
| 43 |
+
for each in $list
|
| 44 |
+
do
|
| 45 |
+
save_CFLAGS="$CFLAGS"
|
| 46 |
+
CFLAGS="$CFLAGS $each"
|
| 47 |
+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])], [flag_ok=yes], [flag_ok=no])
|
| 48 |
+
CFLAGS="$save_CFLAGS"
|
| 49 |
+
|
| 50 |
+
if test "X$flag_ok" = Xyes ; then
|
| 51 |
+
flags_supported="$flags_supported $each"
|
| 52 |
+
else
|
| 53 |
+
flags_unsupported="$flags_unsupported $each"
|
| 54 |
+
fi
|
| 55 |
+
done
|
| 56 |
+
AC_MSG_RESULT([$flags_supported])
|
| 57 |
+
if test "X$flags_unsupported" != X ; then
|
| 58 |
+
AC_MSG_WARN([unsupported compiler flags: $flags_unsupported])
|
| 59 |
+
fi
|
| 60 |
+
$1="$$1 $flags_supported"
|
| 61 |
+
])
|
| 62 |
+
|
asprintf.h
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef __ASPRINTF_H
|
| 2 |
+
#define __ASPRINTF_H
|
| 3 |
+
|
| 4 |
+
#ifdef HAVE_CONFIG_H
|
| 5 |
+
#include <config.h>
|
| 6 |
+
#endif
|
| 7 |
+
|
| 8 |
+
#include <stdio.h>
|
| 9 |
+
|
| 10 |
+
#ifndef HAVE_VASPRINTF
|
| 11 |
+
static inline int vasprintf(char **PTR, const char *TEMPLATE, va_list AP)
|
| 12 |
+
{
|
| 13 |
+
int res;
|
| 14 |
+
char buf[16];
|
| 15 |
+
res = vsnprintf(buf, 16, TEMPLATE, AP);
|
| 16 |
+
if (res > 0) {
|
| 17 |
+
*PTR = (char*)malloc(res+1);
|
| 18 |
+
res = vsnprintf(*PTR, res+1, TEMPLATE, AP);
|
| 19 |
+
}
|
| 20 |
+
return res;
|
| 21 |
+
}
|
| 22 |
+
#endif
|
| 23 |
+
|
| 24 |
+
#ifndef HAVE_ASPRINTF
|
| 25 |
+
static inline int asprintf(char **PTR, const char *TEMPLATE, ...)
|
| 26 |
+
{
|
| 27 |
+
int res;
|
| 28 |
+
va_list AP;
|
| 29 |
+
va_start(AP, TEMPLATE);
|
| 30 |
+
res = vasprintf(PTR, TEMPLATE, AP);
|
| 31 |
+
va_end(AP);
|
| 32 |
+
return res;
|
| 33 |
+
}
|
| 34 |
+
#endif
|
| 35 |
+
|
| 36 |
+
#endif /* ASPRINTF_H */
|
asr.c
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* asr.c
|
| 3 |
+
* Functions for handling asr connections
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
|
| 7 |
+
* Copyright (c) 2010 Joshua Hill. All Rights Reserved.
|
| 8 |
+
*
|
| 9 |
+
* This library is free software; you can redistribute it and/or
|
| 10 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 11 |
+
* License as published by the Free Software Foundation; either
|
| 12 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This library is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 17 |
+
* Lesser General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 20 |
+
* License along with this library; if not, write to the Free Software
|
| 21 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 22 |
+
*/
|
| 23 |
+
|
| 24 |
+
#ifdef HAVE_CONFIG_H
|
| 25 |
+
#include <config.h>
|
| 26 |
+
#endif
|
| 27 |
+
#include <stdio.h>
|
| 28 |
+
#include <stdlib.h>
|
| 29 |
+
#include <string.h>
|
| 30 |
+
#include <unistd.h>
|
| 31 |
+
#include <errno.h>
|
| 32 |
+
#include <libimobiledevice/libimobiledevice.h>
|
| 33 |
+
#ifdef HAVE_OPENSSL
|
| 34 |
+
#include <openssl/sha.h>
|
| 35 |
+
#else
|
| 36 |
+
#include "sha1.h"
|
| 37 |
+
#define SHA_CTX SHA1_CTX
|
| 38 |
+
#define SHA1_Init SHA1Init
|
| 39 |
+
#define SHA1_Update SHA1Update
|
| 40 |
+
#define SHA1_Final SHA1Final
|
| 41 |
+
#endif
|
| 42 |
+
|
| 43 |
+
#include "asr.h"
|
| 44 |
+
#include "idevicerestore.h"
|
| 45 |
+
#include "common.h"
|
| 46 |
+
|
| 47 |
+
#define ASR_VERSION 1
|
| 48 |
+
#define ASR_STREAM_ID 1
|
| 49 |
+
#define ASR_PORT 12345
|
| 50 |
+
#define ASR_BUFFER_SIZE 65536
|
| 51 |
+
#define ASR_FEC_SLICE_STRIDE 40
|
| 52 |
+
#define ASR_PACKETS_PER_FEC 25
|
| 53 |
+
#define ASR_PAYLOAD_PACKET_SIZE 1450
|
| 54 |
+
#define ASR_PAYLOAD_CHUNK_SIZE 131072
|
| 55 |
+
#define ASR_CHECKSUM_CHUNK_SIZE 131072
|
| 56 |
+
|
| 57 |
+
int asr_open_with_timeout(idevice_t device, asr_client_t* asr)
|
| 58 |
+
{
|
| 59 |
+
int i = 0;
|
| 60 |
+
int attempts = 10;
|
| 61 |
+
idevice_connection_t connection = NULL;
|
| 62 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 63 |
+
|
| 64 |
+
*asr = NULL;
|
| 65 |
+
|
| 66 |
+
if (device == NULL) {
|
| 67 |
+
return -1;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
debug("Connecting to ASR\n");
|
| 71 |
+
for (i = 1; i <= attempts; i++) {
|
| 72 |
+
device_error = idevice_connect(device, ASR_PORT, &connection);
|
| 73 |
+
if (device_error == IDEVICE_E_SUCCESS) {
|
| 74 |
+
break;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
if (i >= attempts) {
|
| 78 |
+
error("ERROR: Unable to connect to ASR client\n");
|
| 79 |
+
return -1;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
sleep(2);
|
| 83 |
+
debug("Retrying connection...\n");
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
asr_client_t asr_loc = (asr_client_t)malloc(sizeof(struct asr_client));
|
| 87 |
+
memset(asr_loc, '\0', sizeof(struct asr_client));
|
| 88 |
+
asr_loc->connection = connection;
|
| 89 |
+
|
| 90 |
+
/* receive Initiate command message */
|
| 91 |
+
plist_t data = NULL;
|
| 92 |
+
asr_loc->checksum_chunks = 0;
|
| 93 |
+
if (asr_receive(asr_loc, &data) < 0) {
|
| 94 |
+
error("ERROR: Unable to receive data from ASR\n");
|
| 95 |
+
asr_free(asr_loc);
|
| 96 |
+
plist_free(data);
|
| 97 |
+
return -1;
|
| 98 |
+
}
|
| 99 |
+
plist_t node;
|
| 100 |
+
node = plist_dict_get_item(data, "Command");
|
| 101 |
+
if (node && (plist_get_node_type(node) == PLIST_STRING)) {
|
| 102 |
+
char* strval = NULL;
|
| 103 |
+
plist_get_string_val(node, &strval);
|
| 104 |
+
if (strval && (strcmp(strval, "Initiate") != 0)) {
|
| 105 |
+
error("ERROR: unexpected ASR plist received:\n");
|
| 106 |
+
debug_plist(data);
|
| 107 |
+
plist_free(data);
|
| 108 |
+
asr_free(asr_loc);
|
| 109 |
+
return -1;
|
| 110 |
+
}
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
node = plist_dict_get_item(data, "Checksum Chunks");
|
| 114 |
+
if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
|
| 115 |
+
plist_get_bool_val(node, &(asr_loc->checksum_chunks));
|
| 116 |
+
}
|
| 117 |
+
plist_free(data);
|
| 118 |
+
|
| 119 |
+
*asr = asr_loc;
|
| 120 |
+
|
| 121 |
+
return 0;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t cbfunc, void* userdata)
|
| 125 |
+
{
|
| 126 |
+
if (!asr) {
|
| 127 |
+
return;
|
| 128 |
+
}
|
| 129 |
+
asr->progress_cb = cbfunc;
|
| 130 |
+
asr->progress_cb_data = userdata;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
int asr_receive(asr_client_t asr, plist_t* data)
|
| 134 |
+
{
|
| 135 |
+
uint32_t size = 0;
|
| 136 |
+
char* buffer = NULL;
|
| 137 |
+
plist_t request = NULL;
|
| 138 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 139 |
+
|
| 140 |
+
*data = NULL;
|
| 141 |
+
|
| 142 |
+
buffer = (char*)malloc(ASR_BUFFER_SIZE);
|
| 143 |
+
if (buffer == NULL) {
|
| 144 |
+
error("ERROR: Unable to allocate memory for ASR receive buffer\n");
|
| 145 |
+
return -1;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
device_error = idevice_connection_receive(asr->connection, buffer, ASR_BUFFER_SIZE, &size);
|
| 149 |
+
if (device_error != IDEVICE_E_SUCCESS) {
|
| 150 |
+
error("ERROR: Unable to receive data from ASR\n");
|
| 151 |
+
free(buffer);
|
| 152 |
+
return -1;
|
| 153 |
+
}
|
| 154 |
+
plist_from_xml(buffer, size, &request);
|
| 155 |
+
|
| 156 |
+
*data = request;
|
| 157 |
+
|
| 158 |
+
debug("Received %d bytes:\n", size);
|
| 159 |
+
if (idevicerestore_debug)
|
| 160 |
+
debug_plist(request);
|
| 161 |
+
free(buffer);
|
| 162 |
+
return 0;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
int asr_send(asr_client_t asr, plist_t data)
|
| 166 |
+
{
|
| 167 |
+
uint32_t size = 0;
|
| 168 |
+
char* buffer = NULL;
|
| 169 |
+
|
| 170 |
+
plist_to_xml(data, &buffer, &size);
|
| 171 |
+
if (asr_send_buffer(asr, buffer, size) < 0) {
|
| 172 |
+
error("ERROR: Unable to send plist to ASR\n");
|
| 173 |
+
free(buffer);
|
| 174 |
+
return -1;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
if (buffer)
|
| 178 |
+
free(buffer);
|
| 179 |
+
return 0;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size)
|
| 183 |
+
{
|
| 184 |
+
uint32_t bytes = 0;
|
| 185 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 186 |
+
|
| 187 |
+
device_error = idevice_connection_send(asr->connection, data, size, &bytes);
|
| 188 |
+
if (device_error != IDEVICE_E_SUCCESS || bytes != size) {
|
| 189 |
+
error("ERROR: Unable to send data to ASR. Sent %u of %u bytes.\n", bytes, size);
|
| 190 |
+
return -1;
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
return 0;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
void asr_free(asr_client_t asr)
|
| 197 |
+
{
|
| 198 |
+
if (asr != NULL) {
|
| 199 |
+
if (asr->connection != NULL) {
|
| 200 |
+
idevice_disconnect(asr->connection);
|
| 201 |
+
asr->connection = NULL;
|
| 202 |
+
}
|
| 203 |
+
free(asr);
|
| 204 |
+
asr = NULL;
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
int asr_perform_validation(asr_client_t asr, const char* filesystem)
|
| 209 |
+
{
|
| 210 |
+
FILE* file = NULL;
|
| 211 |
+
uint64_t length = 0;
|
| 212 |
+
char* command = NULL;
|
| 213 |
+
plist_t node = NULL;
|
| 214 |
+
plist_t packet = NULL;
|
| 215 |
+
plist_t packet_info = NULL;
|
| 216 |
+
plist_t payload_info = NULL;
|
| 217 |
+
int attempts = 0;
|
| 218 |
+
|
| 219 |
+
file = fopen(filesystem, "rb");
|
| 220 |
+
if (file == NULL) {
|
| 221 |
+
return -1;
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
#ifdef WIN32
|
| 225 |
+
length = _lseeki64(fileno(file), 0, SEEK_END);
|
| 226 |
+
_lseeki64(fileno(file), 0, SEEK_SET);
|
| 227 |
+
rewind(file);
|
| 228 |
+
#else
|
| 229 |
+
fseeko(file, 0, SEEK_END);
|
| 230 |
+
length = ftello(file);
|
| 231 |
+
fseeko(file, 0, SEEK_SET);
|
| 232 |
+
#endif
|
| 233 |
+
|
| 234 |
+
payload_info = plist_new_dict();
|
| 235 |
+
plist_dict_set_item(payload_info, "Port", plist_new_uint(1));
|
| 236 |
+
plist_dict_set_item(payload_info, "Size", plist_new_uint(length));
|
| 237 |
+
|
| 238 |
+
packet_info = plist_new_dict();
|
| 239 |
+
if (asr->checksum_chunks) {
|
| 240 |
+
plist_dict_set_item(packet_info, "Checksum Chunk Size", plist_new_uint(ASR_CHECKSUM_CHUNK_SIZE));
|
| 241 |
+
}
|
| 242 |
+
plist_dict_set_item(packet_info, "FEC Slice Stride", plist_new_uint(ASR_FEC_SLICE_STRIDE));
|
| 243 |
+
plist_dict_set_item(packet_info, "Packet Payload Size", plist_new_uint(ASR_PAYLOAD_PACKET_SIZE));
|
| 244 |
+
plist_dict_set_item(packet_info, "Packets Per FEC", plist_new_uint(ASR_PACKETS_PER_FEC));
|
| 245 |
+
plist_dict_set_item(packet_info, "Payload", payload_info);
|
| 246 |
+
plist_dict_set_item(packet_info, "Stream ID", plist_new_uint(ASR_STREAM_ID));
|
| 247 |
+
plist_dict_set_item(packet_info, "Version", plist_new_uint(ASR_VERSION));
|
| 248 |
+
|
| 249 |
+
if (asr_send(asr, packet_info)) {
|
| 250 |
+
error("ERROR: Unable to sent packet information to ASR\n");
|
| 251 |
+
plist_free(packet_info);
|
| 252 |
+
return -1;
|
| 253 |
+
}
|
| 254 |
+
plist_free(packet_info);
|
| 255 |
+
|
| 256 |
+
while (1) {
|
| 257 |
+
if (asr_receive(asr, &packet) < 0) {
|
| 258 |
+
error("ERROR: Unable to receive validation packet\n");
|
| 259 |
+
return -1;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
if (packet == NULL) {
|
| 263 |
+
if (attempts < 5) {
|
| 264 |
+
info("Retrying to receive validation packet... %d\n", attempts);
|
| 265 |
+
attempts++;
|
| 266 |
+
sleep(1);
|
| 267 |
+
continue;
|
| 268 |
+
}
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
attempts = 0;
|
| 272 |
+
|
| 273 |
+
node = plist_dict_get_item(packet, "Command");
|
| 274 |
+
if (!node || plist_get_node_type(node) != PLIST_STRING) {
|
| 275 |
+
error("ERROR: Unable to find command node in validation request\n");
|
| 276 |
+
return -1;
|
| 277 |
+
}
|
| 278 |
+
plist_get_string_val(node, &command);
|
| 279 |
+
|
| 280 |
+
if (!strcmp(command, "OOBData")) {
|
| 281 |
+
int ret = asr_handle_oob_data_request(asr, packet, file);
|
| 282 |
+
plist_free(packet);
|
| 283 |
+
if (ret < 0)
|
| 284 |
+
return ret;
|
| 285 |
+
} else if(!strcmp(command, "Payload")) {
|
| 286 |
+
plist_free(packet);
|
| 287 |
+
break;
|
| 288 |
+
|
| 289 |
+
} else {
|
| 290 |
+
error("ERROR: Unknown command received from ASR\n");
|
| 291 |
+
plist_free(packet);
|
| 292 |
+
return -1;
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
return 0;
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file)
|
| 300 |
+
{
|
| 301 |
+
char* oob_data = NULL;
|
| 302 |
+
uint64_t oob_offset = 0;
|
| 303 |
+
uint64_t oob_length = 0;
|
| 304 |
+
plist_t oob_length_node = NULL;
|
| 305 |
+
plist_t oob_offset_node = NULL;
|
| 306 |
+
|
| 307 |
+
oob_length_node = plist_dict_get_item(packet, "OOB Length");
|
| 308 |
+
if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) {
|
| 309 |
+
error("ERROR: Unable to find OOB data length\n");
|
| 310 |
+
return -1;
|
| 311 |
+
}
|
| 312 |
+
plist_get_uint_val(oob_length_node, &oob_length);
|
| 313 |
+
|
| 314 |
+
oob_offset_node = plist_dict_get_item(packet, "OOB Offset");
|
| 315 |
+
if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) {
|
| 316 |
+
error("ERROR: Unable to find OOB data offset\n");
|
| 317 |
+
return -1;
|
| 318 |
+
}
|
| 319 |
+
plist_get_uint_val(oob_offset_node, &oob_offset);
|
| 320 |
+
|
| 321 |
+
oob_data = (char*) malloc(oob_length);
|
| 322 |
+
if (oob_data == NULL) {
|
| 323 |
+
error("ERROR: Out of memory\n");
|
| 324 |
+
return -1;
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
#ifdef WIN32
|
| 328 |
+
rewind(file);
|
| 329 |
+
_lseeki64(fileno(file), oob_offset, SEEK_SET);
|
| 330 |
+
#else
|
| 331 |
+
fseeko(file, oob_offset, SEEK_SET);
|
| 332 |
+
#endif
|
| 333 |
+
if (fread(oob_data, 1, oob_length, file) != oob_length) {
|
| 334 |
+
error("ERROR: Unable to read OOB data from filesystem offset: %s\n", strerror(errno));
|
| 335 |
+
free(oob_data);
|
| 336 |
+
return -1;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
if (asr_send_buffer(asr, oob_data, oob_length) < 0) {
|
| 340 |
+
error("ERROR: Unable to send OOB data to ASR\n");
|
| 341 |
+
free(oob_data);
|
| 342 |
+
return -1;
|
| 343 |
+
}
|
| 344 |
+
free(oob_data);
|
| 345 |
+
return 0;
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
int asr_send_payload(asr_client_t asr, const char* filesystem)
|
| 349 |
+
{
|
| 350 |
+
char *data = NULL;
|
| 351 |
+
FILE* file = NULL;
|
| 352 |
+
uint64_t i, length, bytes = 0;
|
| 353 |
+
double progress = 0;
|
| 354 |
+
|
| 355 |
+
file = fopen(filesystem, "rb");
|
| 356 |
+
if (file == NULL) {
|
| 357 |
+
error("ERROR: Unable to open filesystem image %s: %s\n", filesystem, strerror(errno));
|
| 358 |
+
return -1;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
#ifdef WIN32
|
| 362 |
+
length = _lseeki64(fileno(file), 0, SEEK_END);
|
| 363 |
+
_lseeki64(fileno(file), 0, SEEK_SET);
|
| 364 |
+
rewind(file);
|
| 365 |
+
#else
|
| 366 |
+
fseeko(file, 0, SEEK_END);
|
| 367 |
+
length = ftello(file);
|
| 368 |
+
fseeko(file, 0, SEEK_SET);
|
| 369 |
+
#endif
|
| 370 |
+
|
| 371 |
+
int chunk = 0;
|
| 372 |
+
int add_checksum = 0;
|
| 373 |
+
data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE);
|
| 374 |
+
|
| 375 |
+
SHA_CTX sha1;
|
| 376 |
+
|
| 377 |
+
if (asr->checksum_chunks) {
|
| 378 |
+
SHA1_Init(&sha1);
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
int size = 0;
|
| 382 |
+
for (i = length; i > 0; i -= size) {
|
| 383 |
+
size = ASR_PAYLOAD_CHUNK_SIZE;
|
| 384 |
+
if (i < ASR_PAYLOAD_CHUNK_SIZE) {
|
| 385 |
+
size = i;
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
if (add_checksum) {
|
| 389 |
+
add_checksum = 0;
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
if (asr->checksum_chunks && ((chunk + size) >= ASR_CHECKSUM_CHUNK_SIZE)) {
|
| 393 |
+
// reduce packet size to match checksum chunk size
|
| 394 |
+
size -= ((chunk + size) - ASR_CHECKSUM_CHUNK_SIZE);
|
| 395 |
+
add_checksum = 1;
|
| 396 |
+
}
|
| 397 |
+
|
| 398 |
+
if (fread(data, 1, size, file) != (size_t)size) {
|
| 399 |
+
error("Error reading filesystem\n");
|
| 400 |
+
free(data);
|
| 401 |
+
fclose(file);
|
| 402 |
+
return -1;
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
if (asr_send_buffer(asr, data, size) < 0) {
|
| 406 |
+
error("ERROR: Unable to send filesystem payload\n");
|
| 407 |
+
free(data);
|
| 408 |
+
fclose(file);
|
| 409 |
+
return -1;
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
if (asr->checksum_chunks) {
|
| 413 |
+
SHA1_Update(&sha1, (unsigned char*)data, size);
|
| 414 |
+
chunk += size;
|
| 415 |
+
|
| 416 |
+
if (add_checksum) {
|
| 417 |
+
// get sha1 of last chunk
|
| 418 |
+
SHA1_Final((unsigned char*)data, &sha1);
|
| 419 |
+
|
| 420 |
+
// send checksum
|
| 421 |
+
if (asr_send_buffer(asr, data, 20) < 0) {
|
| 422 |
+
error("ERROR: Unable to send chunk checksum\n");
|
| 423 |
+
free(data);
|
| 424 |
+
fclose(file);
|
| 425 |
+
return -1;
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
// reset SHA1 context
|
| 429 |
+
SHA1_Init(&sha1);
|
| 430 |
+
|
| 431 |
+
// reset chunk byte counter
|
| 432 |
+
chunk = 0;
|
| 433 |
+
}
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
bytes += size;
|
| 437 |
+
progress = ((double)bytes / (double)length);
|
| 438 |
+
if (asr->progress_cb && ((int)(progress*100) > asr->lastprogress)) {
|
| 439 |
+
asr->progress_cb(progress, asr->progress_cb_data);
|
| 440 |
+
asr->lastprogress = (int)(progress*100);
|
| 441 |
+
}
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
// if last chunk wasn't terminated with a checksum we do it here
|
| 445 |
+
if (asr->checksum_chunks && !add_checksum) {
|
| 446 |
+
// get sha1 of last chunk
|
| 447 |
+
SHA1_Final((unsigned char*)data, &sha1);
|
| 448 |
+
|
| 449 |
+
// send checksum
|
| 450 |
+
if (asr_send_buffer(asr, data, 20) < 0) {
|
| 451 |
+
error("ERROR: Unable to send chunk checksum\n");
|
| 452 |
+
free(data);
|
| 453 |
+
fclose(file);
|
| 454 |
+
return -1;
|
| 455 |
+
}
|
| 456 |
+
}
|
| 457 |
+
|
| 458 |
+
free(data);
|
| 459 |
+
fclose(file);
|
| 460 |
+
return 0;
|
| 461 |
+
}
|
asr.h
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* asr.h
|
| 3 |
+
* Functions for handling asr connections
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012 Martin Szulecki. All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
|
| 7 |
+
* Copyright (c) 2010 Joshua Hill. All Rights Reserved.
|
| 8 |
+
*
|
| 9 |
+
* This library is free software; you can redistribute it and/or
|
| 10 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 11 |
+
* License as published by the Free Software Foundation; either
|
| 12 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This library is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 17 |
+
* Lesser General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 20 |
+
* License along with this library; if not, write to the Free Software
|
| 21 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 22 |
+
*/
|
| 23 |
+
|
| 24 |
+
#ifndef IDEVICERESTORE_ASR_H
|
| 25 |
+
#define IDEVICERESTORE_ASR_H
|
| 26 |
+
|
| 27 |
+
#ifdef __cplusplus
|
| 28 |
+
extern "C" {
|
| 29 |
+
#endif
|
| 30 |
+
|
| 31 |
+
#include <libimobiledevice/libimobiledevice.h>
|
| 32 |
+
|
| 33 |
+
typedef void (*asr_progress_cb_t)(double, void*);
|
| 34 |
+
|
| 35 |
+
struct asr_client {
|
| 36 |
+
idevice_connection_t connection;
|
| 37 |
+
uint8_t checksum_chunks;
|
| 38 |
+
int lastprogress;
|
| 39 |
+
asr_progress_cb_t progress_cb;
|
| 40 |
+
void* progress_cb_data;
|
| 41 |
+
};
|
| 42 |
+
typedef struct asr_client *asr_client_t;
|
| 43 |
+
|
| 44 |
+
int asr_open_with_timeout(idevice_t device, asr_client_t* asr);
|
| 45 |
+
void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t, void* userdata);
|
| 46 |
+
int asr_send(asr_client_t asr, plist_t data);
|
| 47 |
+
int asr_receive(asr_client_t asr, plist_t* data);
|
| 48 |
+
int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size);
|
| 49 |
+
void asr_free(asr_client_t asr);
|
| 50 |
+
int asr_perform_validation(asr_client_t asr, const char* filesystem);
|
| 51 |
+
int asr_send_payload(asr_client_t asr, const char* filesystem);
|
| 52 |
+
int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file);
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
#ifdef __cplusplus
|
| 56 |
+
}
|
| 57 |
+
#endif
|
| 58 |
+
|
| 59 |
+
#endif
|
autogen.sh
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
|
| 3 |
+
olddir=`pwd`
|
| 4 |
+
srcdir=`dirname $0`
|
| 5 |
+
test -z "$srcdir" && srcdir=.
|
| 6 |
+
|
| 7 |
+
(
|
| 8 |
+
cd "$srcdir"
|
| 9 |
+
|
| 10 |
+
gprefix=`which glibtoolize 2>&1 >/dev/null`
|
| 11 |
+
if [ $? -eq 0 ]; then
|
| 12 |
+
glibtoolize --force
|
| 13 |
+
else
|
| 14 |
+
libtoolize --force
|
| 15 |
+
fi
|
| 16 |
+
aclocal -I m4
|
| 17 |
+
autoheader
|
| 18 |
+
automake --add-missing
|
| 19 |
+
autoconf
|
| 20 |
+
|
| 21 |
+
cd "$olddir"
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
if [ -z "$NOCONFIGURE" ]; then
|
| 25 |
+
$srcdir/configure "$@"
|
| 26 |
+
fi
|
ax_pthread.m4
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ===========================================================================
|
| 2 |
+
# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
| 3 |
+
# ===========================================================================
|
| 4 |
+
#
|
| 5 |
+
# SYNOPSIS
|
| 6 |
+
#
|
| 7 |
+
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
| 8 |
+
#
|
| 9 |
+
# DESCRIPTION
|
| 10 |
+
#
|
| 11 |
+
# This macro figures out how to build C programs using POSIX threads. It
|
| 12 |
+
# sets the PTHREAD_LIBS output variable to the threads library and linker
|
| 13 |
+
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
|
| 14 |
+
# flags that are needed. (The user can also force certain compiler
|
| 15 |
+
# flags/libs to be tested by setting these environment variables.)
|
| 16 |
+
#
|
| 17 |
+
# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
|
| 18 |
+
# needed for multi-threaded programs (defaults to the value of CC
|
| 19 |
+
# respectively CXX otherwise). (This is necessary on e.g. AIX to use the
|
| 20 |
+
# special cc_r/CC_r compiler alias.)
|
| 21 |
+
#
|
| 22 |
+
# NOTE: You are assumed to not only compile your program with these flags,
|
| 23 |
+
# but also to link with them as well. For example, you might link with
|
| 24 |
+
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
| 25 |
+
# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
| 26 |
+
#
|
| 27 |
+
# If you are only building threaded programs, you may wish to use these
|
| 28 |
+
# variables in your default LIBS, CFLAGS, and CC:
|
| 29 |
+
#
|
| 30 |
+
# LIBS="$PTHREAD_LIBS $LIBS"
|
| 31 |
+
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
| 32 |
+
# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
|
| 33 |
+
# CC="$PTHREAD_CC"
|
| 34 |
+
# CXX="$PTHREAD_CXX"
|
| 35 |
+
#
|
| 36 |
+
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
| 37 |
+
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
|
| 38 |
+
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
| 39 |
+
#
|
| 40 |
+
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
| 41 |
+
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
| 42 |
+
# PTHREAD_CFLAGS.
|
| 43 |
+
#
|
| 44 |
+
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
|
| 45 |
+
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
|
| 46 |
+
# is not found. If ACTION-IF-FOUND is not specified, the default action
|
| 47 |
+
# will define HAVE_PTHREAD.
|
| 48 |
+
#
|
| 49 |
+
# Please let the authors know if this macro fails on any platform, or if
|
| 50 |
+
# you have any other suggestions or comments. This macro was based on work
|
| 51 |
+
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
|
| 52 |
+
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
|
| 53 |
+
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
|
| 54 |
+
# grateful for the helpful feedback of numerous users.
|
| 55 |
+
#
|
| 56 |
+
# Updated for Autoconf 2.68 by Daniel Richard G.
|
| 57 |
+
#
|
| 58 |
+
# LICENSE
|
| 59 |
+
#
|
| 60 |
+
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
| 61 |
+
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
|
| 62 |
+
# Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
|
| 63 |
+
#
|
| 64 |
+
# This program is free software: you can redistribute it and/or modify it
|
| 65 |
+
# under the terms of the GNU General Public License as published by the
|
| 66 |
+
# Free Software Foundation, either version 3 of the License, or (at your
|
| 67 |
+
# option) any later version.
|
| 68 |
+
#
|
| 69 |
+
# This program is distributed in the hope that it will be useful, but
|
| 70 |
+
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 71 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
| 72 |
+
# Public License for more details.
|
| 73 |
+
#
|
| 74 |
+
# You should have received a copy of the GNU General Public License along
|
| 75 |
+
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
| 76 |
+
#
|
| 77 |
+
# As a special exception, the respective Autoconf Macro's copyright owner
|
| 78 |
+
# gives unlimited permission to copy, distribute and modify the configure
|
| 79 |
+
# scripts that are the output of Autoconf when processing the Macro. You
|
| 80 |
+
# need not follow the terms of the GNU General Public License when using
|
| 81 |
+
# or distributing such scripts, even though portions of the text of the
|
| 82 |
+
# Macro appear in them. The GNU General Public License (GPL) does govern
|
| 83 |
+
# all other use of the material that constitutes the Autoconf Macro.
|
| 84 |
+
#
|
| 85 |
+
# This special exception to the GPL applies to versions of the Autoconf
|
| 86 |
+
# Macro released by the Autoconf Archive. When you make and distribute a
|
| 87 |
+
# modified version of the Autoconf Macro, you may extend this special
|
| 88 |
+
# exception to the GPL to apply to your modified version as well.
|
| 89 |
+
|
| 90 |
+
#serial 31
|
| 91 |
+
|
| 92 |
+
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
| 93 |
+
AC_DEFUN([AX_PTHREAD], [
|
| 94 |
+
AC_REQUIRE([AC_CANONICAL_HOST])
|
| 95 |
+
AC_REQUIRE([AC_PROG_CC])
|
| 96 |
+
AC_REQUIRE([AC_PROG_SED])
|
| 97 |
+
AC_LANG_PUSH([C])
|
| 98 |
+
ax_pthread_ok=no
|
| 99 |
+
|
| 100 |
+
# We used to check for pthread.h first, but this fails if pthread.h
|
| 101 |
+
# requires special compiler flags (e.g. on Tru64 or Sequent).
|
| 102 |
+
# It gets checked for in the link test anyway.
|
| 103 |
+
|
| 104 |
+
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
| 105 |
+
# etcetera environment variables, and if threads linking works using
|
| 106 |
+
# them:
|
| 107 |
+
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
|
| 108 |
+
ax_pthread_save_CC="$CC"
|
| 109 |
+
ax_pthread_save_CFLAGS="$CFLAGS"
|
| 110 |
+
ax_pthread_save_LIBS="$LIBS"
|
| 111 |
+
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
|
| 112 |
+
AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
|
| 113 |
+
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
| 114 |
+
LIBS="$PTHREAD_LIBS $LIBS"
|
| 115 |
+
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
|
| 116 |
+
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
|
| 117 |
+
AC_MSG_RESULT([$ax_pthread_ok])
|
| 118 |
+
if test "x$ax_pthread_ok" = "xno"; then
|
| 119 |
+
PTHREAD_LIBS=""
|
| 120 |
+
PTHREAD_CFLAGS=""
|
| 121 |
+
fi
|
| 122 |
+
CC="$ax_pthread_save_CC"
|
| 123 |
+
CFLAGS="$ax_pthread_save_CFLAGS"
|
| 124 |
+
LIBS="$ax_pthread_save_LIBS"
|
| 125 |
+
fi
|
| 126 |
+
|
| 127 |
+
# We must check for the threads library under a number of different
|
| 128 |
+
# names; the ordering is very important because some systems
|
| 129 |
+
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
| 130 |
+
# libraries is broken (non-POSIX).
|
| 131 |
+
|
| 132 |
+
# Create a list of thread flags to try. Items with a "," contain both
|
| 133 |
+
# C compiler flags (before ",") and linker flags (after ","). Other items
|
| 134 |
+
# starting with a "-" are C compiler flags, and remaining items are
|
| 135 |
+
# library names, except for "none" which indicates that we try without
|
| 136 |
+
# any flags at all, and "pthread-config" which is a program returning
|
| 137 |
+
# the flags for the Pth emulation library.
|
| 138 |
+
|
| 139 |
+
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
| 140 |
+
|
| 141 |
+
# The ordering *is* (sometimes) important. Some notes on the
|
| 142 |
+
# individual items follow:
|
| 143 |
+
|
| 144 |
+
# pthreads: AIX (must check this before -lpthread)
|
| 145 |
+
# none: in case threads are in libc; should be tried before -Kthread and
|
| 146 |
+
# other compiler flags to prevent continual compiler warnings
|
| 147 |
+
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
| 148 |
+
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
|
| 149 |
+
# (Note: HP C rejects this with "bad form for `-t' option")
|
| 150 |
+
# -pthreads: Solaris/gcc (Note: HP C also rejects)
|
| 151 |
+
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
| 152 |
+
# doesn't hurt to check since this sometimes defines pthreads and
|
| 153 |
+
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
|
| 154 |
+
# is present but should not be used directly; and before -mthreads,
|
| 155 |
+
# because the compiler interprets this as "-mt" + "-hreads")
|
| 156 |
+
# -mthreads: Mingw32/gcc, Lynx/gcc
|
| 157 |
+
# pthread: Linux, etcetera
|
| 158 |
+
# --thread-safe: KAI C++
|
| 159 |
+
# pthread-config: use pthread-config program (for GNU Pth library)
|
| 160 |
+
|
| 161 |
+
case $host_os in
|
| 162 |
+
|
| 163 |
+
freebsd*)
|
| 164 |
+
|
| 165 |
+
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
| 166 |
+
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
| 167 |
+
|
| 168 |
+
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
|
| 169 |
+
;;
|
| 170 |
+
|
| 171 |
+
hpux*)
|
| 172 |
+
|
| 173 |
+
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
|
| 174 |
+
# multi-threading and also sets -lpthread."
|
| 175 |
+
|
| 176 |
+
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
|
| 177 |
+
;;
|
| 178 |
+
|
| 179 |
+
openedition*)
|
| 180 |
+
|
| 181 |
+
# IBM z/OS requires a feature-test macro to be defined in order to
|
| 182 |
+
# enable POSIX threads at all, so give the user a hint if this is
|
| 183 |
+
# not set. (We don't define these ourselves, as they can affect
|
| 184 |
+
# other portions of the system API in unpredictable ways.)
|
| 185 |
+
|
| 186 |
+
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
|
| 187 |
+
[
|
| 188 |
+
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
|
| 189 |
+
AX_PTHREAD_ZOS_MISSING
|
| 190 |
+
# endif
|
| 191 |
+
],
|
| 192 |
+
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
|
| 193 |
+
;;
|
| 194 |
+
|
| 195 |
+
solaris*)
|
| 196 |
+
|
| 197 |
+
# On Solaris (at least, for some versions), libc contains stubbed
|
| 198 |
+
# (non-functional) versions of the pthreads routines, so link-based
|
| 199 |
+
# tests will erroneously succeed. (N.B.: The stubs are missing
|
| 200 |
+
# pthread_cleanup_push, or rather a function called by this macro,
|
| 201 |
+
# so we could check for that, but who knows whether they'll stub
|
| 202 |
+
# that too in a future libc.) So we'll check first for the
|
| 203 |
+
# standard Solaris way of linking pthreads (-mt -lpthread).
|
| 204 |
+
|
| 205 |
+
ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
|
| 206 |
+
;;
|
| 207 |
+
esac
|
| 208 |
+
|
| 209 |
+
# Are we compiling with Clang?
|
| 210 |
+
|
| 211 |
+
AC_CACHE_CHECK([whether $CC is Clang],
|
| 212 |
+
[ax_cv_PTHREAD_CLANG],
|
| 213 |
+
[ax_cv_PTHREAD_CLANG=no
|
| 214 |
+
# Note that Autoconf sets GCC=yes for Clang as well as GCC
|
| 215 |
+
if test "x$GCC" = "xyes"; then
|
| 216 |
+
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
|
| 217 |
+
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
|
| 218 |
+
# if defined(__clang__) && defined(__llvm__)
|
| 219 |
+
AX_PTHREAD_CC_IS_CLANG
|
| 220 |
+
# endif
|
| 221 |
+
],
|
| 222 |
+
[ax_cv_PTHREAD_CLANG=yes])
|
| 223 |
+
fi
|
| 224 |
+
])
|
| 225 |
+
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
|
| 229 |
+
|
| 230 |
+
# Note that for GCC and Clang -pthread generally implies -lpthread,
|
| 231 |
+
# except when -nostdlib is passed.
|
| 232 |
+
# This is problematic using libtool to build C++ shared libraries with pthread:
|
| 233 |
+
# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
|
| 234 |
+
# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
|
| 235 |
+
# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
|
| 236 |
+
# To solve this, first try -pthread together with -lpthread for GCC
|
| 237 |
+
|
| 238 |
+
AS_IF([test "x$GCC" = "xyes"],
|
| 239 |
+
[ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
|
| 240 |
+
|
| 241 |
+
# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
|
| 242 |
+
|
| 243 |
+
AS_IF([test "x$ax_pthread_clang" = "xyes"],
|
| 244 |
+
[ax_pthread_flags="-pthread,-lpthread -pthread"])
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
# The presence of a feature test macro requesting re-entrant function
|
| 248 |
+
# definitions is, on some systems, a strong hint that pthreads support is
|
| 249 |
+
# correctly enabled
|
| 250 |
+
|
| 251 |
+
case $host_os in
|
| 252 |
+
darwin* | hpux* | linux* | osf* | solaris*)
|
| 253 |
+
ax_pthread_check_macro="_REENTRANT"
|
| 254 |
+
;;
|
| 255 |
+
|
| 256 |
+
aix*)
|
| 257 |
+
ax_pthread_check_macro="_THREAD_SAFE"
|
| 258 |
+
;;
|
| 259 |
+
|
| 260 |
+
*)
|
| 261 |
+
ax_pthread_check_macro="--"
|
| 262 |
+
;;
|
| 263 |
+
esac
|
| 264 |
+
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
|
| 265 |
+
[ax_pthread_check_cond=0],
|
| 266 |
+
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
if test "x$ax_pthread_ok" = "xno"; then
|
| 270 |
+
for ax_pthread_try_flag in $ax_pthread_flags; do
|
| 271 |
+
|
| 272 |
+
case $ax_pthread_try_flag in
|
| 273 |
+
none)
|
| 274 |
+
AC_MSG_CHECKING([whether pthreads work without any flags])
|
| 275 |
+
;;
|
| 276 |
+
|
| 277 |
+
*,*)
|
| 278 |
+
PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
|
| 279 |
+
PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
|
| 280 |
+
AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
|
| 281 |
+
;;
|
| 282 |
+
|
| 283 |
+
-*)
|
| 284 |
+
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
|
| 285 |
+
PTHREAD_CFLAGS="$ax_pthread_try_flag"
|
| 286 |
+
;;
|
| 287 |
+
|
| 288 |
+
pthread-config)
|
| 289 |
+
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
|
| 290 |
+
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
|
| 291 |
+
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
| 292 |
+
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
| 293 |
+
;;
|
| 294 |
+
|
| 295 |
+
*)
|
| 296 |
+
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
|
| 297 |
+
PTHREAD_LIBS="-l$ax_pthread_try_flag"
|
| 298 |
+
;;
|
| 299 |
+
esac
|
| 300 |
+
|
| 301 |
+
ax_pthread_save_CFLAGS="$CFLAGS"
|
| 302 |
+
ax_pthread_save_LIBS="$LIBS"
|
| 303 |
+
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
| 304 |
+
LIBS="$PTHREAD_LIBS $LIBS"
|
| 305 |
+
|
| 306 |
+
# Check for various functions. We must include pthread.h,
|
| 307 |
+
# since some functions may be macros. (On the Sequent, we
|
| 308 |
+
# need a special flag -Kthread to make this header compile.)
|
| 309 |
+
# We check for pthread_join because it is in -lpthread on IRIX
|
| 310 |
+
# while pthread_create is in libc. We check for pthread_attr_init
|
| 311 |
+
# due to DEC craziness with -lpthreads. We check for
|
| 312 |
+
# pthread_cleanup_push because it is one of the few pthread
|
| 313 |
+
# functions on Solaris that doesn't have a non-functional libc stub.
|
| 314 |
+
# We try pthread_create on general principles.
|
| 315 |
+
|
| 316 |
+
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
|
| 317 |
+
# if $ax_pthread_check_cond
|
| 318 |
+
# error "$ax_pthread_check_macro must be defined"
|
| 319 |
+
# endif
|
| 320 |
+
static void *some_global = NULL;
|
| 321 |
+
static void routine(void *a)
|
| 322 |
+
{
|
| 323 |
+
/* To avoid any unused-parameter or
|
| 324 |
+
unused-but-set-parameter warning. */
|
| 325 |
+
some_global = a;
|
| 326 |
+
}
|
| 327 |
+
static void *start_routine(void *a) { return a; }],
|
| 328 |
+
[pthread_t th; pthread_attr_t attr;
|
| 329 |
+
pthread_create(&th, 0, start_routine, 0);
|
| 330 |
+
pthread_join(th, 0);
|
| 331 |
+
pthread_attr_init(&attr);
|
| 332 |
+
pthread_cleanup_push(routine, 0);
|
| 333 |
+
pthread_cleanup_pop(0) /* ; */])],
|
| 334 |
+
[ax_pthread_ok=yes],
|
| 335 |
+
[])
|
| 336 |
+
|
| 337 |
+
CFLAGS="$ax_pthread_save_CFLAGS"
|
| 338 |
+
LIBS="$ax_pthread_save_LIBS"
|
| 339 |
+
|
| 340 |
+
AC_MSG_RESULT([$ax_pthread_ok])
|
| 341 |
+
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
|
| 342 |
+
|
| 343 |
+
PTHREAD_LIBS=""
|
| 344 |
+
PTHREAD_CFLAGS=""
|
| 345 |
+
done
|
| 346 |
+
fi
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
# Clang needs special handling, because older versions handle the -pthread
|
| 350 |
+
# option in a rather... idiosyncratic way
|
| 351 |
+
|
| 352 |
+
if test "x$ax_pthread_clang" = "xyes"; then
|
| 353 |
+
|
| 354 |
+
# Clang takes -pthread; it has never supported any other flag
|
| 355 |
+
|
| 356 |
+
# (Note 1: This will need to be revisited if a system that Clang
|
| 357 |
+
# supports has POSIX threads in a separate library. This tends not
|
| 358 |
+
# to be the way of modern systems, but it's conceivable.)
|
| 359 |
+
|
| 360 |
+
# (Note 2: On some systems, notably Darwin, -pthread is not needed
|
| 361 |
+
# to get POSIX threads support; the API is always present and
|
| 362 |
+
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
|
| 363 |
+
# -pthread does define _REENTRANT, and while the Darwin headers
|
| 364 |
+
# ignore this macro, third-party headers might not.)
|
| 365 |
+
|
| 366 |
+
# However, older versions of Clang make a point of warning the user
|
| 367 |
+
# that, in an invocation where only linking and no compilation is
|
| 368 |
+
# taking place, the -pthread option has no effect ("argument unused
|
| 369 |
+
# during compilation"). They expect -pthread to be passed in only
|
| 370 |
+
# when source code is being compiled.
|
| 371 |
+
#
|
| 372 |
+
# Problem is, this is at odds with the way Automake and most other
|
| 373 |
+
# C build frameworks function, which is that the same flags used in
|
| 374 |
+
# compilation (CFLAGS) are also used in linking. Many systems
|
| 375 |
+
# supported by AX_PTHREAD require exactly this for POSIX threads
|
| 376 |
+
# support, and in fact it is often not straightforward to specify a
|
| 377 |
+
# flag that is used only in the compilation phase and not in
|
| 378 |
+
# linking. Such a scenario is extremely rare in practice.
|
| 379 |
+
#
|
| 380 |
+
# Even though use of the -pthread flag in linking would only print
|
| 381 |
+
# a warning, this can be a nuisance for well-run software projects
|
| 382 |
+
# that build with -Werror. So if the active version of Clang has
|
| 383 |
+
# this misfeature, we search for an option to squash it.
|
| 384 |
+
|
| 385 |
+
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
|
| 386 |
+
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
|
| 387 |
+
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
|
| 388 |
+
# Create an alternate version of $ac_link that compiles and
|
| 389 |
+
# links in two steps (.c -> .o, .o -> exe) instead of one
|
| 390 |
+
# (.c -> exe), because the warning occurs only in the second
|
| 391 |
+
# step
|
| 392 |
+
ax_pthread_save_ac_link="$ac_link"
|
| 393 |
+
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
|
| 394 |
+
ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
|
| 395 |
+
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
|
| 396 |
+
ax_pthread_save_CFLAGS="$CFLAGS"
|
| 397 |
+
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
|
| 398 |
+
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
|
| 399 |
+
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
|
| 400 |
+
ac_link="$ax_pthread_save_ac_link"
|
| 401 |
+
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
| 402 |
+
[ac_link="$ax_pthread_2step_ac_link"
|
| 403 |
+
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
| 404 |
+
[break])
|
| 405 |
+
])
|
| 406 |
+
done
|
| 407 |
+
ac_link="$ax_pthread_save_ac_link"
|
| 408 |
+
CFLAGS="$ax_pthread_save_CFLAGS"
|
| 409 |
+
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
|
| 410 |
+
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
|
| 411 |
+
])
|
| 412 |
+
|
| 413 |
+
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
|
| 414 |
+
no | unknown) ;;
|
| 415 |
+
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
|
| 416 |
+
esac
|
| 417 |
+
|
| 418 |
+
fi # $ax_pthread_clang = yes
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
# Various other checks:
|
| 423 |
+
if test "x$ax_pthread_ok" = "xyes"; then
|
| 424 |
+
ax_pthread_save_CFLAGS="$CFLAGS"
|
| 425 |
+
ax_pthread_save_LIBS="$LIBS"
|
| 426 |
+
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
| 427 |
+
LIBS="$PTHREAD_LIBS $LIBS"
|
| 428 |
+
|
| 429 |
+
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
| 430 |
+
AC_CACHE_CHECK([for joinable pthread attribute],
|
| 431 |
+
[ax_cv_PTHREAD_JOINABLE_ATTR],
|
| 432 |
+
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
|
| 433 |
+
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
| 434 |
+
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
| 435 |
+
[int attr = $ax_pthread_attr; return attr /* ; */])],
|
| 436 |
+
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
|
| 437 |
+
[])
|
| 438 |
+
done
|
| 439 |
+
])
|
| 440 |
+
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
|
| 441 |
+
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
|
| 442 |
+
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
|
| 443 |
+
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
|
| 444 |
+
[$ax_cv_PTHREAD_JOINABLE_ATTR],
|
| 445 |
+
[Define to necessary symbol if this constant
|
| 446 |
+
uses a non-standard name on your system.])
|
| 447 |
+
ax_pthread_joinable_attr_defined=yes
|
| 448 |
+
])
|
| 449 |
+
|
| 450 |
+
AC_CACHE_CHECK([whether more special flags are required for pthreads],
|
| 451 |
+
[ax_cv_PTHREAD_SPECIAL_FLAGS],
|
| 452 |
+
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
|
| 453 |
+
case $host_os in
|
| 454 |
+
solaris*)
|
| 455 |
+
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
|
| 456 |
+
;;
|
| 457 |
+
esac
|
| 458 |
+
])
|
| 459 |
+
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
|
| 460 |
+
test "x$ax_pthread_special_flags_added" != "xyes"],
|
| 461 |
+
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
|
| 462 |
+
ax_pthread_special_flags_added=yes])
|
| 463 |
+
|
| 464 |
+
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
| 465 |
+
[ax_cv_PTHREAD_PRIO_INHERIT],
|
| 466 |
+
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
| 467 |
+
[[int i = PTHREAD_PRIO_INHERIT;
|
| 468 |
+
return i;]])],
|
| 469 |
+
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
| 470 |
+
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
| 471 |
+
])
|
| 472 |
+
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
|
| 473 |
+
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
|
| 474 |
+
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
|
| 475 |
+
ax_pthread_prio_inherit_defined=yes
|
| 476 |
+
])
|
| 477 |
+
|
| 478 |
+
CFLAGS="$ax_pthread_save_CFLAGS"
|
| 479 |
+
LIBS="$ax_pthread_save_LIBS"
|
| 480 |
+
|
| 481 |
+
# More AIX lossage: compile with *_r variant
|
| 482 |
+
if test "x$GCC" != "xyes"; then
|
| 483 |
+
case $host_os in
|
| 484 |
+
aix*)
|
| 485 |
+
AS_CASE(["x/$CC"],
|
| 486 |
+
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
| 487 |
+
[#handle absolute path differently from PATH based program lookup
|
| 488 |
+
AS_CASE(["x$CC"],
|
| 489 |
+
[x/*],
|
| 490 |
+
[
|
| 491 |
+
AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
|
| 492 |
+
AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
|
| 493 |
+
],
|
| 494 |
+
[
|
| 495 |
+
AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
|
| 496 |
+
AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
|
| 497 |
+
]
|
| 498 |
+
)
|
| 499 |
+
])
|
| 500 |
+
;;
|
| 501 |
+
esac
|
| 502 |
+
fi
|
| 503 |
+
fi
|
| 504 |
+
|
| 505 |
+
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
|
| 506 |
+
test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
|
| 507 |
+
|
| 508 |
+
AC_SUBST([PTHREAD_LIBS])
|
| 509 |
+
AC_SUBST([PTHREAD_CFLAGS])
|
| 510 |
+
AC_SUBST([PTHREAD_CC])
|
| 511 |
+
AC_SUBST([PTHREAD_CXX])
|
| 512 |
+
|
| 513 |
+
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
| 514 |
+
if test "x$ax_pthread_ok" = "xyes"; then
|
| 515 |
+
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
|
| 516 |
+
:
|
| 517 |
+
else
|
| 518 |
+
ax_pthread_ok=no
|
| 519 |
+
$2
|
| 520 |
+
fi
|
| 521 |
+
AC_LANG_POP
|
| 522 |
+
])dnl AX_PTHREAD
|
ax_python_devel.m4
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ===========================================================================
|
| 2 |
+
# https://www.gnu.org/software/autoconf-archive/ax_python_devel.html
|
| 3 |
+
# ===========================================================================
|
| 4 |
+
#
|
| 5 |
+
# SYNOPSIS
|
| 6 |
+
#
|
| 7 |
+
# AX_PYTHON_DEVEL([version[,optional]])
|
| 8 |
+
#
|
| 9 |
+
# DESCRIPTION
|
| 10 |
+
#
|
| 11 |
+
# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
|
| 12 |
+
# in your configure.ac.
|
| 13 |
+
#
|
| 14 |
+
# This macro checks for Python and tries to get the include path to
|
| 15 |
+
# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LIBS) output
|
| 16 |
+
# variables. It also exports $(PYTHON_EXTRA_LIBS) and
|
| 17 |
+
# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
|
| 18 |
+
#
|
| 19 |
+
# You can search for some particular version of Python by passing a
|
| 20 |
+
# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
|
| 21 |
+
# note that you *have* to pass also an operator along with the version to
|
| 22 |
+
# match, and pay special attention to the single quotes surrounding the
|
| 23 |
+
# version number. Don't use "PYTHON_VERSION" for this: that environment
|
| 24 |
+
# variable is declared as precious and thus reserved for the end-user.
|
| 25 |
+
#
|
| 26 |
+
# By default this will fail if it does not detect a development version of
|
| 27 |
+
# python. If you want it to continue, set optional to true, like
|
| 28 |
+
# AX_PYTHON_DEVEL([], [true]). The ax_python_devel_found variable will be
|
| 29 |
+
# "no" if it fails.
|
| 30 |
+
#
|
| 31 |
+
# This macro should work for all versions of Python >= 2.1.0. As an end
|
| 32 |
+
# user, you can disable the check for the python version by setting the
|
| 33 |
+
# PYTHON_NOVERSIONCHECK environment variable to something else than the
|
| 34 |
+
# empty string.
|
| 35 |
+
#
|
| 36 |
+
# If you need to use this macro for an older Python version, please
|
| 37 |
+
# contact the authors. We're always open for feedback.
|
| 38 |
+
#
|
| 39 |
+
# LICENSE
|
| 40 |
+
#
|
| 41 |
+
# Copyright (c) 2009 Sebastian Huber <sebastian-huber@web.de>
|
| 42 |
+
# Copyright (c) 2009 Alan W. Irwin
|
| 43 |
+
# Copyright (c) 2009 Rafael Laboissiere <rafael@laboissiere.net>
|
| 44 |
+
# Copyright (c) 2009 Andrew Collier
|
| 45 |
+
# Copyright (c) 2009 Matteo Settenvini <matteo@member.fsf.org>
|
| 46 |
+
# Copyright (c) 2009 Horst Knorr <hk_classes@knoda.org>
|
| 47 |
+
# Copyright (c) 2013 Daniel Mullner <muellner@math.stanford.edu>
|
| 48 |
+
#
|
| 49 |
+
# This program is free software: you can redistribute it and/or modify it
|
| 50 |
+
# under the terms of the GNU General Public License as published by the
|
| 51 |
+
# Free Software Foundation, either version 3 of the License, or (at your
|
| 52 |
+
# option) any later version.
|
| 53 |
+
#
|
| 54 |
+
# This program is distributed in the hope that it will be useful, but
|
| 55 |
+
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 56 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
| 57 |
+
# Public License for more details.
|
| 58 |
+
#
|
| 59 |
+
# You should have received a copy of the GNU General Public License along
|
| 60 |
+
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
| 61 |
+
#
|
| 62 |
+
# As a special exception, the respective Autoconf Macro's copyright owner
|
| 63 |
+
# gives unlimited permission to copy, distribute and modify the configure
|
| 64 |
+
# scripts that are the output of Autoconf when processing the Macro. You
|
| 65 |
+
# need not follow the terms of the GNU General Public License when using
|
| 66 |
+
# or distributing such scripts, even though portions of the text of the
|
| 67 |
+
# Macro appear in them. The GNU General Public License (GPL) does govern
|
| 68 |
+
# all other use of the material that constitutes the Autoconf Macro.
|
| 69 |
+
#
|
| 70 |
+
# This special exception to the GPL applies to versions of the Autoconf
|
| 71 |
+
# Macro released by the Autoconf Archive. When you make and distribute a
|
| 72 |
+
# modified version of the Autoconf Macro, you may extend this special
|
| 73 |
+
# exception to the GPL to apply to your modified version as well.
|
| 74 |
+
|
| 75 |
+
#serial 37
|
| 76 |
+
|
| 77 |
+
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
|
| 78 |
+
AC_DEFUN([AX_PYTHON_DEVEL],[
|
| 79 |
+
# Get whether it's optional
|
| 80 |
+
if test -z "$2"; then
|
| 81 |
+
ax_python_devel_optional=false
|
| 82 |
+
else
|
| 83 |
+
ax_python_devel_optional=$2
|
| 84 |
+
fi
|
| 85 |
+
ax_python_devel_found=yes
|
| 86 |
+
|
| 87 |
+
#
|
| 88 |
+
# Allow the use of a (user set) custom python version
|
| 89 |
+
#
|
| 90 |
+
AC_ARG_VAR([PYTHON_VERSION],[The installed Python
|
| 91 |
+
version to use, for example '2.3'. This string
|
| 92 |
+
will be appended to the Python interpreter
|
| 93 |
+
canonical name.])
|
| 94 |
+
|
| 95 |
+
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
|
| 96 |
+
if test -z "$PYTHON"; then
|
| 97 |
+
AC_MSG_WARN([Cannot find python$PYTHON_VERSION in your system path])
|
| 98 |
+
if ! $ax_python_devel_optional; then
|
| 99 |
+
AC_MSG_ERROR([Giving up, python development not available])
|
| 100 |
+
fi
|
| 101 |
+
ax_python_devel_found=no
|
| 102 |
+
PYTHON_VERSION=""
|
| 103 |
+
fi
|
| 104 |
+
|
| 105 |
+
if test $ax_python_devel_found = yes; then
|
| 106 |
+
#
|
| 107 |
+
# Check for a version of Python >= 2.1.0
|
| 108 |
+
#
|
| 109 |
+
AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
|
| 110 |
+
ac_supports_python_ver=`$PYTHON -c "import sys; \
|
| 111 |
+
ver = sys.version.split ()[[0]]; \
|
| 112 |
+
print (ver >= '2.1.0')"`
|
| 113 |
+
if test "$ac_supports_python_ver" != "True"; then
|
| 114 |
+
if test -z "$PYTHON_NOVERSIONCHECK"; then
|
| 115 |
+
AC_MSG_RESULT([no])
|
| 116 |
+
AC_MSG_WARN([
|
| 117 |
+
This version of the AC@&t@_PYTHON_DEVEL macro
|
| 118 |
+
doesn't work properly with versions of Python before
|
| 119 |
+
2.1.0. You may need to re-run configure, setting the
|
| 120 |
+
variables PYTHON_CPPFLAGS, PYTHON_LIBS, PYTHON_SITE_PKG,
|
| 121 |
+
PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
|
| 122 |
+
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
|
| 123 |
+
to something else than an empty string.
|
| 124 |
+
])
|
| 125 |
+
if ! $ax_python_devel_optional; then
|
| 126 |
+
AC_MSG_FAILURE([Giving up])
|
| 127 |
+
fi
|
| 128 |
+
ax_python_devel_found=no
|
| 129 |
+
PYTHON_VERSION=""
|
| 130 |
+
else
|
| 131 |
+
AC_MSG_RESULT([skip at user request])
|
| 132 |
+
fi
|
| 133 |
+
else
|
| 134 |
+
AC_MSG_RESULT([yes])
|
| 135 |
+
fi
|
| 136 |
+
fi
|
| 137 |
+
|
| 138 |
+
if test $ax_python_devel_found = yes; then
|
| 139 |
+
#
|
| 140 |
+
# If the macro parameter ``version'' is set, honour it.
|
| 141 |
+
# A Python shim class, VPy, is used to implement correct version comparisons via
|
| 142 |
+
# string expressions, since e.g. a naive textual ">= 2.7.3" won't work for
|
| 143 |
+
# Python 2.7.10 (the ".1" being evaluated as less than ".3").
|
| 144 |
+
#
|
| 145 |
+
if test -n "$1"; then
|
| 146 |
+
AC_MSG_CHECKING([for a version of Python $1])
|
| 147 |
+
cat << EOF > ax_python_devel_vpy.py
|
| 148 |
+
class VPy:
|
| 149 |
+
def vtup(self, s):
|
| 150 |
+
return tuple(map(int, s.strip().replace("rc", ".").split(".")))
|
| 151 |
+
def __init__(self):
|
| 152 |
+
import sys
|
| 153 |
+
self.vpy = tuple(sys.version_info)[[:3]]
|
| 154 |
+
def __eq__(self, s):
|
| 155 |
+
return self.vpy == self.vtup(s)
|
| 156 |
+
def __ne__(self, s):
|
| 157 |
+
return self.vpy != self.vtup(s)
|
| 158 |
+
def __lt__(self, s):
|
| 159 |
+
return self.vpy < self.vtup(s)
|
| 160 |
+
def __gt__(self, s):
|
| 161 |
+
return self.vpy > self.vtup(s)
|
| 162 |
+
def __le__(self, s):
|
| 163 |
+
return self.vpy <= self.vtup(s)
|
| 164 |
+
def __ge__(self, s):
|
| 165 |
+
return self.vpy >= self.vtup(s)
|
| 166 |
+
EOF
|
| 167 |
+
ac_supports_python_ver=`$PYTHON -c "import ax_python_devel_vpy; \
|
| 168 |
+
ver = ax_python_devel_vpy.VPy(); \
|
| 169 |
+
print (ver $1)"`
|
| 170 |
+
rm -rf ax_python_devel_vpy*.py* __pycache__/ax_python_devel_vpy*.py*
|
| 171 |
+
if test "$ac_supports_python_ver" = "True"; then
|
| 172 |
+
AC_MSG_RESULT([yes])
|
| 173 |
+
else
|
| 174 |
+
AC_MSG_RESULT([no])
|
| 175 |
+
AC_MSG_WARN([this package requires Python $1.
|
| 176 |
+
If you have it installed, but it isn't the default Python
|
| 177 |
+
interpreter in your system path, please pass the PYTHON_VERSION
|
| 178 |
+
variable to configure. See ``configure --help'' for reference.
|
| 179 |
+
])
|
| 180 |
+
if ! $ax_python_devel_optional; then
|
| 181 |
+
AC_MSG_ERROR([Giving up])
|
| 182 |
+
fi
|
| 183 |
+
ax_python_devel_found=no
|
| 184 |
+
PYTHON_VERSION=""
|
| 185 |
+
fi
|
| 186 |
+
fi
|
| 187 |
+
fi
|
| 188 |
+
|
| 189 |
+
if test $ax_python_devel_found = yes; then
|
| 190 |
+
#
|
| 191 |
+
# Check if you have distutils, else fail
|
| 192 |
+
#
|
| 193 |
+
AC_MSG_CHECKING([for the sysconfig Python package])
|
| 194 |
+
ac_sysconfig_result=`$PYTHON -c "import sysconfig" 2>&1`
|
| 195 |
+
if test $? -eq 0; then
|
| 196 |
+
AC_MSG_RESULT([yes])
|
| 197 |
+
IMPORT_SYSCONFIG="import sysconfig"
|
| 198 |
+
else
|
| 199 |
+
AC_MSG_RESULT([no])
|
| 200 |
+
|
| 201 |
+
AC_MSG_CHECKING([for the distutils Python package])
|
| 202 |
+
ac_sysconfig_result=`$PYTHON -c "from distutils import sysconfig" 2>&1`
|
| 203 |
+
if test $? -eq 0; then
|
| 204 |
+
AC_MSG_RESULT([yes])
|
| 205 |
+
IMPORT_SYSCONFIG="from distutils import sysconfig"
|
| 206 |
+
else
|
| 207 |
+
AC_MSG_WARN([cannot import Python module "distutils".
|
| 208 |
+
Please check your Python installation. The error was:
|
| 209 |
+
$ac_sysconfig_result])
|
| 210 |
+
if ! $ax_python_devel_optional; then
|
| 211 |
+
AC_MSG_ERROR([Giving up])
|
| 212 |
+
fi
|
| 213 |
+
ax_python_devel_found=no
|
| 214 |
+
PYTHON_VERSION=""
|
| 215 |
+
fi
|
| 216 |
+
fi
|
| 217 |
+
fi
|
| 218 |
+
|
| 219 |
+
if test $ax_python_devel_found = yes; then
|
| 220 |
+
#
|
| 221 |
+
# Check for Python include path
|
| 222 |
+
#
|
| 223 |
+
AC_MSG_CHECKING([for Python include path])
|
| 224 |
+
if test -z "$PYTHON_CPPFLAGS"; then
|
| 225 |
+
if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
|
| 226 |
+
# sysconfig module has different functions
|
| 227 |
+
python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
| 228 |
+
print (sysconfig.get_path ('include'));"`
|
| 229 |
+
plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
| 230 |
+
print (sysconfig.get_path ('platinclude'));"`
|
| 231 |
+
else
|
| 232 |
+
# old distutils way
|
| 233 |
+
python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
| 234 |
+
print (sysconfig.get_python_inc ());"`
|
| 235 |
+
plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
| 236 |
+
print (sysconfig.get_python_inc (plat_specific=1));"`
|
| 237 |
+
fi
|
| 238 |
+
if test -n "${python_path}"; then
|
| 239 |
+
if test "${plat_python_path}" != "${python_path}"; then
|
| 240 |
+
python_path="-I$python_path -I$plat_python_path"
|
| 241 |
+
else
|
| 242 |
+
python_path="-I$python_path"
|
| 243 |
+
fi
|
| 244 |
+
fi
|
| 245 |
+
PYTHON_CPPFLAGS=$python_path
|
| 246 |
+
fi
|
| 247 |
+
AC_MSG_RESULT([$PYTHON_CPPFLAGS])
|
| 248 |
+
AC_SUBST([PYTHON_CPPFLAGS])
|
| 249 |
+
|
| 250 |
+
#
|
| 251 |
+
# Check for Python library path
|
| 252 |
+
#
|
| 253 |
+
AC_MSG_CHECKING([for Python library path])
|
| 254 |
+
if test -z "$PYTHON_LIBS"; then
|
| 255 |
+
# (makes two attempts to ensure we've got a version number
|
| 256 |
+
# from the interpreter)
|
| 257 |
+
ac_python_version=`cat<<EOD | $PYTHON -
|
| 258 |
+
|
| 259 |
+
# join all versioning strings, on some systems
|
| 260 |
+
# major/minor numbers could be in different list elements
|
| 261 |
+
from sysconfig import *
|
| 262 |
+
e = get_config_var('VERSION')
|
| 263 |
+
if e is not None:
|
| 264 |
+
print(e)
|
| 265 |
+
EOD`
|
| 266 |
+
|
| 267 |
+
if test -z "$ac_python_version"; then
|
| 268 |
+
if test -n "$PYTHON_VERSION"; then
|
| 269 |
+
ac_python_version=$PYTHON_VERSION
|
| 270 |
+
else
|
| 271 |
+
ac_python_version=`$PYTHON -c "import sys; \
|
| 272 |
+
print ("%d.%d" % sys.version_info[[:2]])"`
|
| 273 |
+
fi
|
| 274 |
+
fi
|
| 275 |
+
|
| 276 |
+
# Make the versioning information available to the compiler
|
| 277 |
+
AC_DEFINE_UNQUOTED([HAVE_PYTHON], ["$ac_python_version"],
|
| 278 |
+
[If available, contains the Python version number currently in use.])
|
| 279 |
+
|
| 280 |
+
# First, the library directory:
|
| 281 |
+
ac_python_libdir=`cat<<EOD | $PYTHON -
|
| 282 |
+
|
| 283 |
+
# There should be only one
|
| 284 |
+
$IMPORT_SYSCONFIG
|
| 285 |
+
e = sysconfig.get_config_var('LIBDIR')
|
| 286 |
+
if e is not None:
|
| 287 |
+
print (e)
|
| 288 |
+
EOD`
|
| 289 |
+
|
| 290 |
+
# Now, for the library:
|
| 291 |
+
ac_python_library=`cat<<EOD | $PYTHON -
|
| 292 |
+
|
| 293 |
+
$IMPORT_SYSCONFIG
|
| 294 |
+
c = sysconfig.get_config_vars()
|
| 295 |
+
if 'LDVERSION' in c:
|
| 296 |
+
print ('python'+c[['LDVERSION']])
|
| 297 |
+
else:
|
| 298 |
+
print ('python'+c[['VERSION']])
|
| 299 |
+
EOD`
|
| 300 |
+
|
| 301 |
+
# This small piece shamelessly adapted from PostgreSQL python macro;
|
| 302 |
+
# credits goes to momjian, I think. I'd like to put the right name
|
| 303 |
+
# in the credits, if someone can point me in the right direction... ?
|
| 304 |
+
#
|
| 305 |
+
if test -n "$ac_python_libdir" -a -n "$ac_python_library"
|
| 306 |
+
then
|
| 307 |
+
# use the official shared library
|
| 308 |
+
ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
|
| 309 |
+
PYTHON_LIBS="-L$ac_python_libdir -l$ac_python_library"
|
| 310 |
+
else
|
| 311 |
+
# old way: use libpython from python_configdir
|
| 312 |
+
ac_python_libdir=`$PYTHON -c \
|
| 313 |
+
"from sysconfig import get_python_lib as f; \
|
| 314 |
+
import os; \
|
| 315 |
+
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
|
| 316 |
+
PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
|
| 317 |
+
fi
|
| 318 |
+
|
| 319 |
+
if test -z "$PYTHON_LIBS"; then
|
| 320 |
+
AC_MSG_WARN([
|
| 321 |
+
Cannot determine location of your Python DSO. Please check it was installed with
|
| 322 |
+
dynamic libraries enabled, or try setting PYTHON_LIBS by hand.
|
| 323 |
+
])
|
| 324 |
+
if ! $ax_python_devel_optional; then
|
| 325 |
+
AC_MSG_ERROR([Giving up])
|
| 326 |
+
fi
|
| 327 |
+
ax_python_devel_found=no
|
| 328 |
+
PYTHON_VERSION=""
|
| 329 |
+
fi
|
| 330 |
+
fi
|
| 331 |
+
fi
|
| 332 |
+
|
| 333 |
+
if test $ax_python_devel_found = yes; then
|
| 334 |
+
AC_MSG_RESULT([$PYTHON_LIBS])
|
| 335 |
+
AC_SUBST([PYTHON_LIBS])
|
| 336 |
+
|
| 337 |
+
#
|
| 338 |
+
# Check for site packages
|
| 339 |
+
#
|
| 340 |
+
AC_MSG_CHECKING([for Python site-packages path])
|
| 341 |
+
if test -z "$PYTHON_SITE_PKG"; then
|
| 342 |
+
if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
|
| 343 |
+
PYTHON_SITE_PKG=`$PYTHON -c "
|
| 344 |
+
$IMPORT_SYSCONFIG;
|
| 345 |
+
if hasattr(sysconfig, 'get_default_scheme'):
|
| 346 |
+
scheme = sysconfig.get_default_scheme()
|
| 347 |
+
else:
|
| 348 |
+
scheme = sysconfig._get_default_scheme()
|
| 349 |
+
if scheme == 'posix_local':
|
| 350 |
+
# Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
|
| 351 |
+
scheme = 'posix_prefix'
|
| 352 |
+
prefix = '$prefix'
|
| 353 |
+
if prefix == 'NONE':
|
| 354 |
+
prefix = '$ac_default_prefix'
|
| 355 |
+
sitedir = sysconfig.get_path('purelib', scheme, vars={'base': prefix})
|
| 356 |
+
print(sitedir)"`
|
| 357 |
+
else
|
| 358 |
+
# distutils.sysconfig way
|
| 359 |
+
PYTHON_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
| 360 |
+
print (sysconfig.get_python_lib(0,0));"`
|
| 361 |
+
fi
|
| 362 |
+
fi
|
| 363 |
+
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
| 364 |
+
AC_SUBST([PYTHON_SITE_PKG])
|
| 365 |
+
|
| 366 |
+
#
|
| 367 |
+
# Check for platform-specific site packages
|
| 368 |
+
#
|
| 369 |
+
AC_MSG_CHECKING([for Python platform specific site-packages path])
|
| 370 |
+
if test -z "$PYTHON_PLATFORM_SITE_PKG"; then
|
| 371 |
+
if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
|
| 372 |
+
PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "
|
| 373 |
+
$IMPORT_SYSCONFIG;
|
| 374 |
+
if hasattr(sysconfig, 'get_default_scheme'):
|
| 375 |
+
scheme = sysconfig.get_default_scheme()
|
| 376 |
+
else:
|
| 377 |
+
scheme = sysconfig._get_default_scheme()
|
| 378 |
+
if scheme == 'posix_local':
|
| 379 |
+
# Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
|
| 380 |
+
scheme = 'posix_prefix'
|
| 381 |
+
prefix = '$prefix'
|
| 382 |
+
if prefix == 'NONE':
|
| 383 |
+
prefix = '$ac_default_prefix'
|
| 384 |
+
sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase': prefix})
|
| 385 |
+
print(sitedir)"`
|
| 386 |
+
else
|
| 387 |
+
# distutils.sysconfig way
|
| 388 |
+
PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
| 389 |
+
print (sysconfig.get_python_lib(1,0));"`
|
| 390 |
+
fi
|
| 391 |
+
fi
|
| 392 |
+
AC_MSG_RESULT([$PYTHON_PLATFORM_SITE_PKG])
|
| 393 |
+
AC_SUBST([PYTHON_PLATFORM_SITE_PKG])
|
| 394 |
+
|
| 395 |
+
#
|
| 396 |
+
# libraries which must be linked in when embedding
|
| 397 |
+
#
|
| 398 |
+
AC_MSG_CHECKING(python extra libraries)
|
| 399 |
+
if test -z "$PYTHON_EXTRA_LIBS"; then
|
| 400 |
+
PYTHON_EXTRA_LIBS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
| 401 |
+
conf = sysconfig.get_config_var; \
|
| 402 |
+
print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
|
| 403 |
+
fi
|
| 404 |
+
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
|
| 405 |
+
AC_SUBST(PYTHON_EXTRA_LIBS)
|
| 406 |
+
|
| 407 |
+
#
|
| 408 |
+
# linking flags needed when embedding
|
| 409 |
+
#
|
| 410 |
+
AC_MSG_CHECKING(python extra linking flags)
|
| 411 |
+
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
|
| 412 |
+
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
| 413 |
+
conf = sysconfig.get_config_var; \
|
| 414 |
+
print (conf('LINKFORSHARED'))"`
|
| 415 |
+
# Hack for macos, it sticks this in here.
|
| 416 |
+
PYTHON_EXTRA_LDFLAGS=`echo $PYTHON_EXTRA_LDFLAGS | sed 's/CoreFoundation.*$/CoreFoundation/'`
|
| 417 |
+
fi
|
| 418 |
+
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
| 419 |
+
AC_SUBST(PYTHON_EXTRA_LDFLAGS)
|
| 420 |
+
|
| 421 |
+
#
|
| 422 |
+
# final check to see if everything compiles alright
|
| 423 |
+
#
|
| 424 |
+
AC_MSG_CHECKING([consistency of all components of python development environment])
|
| 425 |
+
# save current global flags
|
| 426 |
+
ac_save_LIBS="$LIBS"
|
| 427 |
+
ac_save_LDFLAGS="$LDFLAGS"
|
| 428 |
+
ac_save_CPPFLAGS="$CPPFLAGS"
|
| 429 |
+
LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS"
|
| 430 |
+
LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
|
| 431 |
+
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
|
| 432 |
+
AC_LANG_PUSH([C])
|
| 433 |
+
AC_LINK_IFELSE([
|
| 434 |
+
AC_LANG_PROGRAM([[#include <Python.h>]],
|
| 435 |
+
[[Py_Initialize();]])
|
| 436 |
+
],[pythonexists=yes],[pythonexists=no])
|
| 437 |
+
AC_LANG_POP([C])
|
| 438 |
+
# turn back to default flags
|
| 439 |
+
CPPFLAGS="$ac_save_CPPFLAGS"
|
| 440 |
+
LIBS="$ac_save_LIBS"
|
| 441 |
+
LDFLAGS="$ac_save_LDFLAGS"
|
| 442 |
+
|
| 443 |
+
AC_MSG_RESULT([$pythonexists])
|
| 444 |
+
|
| 445 |
+
if test ! "x$pythonexists" = "xyes"; then
|
| 446 |
+
AC_MSG_WARN([
|
| 447 |
+
Could not link test program to Python. Maybe the main Python library has been
|
| 448 |
+
installed in some non-standard library path. If so, pass it to configure,
|
| 449 |
+
via the LIBS environment variable.
|
| 450 |
+
Example: ./configure LIBS="-L/usr/non-standard-path/python/lib"
|
| 451 |
+
============================================================================
|
| 452 |
+
ERROR!
|
| 453 |
+
You probably have to install the development version of the Python package
|
| 454 |
+
for your distribution. The exact name of this package varies among them.
|
| 455 |
+
============================================================================
|
| 456 |
+
])
|
| 457 |
+
if ! $ax_python_devel_optional; then
|
| 458 |
+
AC_MSG_ERROR([Giving up])
|
| 459 |
+
fi
|
| 460 |
+
ax_python_devel_found=no
|
| 461 |
+
PYTHON_VERSION=""
|
| 462 |
+
fi
|
| 463 |
+
fi
|
| 464 |
+
|
| 465 |
+
#
|
| 466 |
+
# all done!
|
| 467 |
+
#
|
| 468 |
+
])
|
bt_packet_logger.c
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* bt_packet_logger.c
|
| 3 |
+
* com.apple.bluetooth.BTPacketLogger service implementation.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2021 Geoffrey Kruse, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifdef HAVE_CONFIG_H
|
| 23 |
+
#include <config.h>
|
| 24 |
+
#endif
|
| 25 |
+
#include <string.h>
|
| 26 |
+
#include <stdlib.h>
|
| 27 |
+
|
| 28 |
+
#include "bt_packet_logger.h"
|
| 29 |
+
#include "lockdown.h"
|
| 30 |
+
#include "common/debug.h"
|
| 31 |
+
|
| 32 |
+
struct bt_packet_logger_worker_thread {
|
| 33 |
+
bt_packet_logger_client_t client;
|
| 34 |
+
bt_packet_logger_receive_cb_t cbfunc;
|
| 35 |
+
void *user_data;
|
| 36 |
+
uint8_t rxbuff[BT_MAX_PACKET_SIZE];
|
| 37 |
+
};
|
| 38 |
+
|
| 39 |
+
#define SZ_READ_TIMEOUT 100
|
| 40 |
+
#define PAYLOAD_READ_TIMEOUT 500
|
| 41 |
+
|
| 42 |
+
/**
|
| 43 |
+
* Convert a service_error_t value to a bt_packet_logger_error_t value.
|
| 44 |
+
* Used internally to get correct error codes.
|
| 45 |
+
*
|
| 46 |
+
* @param err An service_error_t error code
|
| 47 |
+
*
|
| 48 |
+
* @return A matching bt_packet_logger_error_t error code,
|
| 49 |
+
* BT_PACKET_LOGGER_E_UNKNOWN_ERROR otherwise.
|
| 50 |
+
*/
|
| 51 |
+
static bt_packet_logger_error_t bt_packet_logger_error(service_error_t err)
|
| 52 |
+
{
|
| 53 |
+
switch (err) {
|
| 54 |
+
case SERVICE_E_SUCCESS:
|
| 55 |
+
return BT_PACKET_LOGGER_E_SUCCESS;
|
| 56 |
+
case SERVICE_E_INVALID_ARG:
|
| 57 |
+
return BT_PACKET_LOGGER_E_INVALID_ARG;
|
| 58 |
+
case SERVICE_E_MUX_ERROR:
|
| 59 |
+
return BT_PACKET_LOGGER_E_MUX_ERROR;
|
| 60 |
+
case SERVICE_E_SSL_ERROR:
|
| 61 |
+
return BT_PACKET_LOGGER_E_SSL_ERROR;
|
| 62 |
+
case SERVICE_E_NOT_ENOUGH_DATA:
|
| 63 |
+
return BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA;
|
| 64 |
+
case SERVICE_E_TIMEOUT:
|
| 65 |
+
return BT_PACKET_LOGGER_E_TIMEOUT;
|
| 66 |
+
default:
|
| 67 |
+
break;
|
| 68 |
+
}
|
| 69 |
+
return BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd_service_descriptor_t service, bt_packet_logger_client_t * client)
|
| 73 |
+
{
|
| 74 |
+
if (!device || !service || service->port == 0 || !client || *client) {
|
| 75 |
+
debug_info("Incorrect parameter passed to bt_packet_logger_client_new.");
|
| 76 |
+
return BT_PACKET_LOGGER_E_INVALID_ARG;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
debug_info("Creating bt_packet_logger_client, port = %d.", service->port);
|
| 80 |
+
|
| 81 |
+
service_client_t parent = NULL;
|
| 82 |
+
bt_packet_logger_error_t ret = bt_packet_logger_error(service_client_new(device, service, &parent));
|
| 83 |
+
if (ret != BT_PACKET_LOGGER_E_SUCCESS) {
|
| 84 |
+
debug_info("Creating base service client failed. Error: %i", ret);
|
| 85 |
+
return ret;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
bt_packet_logger_client_t client_loc = (bt_packet_logger_client_t) malloc(sizeof(struct bt_packet_logger_client_private));
|
| 89 |
+
client_loc->parent = parent;
|
| 90 |
+
client_loc->worker = THREAD_T_NULL;
|
| 91 |
+
|
| 92 |
+
*client = client_loc;
|
| 93 |
+
|
| 94 |
+
debug_info("bt_packet_logger_client successfully created.");
|
| 95 |
+
return 0;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, bt_packet_logger_client_t * client, const char* label)
|
| 99 |
+
{
|
| 100 |
+
bt_packet_logger_error_t err = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
|
| 101 |
+
service_client_factory_start_service(device, BT_PACKETLOGGER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(bt_packet_logger_client_new), &err);
|
| 102 |
+
return err;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client)
|
| 106 |
+
{
|
| 107 |
+
if (!client)
|
| 108 |
+
return BT_PACKET_LOGGER_E_INVALID_ARG;
|
| 109 |
+
bt_packet_logger_stop_capture(client);
|
| 110 |
+
bt_packet_logger_error_t err = bt_packet_logger_error(service_client_free(client->parent));
|
| 111 |
+
free(client);
|
| 112 |
+
|
| 113 |
+
return err;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
bt_packet_logger_error_t bt_packet_logger_receive_with_timeout(bt_packet_logger_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
|
| 117 |
+
{
|
| 118 |
+
bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
|
| 119 |
+
int bytes = 0;
|
| 120 |
+
|
| 121 |
+
if (!client || !data || (size == 0)) {
|
| 122 |
+
return BT_PACKET_LOGGER_E_INVALID_ARG;
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
res = bt_packet_logger_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
|
| 126 |
+
if (res != BT_PACKET_LOGGER_E_SUCCESS && res != BT_PACKET_LOGGER_E_TIMEOUT && res != BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA) {
|
| 127 |
+
debug_info("Could not read data, error %d", res);
|
| 128 |
+
}
|
| 129 |
+
if (received) {
|
| 130 |
+
*received = (uint32_t)bytes;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
return res;
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
void *bt_packet_logger_worker(void *arg)
|
| 137 |
+
{
|
| 138 |
+
bt_packet_logger_error_t ret = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
|
| 139 |
+
struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)arg;
|
| 140 |
+
|
| 141 |
+
if (!btwt) {
|
| 142 |
+
return NULL;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
debug_info("Running");
|
| 146 |
+
|
| 147 |
+
while (btwt->client->parent) {
|
| 148 |
+
uint32_t bytes = 0;
|
| 149 |
+
uint16_t len;
|
| 150 |
+
|
| 151 |
+
ret = bt_packet_logger_receive_with_timeout(btwt->client, (char*)&len, 2, &bytes, SZ_READ_TIMEOUT);
|
| 152 |
+
|
| 153 |
+
if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) {
|
| 154 |
+
continue;
|
| 155 |
+
} else if (ret < 0) {
|
| 156 |
+
debug_info("Connection to bt packet logger interrupted");
|
| 157 |
+
break;
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
// sanity check received length
|
| 161 |
+
if(bytes > 0 && len > sizeof(bt_packet_logger_header_t)) {
|
| 162 |
+
debug_info("Reading %u bytes\n", len);
|
| 163 |
+
ret = bt_packet_logger_receive_with_timeout(btwt->client, (char *)btwt->rxbuff, len, &bytes, PAYLOAD_READ_TIMEOUT);
|
| 164 |
+
|
| 165 |
+
if(len != bytes) {
|
| 166 |
+
debug_info("Failed Read Expected %u, Received %u\n", len, bytes);
|
| 167 |
+
continue;
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) {
|
| 171 |
+
continue;
|
| 172 |
+
} else if (ret < 0) {
|
| 173 |
+
debug_info("Connection to bt packet logger interrupted");
|
| 174 |
+
break;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
btwt->cbfunc(btwt->rxbuff, len, btwt->user_data);
|
| 178 |
+
}
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
// null check performed above
|
| 182 |
+
free(btwt);
|
| 183 |
+
|
| 184 |
+
debug_info("Exiting");
|
| 185 |
+
|
| 186 |
+
return NULL;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_t client, bt_packet_logger_receive_cb_t callback, void* user_data)
|
| 190 |
+
{
|
| 191 |
+
if (!client || !callback)
|
| 192 |
+
return BT_PACKET_LOGGER_E_INVALID_ARG;
|
| 193 |
+
|
| 194 |
+
bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
|
| 195 |
+
|
| 196 |
+
if (client->worker) {
|
| 197 |
+
debug_info("Another syslog capture thread appears to be running already.");
|
| 198 |
+
return res;
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
/* start worker thread */
|
| 202 |
+
struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)malloc(sizeof(struct bt_packet_logger_worker_thread));
|
| 203 |
+
if (btwt) {
|
| 204 |
+
btwt->client = client;
|
| 205 |
+
btwt->cbfunc = callback;
|
| 206 |
+
btwt->user_data = user_data;
|
| 207 |
+
|
| 208 |
+
if (thread_new(&client->worker, bt_packet_logger_worker, btwt) == 0) {
|
| 209 |
+
res = BT_PACKET_LOGGER_E_SUCCESS;
|
| 210 |
+
}
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
return res;
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client)
|
| 218 |
+
{
|
| 219 |
+
if (client->worker) {
|
| 220 |
+
/* notify thread to finish */
|
| 221 |
+
service_client_t parent = client->parent;
|
| 222 |
+
client->parent = NULL;
|
| 223 |
+
/* join thread to make it exit */
|
| 224 |
+
thread_join(client->worker);
|
| 225 |
+
thread_free(client->worker);
|
| 226 |
+
client->worker = THREAD_T_NULL;
|
| 227 |
+
client->parent = parent;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
return BT_PACKET_LOGGER_E_SUCCESS;
|
| 231 |
+
}
|
bt_packet_logger.h
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* bt_packet_logger.h
|
| 3 |
+
* com.apple.bluetooth.BTPacketLogger service header file.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2021 Geoffrey Kruse, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifndef _BR_PACKET_LOGGER_H
|
| 23 |
+
#define _BR_PACKET_LOGGER_H
|
| 24 |
+
|
| 25 |
+
#include "idevice.h"
|
| 26 |
+
#include "libimobiledevice/bt_packet_logger.h"
|
| 27 |
+
#include "service.h"
|
| 28 |
+
#include <libimobiledevice-glue/thread.h>
|
| 29 |
+
|
| 30 |
+
struct bt_packet_logger_client_private {
|
| 31 |
+
service_client_t parent;
|
| 32 |
+
THREAD_T worker;
|
| 33 |
+
};
|
| 34 |
+
|
| 35 |
+
void *bt_packet_logger_worker(void *arg);
|
| 36 |
+
|
| 37 |
+
#endif
|
common.c
ADDED
|
@@ -0,0 +1,647 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* common.c
|
| 3 |
+
* Misc functions used in idevicerestore
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2012 Martin Szulecki. All Rights Reserved.
|
| 7 |
+
* Copyright (c) 2010 Joshua Hill. All Rights Reserved.
|
| 8 |
+
*
|
| 9 |
+
* This library is free software; you can redistribute it and/or
|
| 10 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 11 |
+
* License as published by the Free Software Foundation; either
|
| 12 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This library is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 17 |
+
* Lesser General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 20 |
+
* License along with this library; if not, write to the Free Software
|
| 21 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 22 |
+
*/
|
| 23 |
+
|
| 24 |
+
#ifdef HAVE_CONFIG_H
|
| 25 |
+
#include <config.h>
|
| 26 |
+
#endif
|
| 27 |
+
|
| 28 |
+
#include <stdio.h>
|
| 29 |
+
#include <stdlib.h>
|
| 30 |
+
#include <string.h>
|
| 31 |
+
#include <unistd.h>
|
| 32 |
+
#include <errno.h>
|
| 33 |
+
#include <libgen.h>
|
| 34 |
+
#include <time.h>
|
| 35 |
+
#include <sys/stat.h>
|
| 36 |
+
#include <fcntl.h>
|
| 37 |
+
#include <ctype.h>
|
| 38 |
+
|
| 39 |
+
#ifdef WIN32
|
| 40 |
+
#include <windows.h>
|
| 41 |
+
#include <conio.h>
|
| 42 |
+
#ifndef _O_EXCL
|
| 43 |
+
#define _O_EXCL 0x0400
|
| 44 |
+
#endif
|
| 45 |
+
#ifndef O_EXCL
|
| 46 |
+
#define O_EXCL _O_EXCL
|
| 47 |
+
#endif
|
| 48 |
+
#else
|
| 49 |
+
#include <sys/time.h>
|
| 50 |
+
#include <pthread.h>
|
| 51 |
+
#include <termios.h>
|
| 52 |
+
#endif
|
| 53 |
+
|
| 54 |
+
#include "common.h"
|
| 55 |
+
#include "endianness.h"
|
| 56 |
+
|
| 57 |
+
#define MAX_PRINT_LEN 64*1024
|
| 58 |
+
|
| 59 |
+
struct idevicerestore_mode_t idevicerestore_modes[] = {
|
| 60 |
+
{ 0, "WTF" },
|
| 61 |
+
{ 1, "DFU" },
|
| 62 |
+
{ 2, "Recovery" },
|
| 63 |
+
{ 3, "Restore" },
|
| 64 |
+
{ 4, "Normal" },
|
| 65 |
+
{ -1, NULL }
|
| 66 |
+
};
|
| 67 |
+
|
| 68 |
+
int idevicerestore_debug = 0;
|
| 69 |
+
|
| 70 |
+
#define idevicerestore_err_buff_size 256
|
| 71 |
+
static char idevicerestore_err_buff[idevicerestore_err_buff_size] = {0, };
|
| 72 |
+
|
| 73 |
+
static FILE* info_stream = NULL;
|
| 74 |
+
static FILE* error_stream = NULL;
|
| 75 |
+
static FILE* debug_stream = NULL;
|
| 76 |
+
|
| 77 |
+
static int info_disabled = 0;
|
| 78 |
+
static int error_disabled = 0;
|
| 79 |
+
static int debug_disabled = 0;
|
| 80 |
+
|
| 81 |
+
void info(const char* format, ...)
|
| 82 |
+
{
|
| 83 |
+
if (info_disabled) return;
|
| 84 |
+
va_list vargs;
|
| 85 |
+
va_start(vargs, format);
|
| 86 |
+
vfprintf((info_stream) ? info_stream : stdout, format, vargs);
|
| 87 |
+
va_end(vargs);
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
void error(const char* format, ...)
|
| 91 |
+
{
|
| 92 |
+
va_list vargs, vargs2;
|
| 93 |
+
va_start(vargs, format);
|
| 94 |
+
va_copy(vargs2, vargs);
|
| 95 |
+
vsnprintf(idevicerestore_err_buff, idevicerestore_err_buff_size, format, vargs);
|
| 96 |
+
va_end(vargs);
|
| 97 |
+
if (!error_disabled) {
|
| 98 |
+
vfprintf((error_stream) ? error_stream : stderr, format, vargs2);
|
| 99 |
+
}
|
| 100 |
+
va_end(vargs2);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
void debug(const char* format, ...)
|
| 104 |
+
{
|
| 105 |
+
if (debug_disabled) return;
|
| 106 |
+
if (!idevicerestore_debug) {
|
| 107 |
+
return;
|
| 108 |
+
}
|
| 109 |
+
va_list vargs;
|
| 110 |
+
va_start(vargs, format);
|
| 111 |
+
vfprintf((debug_stream) ? debug_stream : stderr, format, vargs);
|
| 112 |
+
va_end(vargs);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
void idevicerestore_set_info_stream(FILE* strm)
|
| 116 |
+
{
|
| 117 |
+
if (strm) {
|
| 118 |
+
info_disabled = 0;
|
| 119 |
+
info_stream = strm;
|
| 120 |
+
} else {
|
| 121 |
+
info_disabled = 1;
|
| 122 |
+
}
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
void idevicerestore_set_error_stream(FILE* strm)
|
| 126 |
+
{
|
| 127 |
+
if (strm) {
|
| 128 |
+
error_disabled = 0;
|
| 129 |
+
error_stream = strm;
|
| 130 |
+
} else {
|
| 131 |
+
error_disabled = 1;
|
| 132 |
+
}
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
void idevicerestore_set_debug_stream(FILE* strm)
|
| 136 |
+
{
|
| 137 |
+
if (strm) {
|
| 138 |
+
debug_disabled = 0;
|
| 139 |
+
debug_stream = strm;
|
| 140 |
+
} else {
|
| 141 |
+
debug_disabled = 1;
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
const char* idevicerestore_get_error(void)
|
| 146 |
+
{
|
| 147 |
+
if (idevicerestore_err_buff[0] == 0) {
|
| 148 |
+
return NULL;
|
| 149 |
+
} else {
|
| 150 |
+
char* p = NULL;
|
| 151 |
+
while ((strlen(idevicerestore_err_buff) > 0) && (p = strrchr(idevicerestore_err_buff, '\n'))) {
|
| 152 |
+
p[0] = '\0';
|
| 153 |
+
}
|
| 154 |
+
return (const char*)idevicerestore_err_buff;
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
int write_file(const char* filename, const void* data, size_t size) {
|
| 159 |
+
size_t bytes = 0;
|
| 160 |
+
FILE* file = NULL;
|
| 161 |
+
|
| 162 |
+
debug("Writing data to %s\n", filename);
|
| 163 |
+
file = fopen(filename, "wb");
|
| 164 |
+
if (file == NULL) {
|
| 165 |
+
error("write_file: Unable to open file %s\n", filename);
|
| 166 |
+
return -1;
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
bytes = fwrite(data, 1, size, file);
|
| 170 |
+
fclose(file);
|
| 171 |
+
|
| 172 |
+
if (bytes != size) {
|
| 173 |
+
error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, (int)bytes, (int)size);
|
| 174 |
+
return -1;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
return size;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
int read_file(const char* filename, void** data, size_t* size) {
|
| 181 |
+
size_t bytes = 0;
|
| 182 |
+
size_t length = 0;
|
| 183 |
+
FILE* file = NULL;
|
| 184 |
+
char* buffer = NULL;
|
| 185 |
+
struct stat fst;
|
| 186 |
+
|
| 187 |
+
debug("Reading data from %s\n", filename);
|
| 188 |
+
|
| 189 |
+
*size = 0;
|
| 190 |
+
*data = NULL;
|
| 191 |
+
|
| 192 |
+
file = fopen(filename, "rb");
|
| 193 |
+
if (file == NULL) {
|
| 194 |
+
error("read_file: cannot open %s: %s\n", filename, strerror(errno));
|
| 195 |
+
return -1;
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
if (fstat(fileno(file), &fst) < 0) {
|
| 199 |
+
error("read_file: fstat: %s\n", strerror(errno));
|
| 200 |
+
return -1;
|
| 201 |
+
}
|
| 202 |
+
length = fst.st_size;
|
| 203 |
+
|
| 204 |
+
buffer = (char*) malloc(length);
|
| 205 |
+
if (buffer == NULL) {
|
| 206 |
+
error("ERROR: Out of memory\n");
|
| 207 |
+
fclose(file);
|
| 208 |
+
return -1;
|
| 209 |
+
}
|
| 210 |
+
bytes = fread(buffer, 1, length, file);
|
| 211 |
+
fclose(file);
|
| 212 |
+
|
| 213 |
+
if (bytes != length) {
|
| 214 |
+
error("ERROR: Unable to read entire file\n");
|
| 215 |
+
free(buffer);
|
| 216 |
+
return -1;
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
*size = length;
|
| 220 |
+
*data = buffer;
|
| 221 |
+
return 0;
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
void debug_plist(plist_t plist) {
|
| 225 |
+
uint32_t size = 0;
|
| 226 |
+
char* data = NULL;
|
| 227 |
+
plist_to_xml(plist, &data, &size);
|
| 228 |
+
if (size <= MAX_PRINT_LEN)
|
| 229 |
+
info("%s:printing %i bytes plist:\n%s", __FILE__, size, data);
|
| 230 |
+
else
|
| 231 |
+
info("%s:supressed printing %i bytes plist...\n", __FILE__, size);
|
| 232 |
+
free(data);
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
void print_progress_bar(double progress) {
|
| 236 |
+
#ifndef WIN32
|
| 237 |
+
if (info_disabled) return;
|
| 238 |
+
int i = 0;
|
| 239 |
+
if(progress < 0) return;
|
| 240 |
+
if(progress > 100) progress = 100;
|
| 241 |
+
info("\r[");
|
| 242 |
+
for(i = 0; i < 50; i++) {
|
| 243 |
+
if(i < progress / 2) info("=");
|
| 244 |
+
else info(" ");
|
| 245 |
+
}
|
| 246 |
+
info("] %5.1f%%", progress);
|
| 247 |
+
if(progress >= 100) info("\n");
|
| 248 |
+
fflush((info_stream) ? info_stream : stdout);
|
| 249 |
+
#endif
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
#define GET_RAND(min, max) ((rand() % (max - min)) + min)
|
| 253 |
+
|
| 254 |
+
char *generate_guid(void)
|
| 255 |
+
{
|
| 256 |
+
char *guid = (char *) malloc(sizeof(char) * 37);
|
| 257 |
+
const char *chars = "ABCDEF0123456789";
|
| 258 |
+
srand(time(NULL));
|
| 259 |
+
int i = 0;
|
| 260 |
+
|
| 261 |
+
for (i = 0; i < 36; i++) {
|
| 262 |
+
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
| 263 |
+
guid[i] = '-';
|
| 264 |
+
continue;
|
| 265 |
+
} else {
|
| 266 |
+
guid[i] = chars[GET_RAND(0, 16)];
|
| 267 |
+
}
|
| 268 |
+
}
|
| 269 |
+
guid[36] = '\0';
|
| 270 |
+
return guid;
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
int mkdir_with_parents(const char *dir, int mode)
|
| 274 |
+
{
|
| 275 |
+
if (!dir) return -1;
|
| 276 |
+
if (__mkdir(dir, mode) == 0) {
|
| 277 |
+
return 0;
|
| 278 |
+
} else {
|
| 279 |
+
if (errno == EEXIST) {
|
| 280 |
+
return 0;
|
| 281 |
+
} else if (errno == ENOENT) {
|
| 282 |
+
// ignore
|
| 283 |
+
} else {
|
| 284 |
+
return -1;
|
| 285 |
+
}
|
| 286 |
+
}
|
| 287 |
+
int res;
|
| 288 |
+
char *parent = strdup(dir);
|
| 289 |
+
char *parentdir = dirname(parent);
|
| 290 |
+
if (parentdir && (strcmp(parentdir, ".") != 0) && (strcmp(parentdir, dir) != 0)) {
|
| 291 |
+
res = mkdir_with_parents(parentdir, mode);
|
| 292 |
+
} else {
|
| 293 |
+
res = -1;
|
| 294 |
+
}
|
| 295 |
+
free(parent);
|
| 296 |
+
if (res == 0) {
|
| 297 |
+
mkdir_with_parents(dir, mode);
|
| 298 |
+
}
|
| 299 |
+
return res;
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
#ifndef HAVE_MKSTEMP
|
| 303 |
+
/* Based on libc's __gen_tempname() from sysdeps/posix/tempname.c
|
| 304 |
+
Copyright (C) 1991-2018 Free Software Foundation, Inc.
|
| 305 |
+
With changes from https://stackoverflow.com/a/6036308 and some
|
| 306 |
+
additional changes. */
|
| 307 |
+
int mkstemp(char *tmpl)
|
| 308 |
+
{
|
| 309 |
+
static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
| 310 |
+
int len;
|
| 311 |
+
char *XXXXXX;
|
| 312 |
+
static unsigned long long value;
|
| 313 |
+
unsigned long long random_time_bits;
|
| 314 |
+
unsigned int count;
|
| 315 |
+
int fd = -1;
|
| 316 |
+
int save_errno = errno;
|
| 317 |
+
|
| 318 |
+
/* A lower bound on the number of temporary files to attempt to
|
| 319 |
+
generate. The maximum total number of temporary file names that
|
| 320 |
+
can exist for a given template is 62**6. It should never be
|
| 321 |
+
necessary to try all these combinations. Instead if a reasonable
|
| 322 |
+
number of names is tried (we define reasonable as 62**3) fail to
|
| 323 |
+
give the system administrator the chance to remove the problems. */
|
| 324 |
+
#define ATTEMPTS_MIN (62 * 62 * 62)
|
| 325 |
+
|
| 326 |
+
/* The number of times to attempt to generate a temporary file. To
|
| 327 |
+
conform to POSIX, this must be no smaller than TMP_MAX. */
|
| 328 |
+
#if ATTEMPTS_MIN < TMP_MAX
|
| 329 |
+
unsigned int attempts = TMP_MAX;
|
| 330 |
+
#else
|
| 331 |
+
unsigned int attempts = ATTEMPTS_MIN;
|
| 332 |
+
#endif
|
| 333 |
+
|
| 334 |
+
len = strlen (tmpl);
|
| 335 |
+
if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
|
| 336 |
+
{
|
| 337 |
+
errno = EINVAL;
|
| 338 |
+
return -1;
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
/* This is where the Xs start. */
|
| 342 |
+
XXXXXX = &tmpl[len - 6];
|
| 343 |
+
|
| 344 |
+
/* Get some more or less random data. */
|
| 345 |
+
#ifdef WIN32
|
| 346 |
+
{
|
| 347 |
+
SYSTEMTIME stNow;
|
| 348 |
+
FILETIME ftNow;
|
| 349 |
+
|
| 350 |
+
// get system time
|
| 351 |
+
GetSystemTime(&stNow);
|
| 352 |
+
if (!SystemTimeToFileTime(&stNow, &ftNow))
|
| 353 |
+
{
|
| 354 |
+
errno = -1;
|
| 355 |
+
return -1;
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32)
|
| 359 |
+
| (unsigned long long)ftNow.dwLowDateTime);
|
| 360 |
+
}
|
| 361 |
+
value += random_time_bits ^ ((unsigned long long)GetCurrentProcessId() << 32 | (unsigned long long)GetCurrentThreadId());
|
| 362 |
+
#else
|
| 363 |
+
{
|
| 364 |
+
struct timeval tvNow = {0, 0};
|
| 365 |
+
gettimeofday(&tvNow, NULL);
|
| 366 |
+
random_time_bits = (((unsigned long long)tvNow.tv_sec << 32)
|
| 367 |
+
| (unsigned long long)tvNow.tv_usec);
|
| 368 |
+
}
|
| 369 |
+
value += random_time_bits ^ ((unsigned long long)getpid() << 32 | (unsigned long long)(uintptr_t)pthread_self());
|
| 370 |
+
#endif
|
| 371 |
+
|
| 372 |
+
for (count = 0; count < attempts; value += 7777, ++count)
|
| 373 |
+
{
|
| 374 |
+
unsigned long long v = value;
|
| 375 |
+
|
| 376 |
+
/* Fill in the random bits. */
|
| 377 |
+
XXXXXX[0] = letters[v % 62];
|
| 378 |
+
v /= 62;
|
| 379 |
+
XXXXXX[1] = letters[v % 62];
|
| 380 |
+
v /= 62;
|
| 381 |
+
XXXXXX[2] = letters[v % 62];
|
| 382 |
+
v /= 62;
|
| 383 |
+
XXXXXX[3] = letters[v % 62];
|
| 384 |
+
v /= 62;
|
| 385 |
+
XXXXXX[4] = letters[v % 62];
|
| 386 |
+
v /= 62;
|
| 387 |
+
XXXXXX[5] = letters[v % 62];
|
| 388 |
+
|
| 389 |
+
#ifdef WIN32
|
| 390 |
+
fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
|
| 391 |
+
#else
|
| 392 |
+
fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
| 393 |
+
#endif
|
| 394 |
+
if (fd >= 0)
|
| 395 |
+
{
|
| 396 |
+
errno = save_errno;
|
| 397 |
+
return fd;
|
| 398 |
+
}
|
| 399 |
+
else if (errno != EEXIST)
|
| 400 |
+
return -1;
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
/* We got out of the loop because we ran out of combinations to try. */
|
| 404 |
+
errno = EEXIST;
|
| 405 |
+
return -1;
|
| 406 |
+
}
|
| 407 |
+
#endif
|
| 408 |
+
|
| 409 |
+
char *get_temp_filename(const char *prefix)
|
| 410 |
+
{
|
| 411 |
+
char *result = NULL;
|
| 412 |
+
char *tmpdir;
|
| 413 |
+
size_t lt;
|
| 414 |
+
size_t lp;
|
| 415 |
+
const char *TMPVARS[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", NULL };
|
| 416 |
+
int i = 0;
|
| 417 |
+
int fd;
|
| 418 |
+
|
| 419 |
+
/* check the prefix parameter */
|
| 420 |
+
if (!prefix) {
|
| 421 |
+
prefix = "tmp_";
|
| 422 |
+
}
|
| 423 |
+
#ifdef WIN32
|
| 424 |
+
if (strchr(prefix, '/') || strchr(prefix, '\\')) return NULL;
|
| 425 |
+
#else
|
| 426 |
+
if (strchr(prefix, '/')) return NULL;
|
| 427 |
+
#endif
|
| 428 |
+
|
| 429 |
+
while (TMPVARS[i] && ((tmpdir = getenv(TMPVARS[i])) == NULL)) i++;
|
| 430 |
+
if (!tmpdir || access(tmpdir, W_OK|X_OK) != 0) {
|
| 431 |
+
#ifdef WIN32
|
| 432 |
+
tmpdir = "C:\\WINDOWS\\TEMP";
|
| 433 |
+
#else
|
| 434 |
+
tmpdir = P_tmpdir;
|
| 435 |
+
#endif
|
| 436 |
+
}
|
| 437 |
+
if (!tmpdir || access(tmpdir, W_OK|X_OK) != 0) {
|
| 438 |
+
return NULL;
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
lt = strlen(tmpdir);
|
| 442 |
+
if (lt < 1) {
|
| 443 |
+
return NULL;
|
| 444 |
+
}
|
| 445 |
+
lp = strlen(prefix);
|
| 446 |
+
result = malloc(lt + lp + 8);
|
| 447 |
+
memcpy(result, tmpdir, lt);
|
| 448 |
+
#ifdef WIN32
|
| 449 |
+
if (tmpdir[lt-1] != '/' && tmpdir[lt-1] != '\\') result[lt++] = '\\';
|
| 450 |
+
#else
|
| 451 |
+
if (tmpdir[lt-1] != '/') result[lt++] = '/';
|
| 452 |
+
#endif
|
| 453 |
+
strncpy(result + lt, prefix, lp);
|
| 454 |
+
strcpy(result + lt + lp, "XXXXXX");
|
| 455 |
+
fd = mkstemp(result);
|
| 456 |
+
if (fd < 0) {
|
| 457 |
+
free(result);
|
| 458 |
+
result = NULL;
|
| 459 |
+
}
|
| 460 |
+
close(fd);
|
| 461 |
+
return result;
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress)
|
| 465 |
+
{
|
| 466 |
+
if(client && client->progress_cb) {
|
| 467 |
+
client->progress_cb(step, progress, client->progress_cb_data);
|
| 468 |
+
} else {
|
| 469 |
+
// we don't want to be too verbose in regular idevicerestore.
|
| 470 |
+
if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW)) {
|
| 471 |
+
print_progress_bar(100.0 * progress);
|
| 472 |
+
}
|
| 473 |
+
}
|
| 474 |
+
}
|
| 475 |
+
|
| 476 |
+
#ifndef HAVE_STRSEP
|
| 477 |
+
char* strsep(char** strp, const char* delim)
|
| 478 |
+
{
|
| 479 |
+
char *p, *s;
|
| 480 |
+
if (strp == NULL || *strp == NULL || **strp == '\0') return NULL;
|
| 481 |
+
s = *strp;
|
| 482 |
+
p = s + strcspn(s, delim);
|
| 483 |
+
if (*p != '\0') *p++ = '\0';
|
| 484 |
+
*strp = p;
|
| 485 |
+
return s;
|
| 486 |
+
}
|
| 487 |
+
#endif
|
| 488 |
+
|
| 489 |
+
#ifndef HAVE_REALPATH
|
| 490 |
+
char* realpath(const char *filename, char *resolved_name)
|
| 491 |
+
{
|
| 492 |
+
#ifdef WIN32
|
| 493 |
+
if (access(filename, F_OK) != 0) {
|
| 494 |
+
return NULL;
|
| 495 |
+
}
|
| 496 |
+
if (GetFullPathName(filename, MAX_PATH, resolved_name, NULL) == 0) {
|
| 497 |
+
return NULL;
|
| 498 |
+
}
|
| 499 |
+
return resolved_name;
|
| 500 |
+
#else
|
| 501 |
+
#error please provide a realpath implementation for this platform
|
| 502 |
+
return NULL;
|
| 503 |
+
#endif
|
| 504 |
+
}
|
| 505 |
+
#endif
|
| 506 |
+
|
| 507 |
+
#ifdef WIN32
|
| 508 |
+
#define BS_CC '\b'
|
| 509 |
+
#define CTRL_C_CC 0x03
|
| 510 |
+
#define ESC_CC 0x1B
|
| 511 |
+
#define my_getch _getch
|
| 512 |
+
#else
|
| 513 |
+
#define BS_CC 0x7f
|
| 514 |
+
static int my_getch(void)
|
| 515 |
+
{
|
| 516 |
+
struct termios oldt, newt;
|
| 517 |
+
int ch;
|
| 518 |
+
tcgetattr(STDIN_FILENO, &oldt);
|
| 519 |
+
newt = oldt;
|
| 520 |
+
newt.c_lflag &= ~(ICANON | ECHO);
|
| 521 |
+
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
| 522 |
+
ch = getchar();
|
| 523 |
+
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
| 524 |
+
return ch;
|
| 525 |
+
}
|
| 526 |
+
#endif
|
| 527 |
+
|
| 528 |
+
void get_user_input(char *buf, int maxlen, int secure)
|
| 529 |
+
{
|
| 530 |
+
int len = 0;
|
| 531 |
+
int c;
|
| 532 |
+
|
| 533 |
+
while ((c = my_getch()) > 0) {
|
| 534 |
+
if ((c == '\r') || (c == '\n')) {
|
| 535 |
+
break;
|
| 536 |
+
} else if (isprint(c)) {
|
| 537 |
+
if (len < maxlen-1)
|
| 538 |
+
buf[len++] = c;
|
| 539 |
+
fputc((secure) ? '*' : c, stdout);
|
| 540 |
+
} else if (c == BS_CC) {
|
| 541 |
+
if (len > 0) {
|
| 542 |
+
fputs("\b \b", stdout);
|
| 543 |
+
len--;
|
| 544 |
+
}
|
| 545 |
+
}
|
| 546 |
+
#ifdef WIN32
|
| 547 |
+
else if (c == CTRL_C_CC || c == ESC_CC) {
|
| 548 |
+
c = -1;
|
| 549 |
+
break;
|
| 550 |
+
}
|
| 551 |
+
#endif
|
| 552 |
+
}
|
| 553 |
+
if (c < 0) {
|
| 554 |
+
len = 0;
|
| 555 |
+
}
|
| 556 |
+
fputs("\n", stdout);
|
| 557 |
+
buf[len] = 0;
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
uint64_t _plist_dict_get_uint(plist_t dict, const char *key)
|
| 561 |
+
{
|
| 562 |
+
uint64_t uintval = 0;
|
| 563 |
+
char *strval = NULL;
|
| 564 |
+
uint64_t strsz = 0;
|
| 565 |
+
plist_t node = plist_dict_get_item(dict, key);
|
| 566 |
+
if (!node) {
|
| 567 |
+
return (uint64_t)-1LL;
|
| 568 |
+
}
|
| 569 |
+
switch (plist_get_node_type(node)) {
|
| 570 |
+
case PLIST_UINT:
|
| 571 |
+
plist_get_uint_val(node, &uintval);
|
| 572 |
+
break;
|
| 573 |
+
case PLIST_STRING:
|
| 574 |
+
plist_get_string_val(node, &strval);
|
| 575 |
+
if (strval) {
|
| 576 |
+
uintval = strtoull(strval, NULL, 0);
|
| 577 |
+
free(strval);
|
| 578 |
+
}
|
| 579 |
+
break;
|
| 580 |
+
case PLIST_DATA:
|
| 581 |
+
plist_get_data_val(node, &strval, &strsz);
|
| 582 |
+
if (strval) {
|
| 583 |
+
if (strsz == 8) {
|
| 584 |
+
uintval = le64toh(*(uint64_t*)strval);
|
| 585 |
+
} else if (strsz == 4) {
|
| 586 |
+
uintval = le32toh(*(uint32_t*)strval);
|
| 587 |
+
} else if (strsz == 2) {
|
| 588 |
+
uintval = le16toh(*(uint16_t*)strval);
|
| 589 |
+
} else if (strsz == 1) {
|
| 590 |
+
uintval = strval[0];
|
| 591 |
+
} else {
|
| 592 |
+
error("%s: ERROR: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz);
|
| 593 |
+
}
|
| 594 |
+
free(strval);
|
| 595 |
+
}
|
| 596 |
+
break;
|
| 597 |
+
default:
|
| 598 |
+
break;
|
| 599 |
+
}
|
| 600 |
+
return uintval;
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
uint8_t _plist_dict_get_bool(plist_t dict, const char *key)
|
| 604 |
+
{
|
| 605 |
+
uint8_t bval = 0;
|
| 606 |
+
uint64_t uintval = 0;
|
| 607 |
+
char *strval = NULL;
|
| 608 |
+
uint64_t strsz = 0;
|
| 609 |
+
plist_t node = plist_dict_get_item(dict, key);
|
| 610 |
+
if (!node) {
|
| 611 |
+
return 0;
|
| 612 |
+
}
|
| 613 |
+
switch (plist_get_node_type(node)) {
|
| 614 |
+
case PLIST_BOOLEAN:
|
| 615 |
+
plist_get_bool_val(node, &bval);
|
| 616 |
+
break;
|
| 617 |
+
case PLIST_UINT:
|
| 618 |
+
plist_get_uint_val(node, &uintval);
|
| 619 |
+
bval = (uint8_t)uintval;
|
| 620 |
+
break;
|
| 621 |
+
case PLIST_STRING:
|
| 622 |
+
plist_get_string_val(node, &strval);
|
| 623 |
+
if (strval) {
|
| 624 |
+
if (strcmp(strval, "true")) {
|
| 625 |
+
bval = 1;
|
| 626 |
+
} else if (strcmp(strval, "false")) {
|
| 627 |
+
bval = 0;
|
| 628 |
+
}
|
| 629 |
+
free(strval);
|
| 630 |
+
}
|
| 631 |
+
break;
|
| 632 |
+
case PLIST_DATA:
|
| 633 |
+
plist_get_data_val(node, &strval, &strsz);
|
| 634 |
+
if (strval) {
|
| 635 |
+
if (strsz == 1) {
|
| 636 |
+
bval = strval[0];
|
| 637 |
+
} else {
|
| 638 |
+
error("%s: ERROR: invalid size %" PRIu64 " for data to boolean conversion\n", __func__, strsz);
|
| 639 |
+
}
|
| 640 |
+
free(strval);
|
| 641 |
+
}
|
| 642 |
+
break;
|
| 643 |
+
default:
|
| 644 |
+
break;
|
| 645 |
+
}
|
| 646 |
+
return bval;
|
| 647 |
+
}
|
common.h
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* common.h
|
| 3 |
+
* Misc functions used in idevicerestore
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2012 Martin Szulecki. All Rights Reserved.
|
| 7 |
+
* Copyright (c) 2010 Joshua Hill. All Rights Reserved.
|
| 8 |
+
*
|
| 9 |
+
* This library is free software; you can redistribute it and/or
|
| 10 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 11 |
+
* License as published by the Free Software Foundation; either
|
| 12 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This library is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 17 |
+
* Lesser General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 20 |
+
* License along with this library; if not, write to the Free Software
|
| 21 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 22 |
+
*/
|
| 23 |
+
|
| 24 |
+
#ifndef IDEVICERESTORE_COMMON_H
|
| 25 |
+
#define IDEVICERESTORE_COMMON_H
|
| 26 |
+
|
| 27 |
+
#ifdef __cplusplus
|
| 28 |
+
extern "C" {
|
| 29 |
+
#endif
|
| 30 |
+
|
| 31 |
+
#ifdef HAVE_CONFIG_H
|
| 32 |
+
#include <config.h>
|
| 33 |
+
#endif
|
| 34 |
+
|
| 35 |
+
#include <inttypes.h>
|
| 36 |
+
#include <unistd.h>
|
| 37 |
+
|
| 38 |
+
#include <plist/plist.h>
|
| 39 |
+
#include <libirecovery.h>
|
| 40 |
+
|
| 41 |
+
#include "idevicerestore.h"
|
| 42 |
+
#include "thread.h"
|
| 43 |
+
|
| 44 |
+
#define MODE_UNKNOWN -1
|
| 45 |
+
#define MODE_WTF 0
|
| 46 |
+
#define MODE_DFU 1
|
| 47 |
+
#define MODE_RECOVERY 2
|
| 48 |
+
#define MODE_RESTORE 3
|
| 49 |
+
#define MODE_NORMAL 4
|
| 50 |
+
|
| 51 |
+
#define FLAG_QUIT 1
|
| 52 |
+
|
| 53 |
+
#define CPFM_FLAG_SECURITY_MODE 1 << 0
|
| 54 |
+
#define CPFM_FLAG_PRODUCTION_MODE 1 << 1
|
| 55 |
+
|
| 56 |
+
#define IBOOT_FLAG_IMAGE4_AWARE 1 << 2
|
| 57 |
+
#define IBOOT_FLAG_EFFECTIVE_SECURITY_MODE 1 << 3
|
| 58 |
+
#define IBOOT_FLAG_EFFECTIVE_PRODUCTION_MODE 1 << 4
|
| 59 |
+
|
| 60 |
+
#define USER_AGENT_STRING "InetURL/1.0"
|
| 61 |
+
|
| 62 |
+
struct dfu_client_t;
|
| 63 |
+
struct normal_client_t;
|
| 64 |
+
struct restore_client_t;
|
| 65 |
+
struct recovery_client_t;
|
| 66 |
+
|
| 67 |
+
struct idevicerestore_mode_t {
|
| 68 |
+
int index;
|
| 69 |
+
const char* string;
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
+
struct idevicerestore_entry_t {
|
| 73 |
+
char* name;
|
| 74 |
+
char* path;
|
| 75 |
+
char* filename;
|
| 76 |
+
char* blob_data;
|
| 77 |
+
uint32_t blob_size;
|
| 78 |
+
struct idevicerestore_entry* next;
|
| 79 |
+
struct idevicerestore_entry* prev;
|
| 80 |
+
};
|
| 81 |
+
|
| 82 |
+
struct idevicerestore_client_t {
|
| 83 |
+
int flags;
|
| 84 |
+
plist_t tss;
|
| 85 |
+
char* tss_url;
|
| 86 |
+
plist_t version_data;
|
| 87 |
+
uint64_t ecid;
|
| 88 |
+
unsigned char* nonce;
|
| 89 |
+
int nonce_size;
|
| 90 |
+
int image4supported;
|
| 91 |
+
plist_t preflight_info;
|
| 92 |
+
char* udid;
|
| 93 |
+
char* srnm;
|
| 94 |
+
char* ipsw;
|
| 95 |
+
const char* filesystem;
|
| 96 |
+
struct dfu_client_t* dfu;
|
| 97 |
+
struct restore_client_t* restore;
|
| 98 |
+
struct recovery_client_t* recovery;
|
| 99 |
+
irecv_device_t device;
|
| 100 |
+
struct idevicerestore_entry_t** entries;
|
| 101 |
+
struct idevicerestore_mode_t* mode;
|
| 102 |
+
char* version;
|
| 103 |
+
char* build;
|
| 104 |
+
int build_major;
|
| 105 |
+
char* restore_boot_args;
|
| 106 |
+
char* cache_dir;
|
| 107 |
+
unsigned char* root_ticket;
|
| 108 |
+
int root_ticket_len;
|
| 109 |
+
idevicerestore_progress_cb_t progress_cb;
|
| 110 |
+
void* progress_cb_data;
|
| 111 |
+
irecv_device_event_context_t irecv_e_ctx;
|
| 112 |
+
void* idevice_e_ctx;
|
| 113 |
+
mutex_t device_event_mutex;
|
| 114 |
+
cond_t device_event_cond;
|
| 115 |
+
int ignore_device_add_events;
|
| 116 |
+
};
|
| 117 |
+
|
| 118 |
+
extern struct idevicerestore_mode_t idevicerestore_modes[];
|
| 119 |
+
|
| 120 |
+
extern int idevicerestore_debug;
|
| 121 |
+
|
| 122 |
+
__attribute__((format(printf, 1, 2)))
|
| 123 |
+
void info(const char* format, ...);
|
| 124 |
+
__attribute__((format(printf, 1, 2)))
|
| 125 |
+
void error(const char* format, ...);
|
| 126 |
+
__attribute__((format(printf, 1, 2)))
|
| 127 |
+
void debug(const char* format, ...);
|
| 128 |
+
|
| 129 |
+
void debug_plist(plist_t plist);
|
| 130 |
+
void print_progress_bar(double progress);
|
| 131 |
+
int read_file(const char* filename, void** data, size_t* size);
|
| 132 |
+
int write_file(const char* filename, const void* data, size_t size);
|
| 133 |
+
|
| 134 |
+
char *generate_guid(void);
|
| 135 |
+
|
| 136 |
+
#ifdef WIN32
|
| 137 |
+
#include <windows.h>
|
| 138 |
+
#include <unistd.h>
|
| 139 |
+
#define __mkdir(path, mode) mkdir(path)
|
| 140 |
+
#ifndef sleep
|
| 141 |
+
#define sleep(x) Sleep(x*1000)
|
| 142 |
+
#endif
|
| 143 |
+
#define __usleep(x) Sleep(x/1000)
|
| 144 |
+
#else
|
| 145 |
+
#include <sys/stat.h>
|
| 146 |
+
#define __mkdir(path, mode) mkdir(path, mode)
|
| 147 |
+
#define __usleep(x) usleep(x)
|
| 148 |
+
#endif
|
| 149 |
+
|
| 150 |
+
int mkdir_with_parents(const char *dir, int mode);
|
| 151 |
+
|
| 152 |
+
char *get_temp_filename(const char *prefix);
|
| 153 |
+
|
| 154 |
+
void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress);
|
| 155 |
+
|
| 156 |
+
#ifndef HAVE_STRSEP
|
| 157 |
+
char* strsep(char** strp, const char* delim);
|
| 158 |
+
#endif
|
| 159 |
+
|
| 160 |
+
#ifndef HAVE_REALPATH
|
| 161 |
+
char* realpath(const char *filename, char *resolved_name);
|
| 162 |
+
#endif
|
| 163 |
+
|
| 164 |
+
void get_user_input(char *buf, int maxlen, int secure);
|
| 165 |
+
|
| 166 |
+
uint8_t _plist_dict_get_bool(plist_t dict, const char *key);
|
| 167 |
+
uint64_t _plist_dict_get_uint(plist_t dict, const char *key);
|
| 168 |
+
|
| 169 |
+
#ifdef __cplusplus
|
| 170 |
+
}
|
| 171 |
+
#endif
|
| 172 |
+
|
| 173 |
+
#endif
|
companion_proxy.c
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* companion_proxy.c
|
| 3 |
+
* com.apple.companion_proxy service implementation.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2019-2020 Nikias Bassen, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifdef HAVE_CONFIG_H
|
| 23 |
+
#include <config.h>
|
| 24 |
+
#endif
|
| 25 |
+
#include <string.h>
|
| 26 |
+
#include <stdlib.h>
|
| 27 |
+
#include <plist/plist.h>
|
| 28 |
+
|
| 29 |
+
#include "companion_proxy.h"
|
| 30 |
+
#include "lockdown.h"
|
| 31 |
+
#include "common/debug.h"
|
| 32 |
+
|
| 33 |
+
/**
|
| 34 |
+
* Convert a property_list_service_error_t value to a companion_proxy_error_t value.
|
| 35 |
+
* Used internally to get correct error codes.
|
| 36 |
+
*
|
| 37 |
+
* @param err An property_list_service_error_t error code
|
| 38 |
+
*
|
| 39 |
+
* @return A matching companion_proxy_error_t error code,
|
| 40 |
+
* COMPANION_PROXY_E_UNKNOWN_ERROR otherwise.
|
| 41 |
+
*/
|
| 42 |
+
static companion_proxy_error_t companion_proxy_error(property_list_service_error_t err)
|
| 43 |
+
{
|
| 44 |
+
switch (err) {
|
| 45 |
+
case PROPERTY_LIST_SERVICE_E_SUCCESS:
|
| 46 |
+
return COMPANION_PROXY_E_SUCCESS;
|
| 47 |
+
case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
|
| 48 |
+
return COMPANION_PROXY_E_INVALID_ARG;
|
| 49 |
+
case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
|
| 50 |
+
return COMPANION_PROXY_E_PLIST_ERROR;
|
| 51 |
+
case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
|
| 52 |
+
return COMPANION_PROXY_E_MUX_ERROR;
|
| 53 |
+
case PROPERTY_LIST_SERVICE_E_SSL_ERROR:
|
| 54 |
+
return COMPANION_PROXY_E_SSL_ERROR;
|
| 55 |
+
case PROPERTY_LIST_SERVICE_E_NOT_ENOUGH_DATA:
|
| 56 |
+
return COMPANION_PROXY_E_NOT_ENOUGH_DATA;
|
| 57 |
+
case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT:
|
| 58 |
+
return COMPANION_PROXY_E_TIMEOUT;
|
| 59 |
+
default:
|
| 60 |
+
break;
|
| 61 |
+
}
|
| 62 |
+
return COMPANION_PROXY_E_UNKNOWN_ERROR;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
companion_proxy_error_t companion_proxy_client_new(idevice_t device, lockdownd_service_descriptor_t service, companion_proxy_client_t * client)
|
| 66 |
+
{
|
| 67 |
+
*client = NULL;
|
| 68 |
+
|
| 69 |
+
if (!device || !service || service->port == 0 || !client || *client) {
|
| 70 |
+
debug_info("Incorrect parameter passed to companion_proxy_client_new.");
|
| 71 |
+
return COMPANION_PROXY_E_INVALID_ARG;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
debug_info("Creating companion_proxy_client, port = %d.", service->port);
|
| 75 |
+
|
| 76 |
+
property_list_service_client_t plclient = NULL;
|
| 77 |
+
companion_proxy_error_t ret = companion_proxy_error(property_list_service_client_new(device, service, &plclient));
|
| 78 |
+
if (ret != COMPANION_PROXY_E_SUCCESS) {
|
| 79 |
+
debug_info("Creating a property list client failed. Error: %i", ret);
|
| 80 |
+
return ret;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
companion_proxy_client_t client_loc = (companion_proxy_client_t) malloc(sizeof(struct companion_proxy_client_private));
|
| 84 |
+
client_loc->parent = plclient;
|
| 85 |
+
client_loc->event_thread = THREAD_T_NULL;
|
| 86 |
+
|
| 87 |
+
*client = client_loc;
|
| 88 |
+
|
| 89 |
+
debug_info("Created companion_proxy_client successfully.");
|
| 90 |
+
return COMPANION_PROXY_E_SUCCESS;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
companion_proxy_error_t companion_proxy_client_start_service(idevice_t device, companion_proxy_client_t * client, const char* label)
|
| 94 |
+
{
|
| 95 |
+
companion_proxy_error_t err = COMPANION_PROXY_E_UNKNOWN_ERROR;
|
| 96 |
+
service_client_factory_start_service(device, COMPANION_PROXY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(companion_proxy_client_new), &err);
|
| 97 |
+
return err;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
companion_proxy_error_t companion_proxy_client_free(companion_proxy_client_t client)
|
| 101 |
+
{
|
| 102 |
+
if (!client)
|
| 103 |
+
return COMPANION_PROXY_E_INVALID_ARG;
|
| 104 |
+
|
| 105 |
+
property_list_service_client_t parent = client->parent;
|
| 106 |
+
client->parent = NULL;
|
| 107 |
+
if (client->event_thread) {
|
| 108 |
+
debug_info("joining event thread");
|
| 109 |
+
thread_join(client->event_thread);
|
| 110 |
+
thread_free(client->event_thread);
|
| 111 |
+
client->event_thread = THREAD_T_NULL;
|
| 112 |
+
}
|
| 113 |
+
companion_proxy_error_t err = companion_proxy_error(property_list_service_client_free(parent));
|
| 114 |
+
free(client);
|
| 115 |
+
|
| 116 |
+
return err;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
companion_proxy_error_t companion_proxy_send(companion_proxy_client_t client, plist_t plist)
|
| 120 |
+
{
|
| 121 |
+
companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR;
|
| 122 |
+
|
| 123 |
+
res = companion_proxy_error(property_list_service_send_binary_plist(client->parent, plist));
|
| 124 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 125 |
+
debug_info("Sending plist failed with error %d", res);
|
| 126 |
+
return res;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
return res;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
companion_proxy_error_t companion_proxy_receive(companion_proxy_client_t client, plist_t * plist)
|
| 133 |
+
{
|
| 134 |
+
companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR;
|
| 135 |
+
plist_t outplist = NULL;
|
| 136 |
+
res = companion_proxy_error(property_list_service_receive_plist_with_timeout(client->parent, &outplist, 10000));
|
| 137 |
+
if (res != COMPANION_PROXY_E_SUCCESS && res != COMPANION_PROXY_E_TIMEOUT) {
|
| 138 |
+
debug_info("Could not receive plist, error %d", res);
|
| 139 |
+
plist_free(outplist);
|
| 140 |
+
} else if (res == COMPANION_PROXY_E_SUCCESS) {
|
| 141 |
+
*plist = outplist;
|
| 142 |
+
}
|
| 143 |
+
return res;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
companion_proxy_error_t companion_proxy_get_device_registry(companion_proxy_client_t client, plist_t* paired_devices)
|
| 147 |
+
{
|
| 148 |
+
if (!client || !paired_devices) {
|
| 149 |
+
return COMPANION_PROXY_E_INVALID_ARG;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
plist_t dict = plist_new_dict();
|
| 153 |
+
plist_dict_set_item(dict, "Command", plist_new_string("GetDeviceRegistry"));
|
| 154 |
+
|
| 155 |
+
companion_proxy_error_t res = companion_proxy_send(client, dict);
|
| 156 |
+
plist_free(dict);
|
| 157 |
+
dict = NULL;
|
| 158 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 159 |
+
return res;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
res = companion_proxy_receive(client, &dict);
|
| 163 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 164 |
+
return res;
|
| 165 |
+
}
|
| 166 |
+
if (!dict || !PLIST_IS_DICT(dict)) {
|
| 167 |
+
return COMPANION_PROXY_E_PLIST_ERROR;
|
| 168 |
+
}
|
| 169 |
+
plist_t val = plist_dict_get_item(dict, "PairedDevicesArray");
|
| 170 |
+
if (val) {
|
| 171 |
+
*paired_devices = plist_copy(val);
|
| 172 |
+
res = COMPANION_PROXY_E_SUCCESS;
|
| 173 |
+
} else {
|
| 174 |
+
res = COMPANION_PROXY_E_UNKNOWN_ERROR;
|
| 175 |
+
val = plist_dict_get_item(dict, "Error");
|
| 176 |
+
if (val) {
|
| 177 |
+
if (plist_string_val_compare(val, "NoPairedWatches")) {
|
| 178 |
+
res = COMPANION_PROXY_E_NO_DEVICES;
|
| 179 |
+
}
|
| 180 |
+
}
|
| 181 |
+
}
|
| 182 |
+
plist_free(dict);
|
| 183 |
+
return res;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
struct companion_proxy_cb_data {
|
| 187 |
+
companion_proxy_client_t client;
|
| 188 |
+
companion_proxy_device_event_cb_t cbfunc;
|
| 189 |
+
void* user_data;
|
| 190 |
+
};
|
| 191 |
+
|
| 192 |
+
static void* companion_proxy_event_thread(void* arg)
|
| 193 |
+
{
|
| 194 |
+
struct companion_proxy_cb_data* data = (struct companion_proxy_cb_data*)arg;
|
| 195 |
+
companion_proxy_client_t client = data->client;
|
| 196 |
+
companion_proxy_error_t res;
|
| 197 |
+
|
| 198 |
+
plist_t command = plist_new_dict();
|
| 199 |
+
plist_dict_set_item(command, "Command", plist_new_string("StartListeningForDevices"));
|
| 200 |
+
res = companion_proxy_send(client, command);
|
| 201 |
+
plist_free(command);
|
| 202 |
+
|
| 203 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 204 |
+
free(data);
|
| 205 |
+
client->event_thread = THREAD_T_NULL;
|
| 206 |
+
return NULL;
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
while (client && client->parent) {
|
| 210 |
+
plist_t node = NULL;
|
| 211 |
+
res = companion_proxy_error(property_list_service_receive_plist_with_timeout(client->parent, &node, 1000));
|
| 212 |
+
if (res != COMPANION_PROXY_E_SUCCESS && res != COMPANION_PROXY_E_TIMEOUT) {
|
| 213 |
+
debug_info("could not receive plist, error %d", res);
|
| 214 |
+
break;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
if (node) {
|
| 218 |
+
data->cbfunc(node, data->user_data);
|
| 219 |
+
}
|
| 220 |
+
plist_free(node);
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
client->event_thread = THREAD_T_NULL;
|
| 224 |
+
free(data);
|
| 225 |
+
|
| 226 |
+
return NULL;
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
companion_proxy_error_t companion_proxy_start_listening_for_devices(companion_proxy_client_t client, companion_proxy_device_event_cb_t callback, void* userdata)
|
| 230 |
+
{
|
| 231 |
+
if (!client || !client->parent || !callback) {
|
| 232 |
+
return COMPANION_PROXY_E_INVALID_ARG;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
if (client->event_thread) {
|
| 236 |
+
return COMPANION_PROXY_E_OP_IN_PROGRESS;
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
companion_proxy_error_t res = COMPANION_PROXY_E_UNKNOWN_ERROR;
|
| 240 |
+
struct companion_proxy_cb_data *data = (struct companion_proxy_cb_data*)malloc(sizeof(struct companion_proxy_cb_data));
|
| 241 |
+
if (data) {
|
| 242 |
+
data->client = client;
|
| 243 |
+
data->cbfunc = callback;
|
| 244 |
+
data->user_data = userdata;
|
| 245 |
+
|
| 246 |
+
if (thread_new(&client->event_thread, companion_proxy_event_thread, data) == 0) {
|
| 247 |
+
res = COMPANION_PROXY_E_SUCCESS;
|
| 248 |
+
} else {
|
| 249 |
+
free(data);
|
| 250 |
+
}
|
| 251 |
+
}
|
| 252 |
+
return res;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
companion_proxy_error_t companion_proxy_stop_listening_for_devices(companion_proxy_client_t client)
|
| 256 |
+
{
|
| 257 |
+
property_list_service_client_t parent = client->parent;
|
| 258 |
+
client->parent = NULL;
|
| 259 |
+
if (client->event_thread) {
|
| 260 |
+
debug_info("joining event thread");
|
| 261 |
+
thread_join(client->event_thread);
|
| 262 |
+
thread_free(client->event_thread);
|
| 263 |
+
client->event_thread = THREAD_T_NULL;
|
| 264 |
+
}
|
| 265 |
+
client->parent = parent;
|
| 266 |
+
return COMPANION_PROXY_E_SUCCESS;
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
companion_proxy_error_t companion_proxy_get_value_from_registry(companion_proxy_client_t client, const char* companion_udid, const char* key, plist_t* value)
|
| 270 |
+
{
|
| 271 |
+
if (!client || !companion_udid || !key || !value) {
|
| 272 |
+
return COMPANION_PROXY_E_INVALID_ARG;
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
plist_t dict = plist_new_dict();
|
| 276 |
+
plist_dict_set_item(dict, "Command", plist_new_string("GetValueFromRegistry"));
|
| 277 |
+
plist_dict_set_item(dict, "GetValueGizmoUDIDKey", plist_new_string(companion_udid));
|
| 278 |
+
plist_dict_set_item(dict, "GetValueKeyKey", plist_new_string(key));
|
| 279 |
+
|
| 280 |
+
companion_proxy_error_t res = companion_proxy_send(client, dict);
|
| 281 |
+
plist_free(dict);
|
| 282 |
+
dict = NULL;
|
| 283 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 284 |
+
return res;
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
res = companion_proxy_receive(client, &dict);
|
| 288 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 289 |
+
return res;
|
| 290 |
+
}
|
| 291 |
+
if (!dict || !PLIST_IS_DICT(dict)) {
|
| 292 |
+
return COMPANION_PROXY_E_PLIST_ERROR;
|
| 293 |
+
}
|
| 294 |
+
plist_t val = plist_dict_get_item(dict, "RetrievedValueDictionary");
|
| 295 |
+
if (val) {
|
| 296 |
+
*value = plist_copy(val);
|
| 297 |
+
res = COMPANION_PROXY_E_SUCCESS;
|
| 298 |
+
} else {
|
| 299 |
+
res = COMPANION_PROXY_E_UNKNOWN_ERROR;
|
| 300 |
+
val = plist_dict_get_item(dict, "Error");
|
| 301 |
+
if (val) {
|
| 302 |
+
if (!plist_string_val_compare(val, "UnsupportedWatchKey")) {
|
| 303 |
+
res = COMPANION_PROXY_E_UNSUPPORTED_KEY;
|
| 304 |
+
} else if (plist_string_val_compare(val, "TimeoutReply")) {
|
| 305 |
+
res = COMPANION_PROXY_E_TIMEOUT_REPLY;
|
| 306 |
+
}
|
| 307 |
+
}
|
| 308 |
+
}
|
| 309 |
+
plist_free(dict);
|
| 310 |
+
return res;
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
companion_proxy_error_t companion_proxy_start_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port, const char* service_name, uint16_t* forward_port, plist_t options)
|
| 314 |
+
{
|
| 315 |
+
if (!client) {
|
| 316 |
+
return COMPANION_PROXY_E_INVALID_ARG;
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
plist_t dict = plist_new_dict();
|
| 320 |
+
plist_dict_set_item(dict, "Command", plist_new_string("StartForwardingServicePort"));
|
| 321 |
+
plist_dict_set_item(dict, "GizmoRemotePortNumber", plist_new_uint(remote_port));
|
| 322 |
+
if (service_name) {
|
| 323 |
+
plist_dict_set_item(dict, "ForwardedServiceName", plist_new_string(service_name));
|
| 324 |
+
}
|
| 325 |
+
plist_dict_set_item(dict, "IsServiceLowPriority", plist_new_bool(0));
|
| 326 |
+
plist_dict_set_item(dict, "PreferWifi", plist_new_bool(0));
|
| 327 |
+
if (options) {
|
| 328 |
+
plist_dict_merge(&dict, options);
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
companion_proxy_error_t res = companion_proxy_send(client, dict);
|
| 332 |
+
plist_free(dict);
|
| 333 |
+
dict = NULL;
|
| 334 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 335 |
+
return res;
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
res = companion_proxy_receive(client, &dict);
|
| 339 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 340 |
+
return res;
|
| 341 |
+
}
|
| 342 |
+
plist_t val = plist_dict_get_item(dict, "CompanionProxyServicePort");
|
| 343 |
+
if (val) {
|
| 344 |
+
uint64_t u64val = 0;
|
| 345 |
+
plist_get_uint_val(val, &u64val);
|
| 346 |
+
*forward_port = (uint16_t)u64val;
|
| 347 |
+
res = COMPANION_PROXY_E_SUCCESS;
|
| 348 |
+
} else {
|
| 349 |
+
res = COMPANION_PROXY_E_UNKNOWN_ERROR;
|
| 350 |
+
}
|
| 351 |
+
plist_free(dict);
|
| 352 |
+
|
| 353 |
+
return res;
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
companion_proxy_error_t companion_proxy_stop_forwarding_service_port(companion_proxy_client_t client, uint16_t remote_port)
|
| 357 |
+
{
|
| 358 |
+
if (!client) {
|
| 359 |
+
return COMPANION_PROXY_E_INVALID_ARG;
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
plist_t dict = plist_new_dict();
|
| 363 |
+
plist_dict_set_item(dict, "Command", plist_new_string("StopForwardingServicePort"));
|
| 364 |
+
plist_dict_set_item(dict, "GizmoRemotePortNumber", plist_new_uint(remote_port));
|
| 365 |
+
|
| 366 |
+
companion_proxy_error_t res = companion_proxy_send(client, dict);
|
| 367 |
+
plist_free(dict);
|
| 368 |
+
dict = NULL;
|
| 369 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 370 |
+
return res;
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
res = companion_proxy_receive(client, &dict);
|
| 374 |
+
if (res != COMPANION_PROXY_E_SUCCESS) {
|
| 375 |
+
return res;
|
| 376 |
+
}
|
| 377 |
+
plist_free(dict);
|
| 378 |
+
|
| 379 |
+
return res;
|
| 380 |
+
}
|
companion_proxy.h
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* companion_proxy.h
|
| 3 |
+
* com.apple.companion_proxy service header file.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2019-2020 Nikias Bassen, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifndef __COMPANION_PROXY_H
|
| 23 |
+
#define __COMPANION_PROXY_H
|
| 24 |
+
|
| 25 |
+
#include "idevice.h"
|
| 26 |
+
#include "libimobiledevice/companion_proxy.h"
|
| 27 |
+
#include "property_list_service.h"
|
| 28 |
+
#include <libimobiledevice-glue/thread.h>
|
| 29 |
+
|
| 30 |
+
struct companion_proxy_client_private {
|
| 31 |
+
property_list_service_client_t parent;
|
| 32 |
+
THREAD_T event_thread;
|
| 33 |
+
};
|
| 34 |
+
|
| 35 |
+
#endif
|
configure.ac
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- Autoconf -*-
|
| 2 |
+
# Process this file with autoconf to produce a configure script.
|
| 3 |
+
|
| 4 |
+
AC_PREREQ([2.68])
|
| 5 |
+
AC_INIT([libimobiledevice], [m4_esyscmd(./git-version-gen $RELEASE_VERSION)], [https://github.com/libimobiledevice/libimobiledevice/issues], [], [https://libimobiledevice.org])
|
| 6 |
+
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip check-news])
|
| 7 |
+
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
|
| 8 |
+
AC_CONFIG_SRCDIR([src/])
|
| 9 |
+
AC_CONFIG_HEADERS([config.h])
|
| 10 |
+
AC_CONFIG_MACRO_DIR([m4])
|
| 11 |
+
|
| 12 |
+
dnl libtool versioning
|
| 13 |
+
# +1 : 0 : +1 == adds new functions to the interface
|
| 14 |
+
# +1 : 0 : 0 == changes or removes functions (changes include both
|
| 15 |
+
# changes to the signature and the semantic)
|
| 16 |
+
# ? :+1 : ? == just internal changes
|
| 17 |
+
# CURRENT : REVISION : AGE
|
| 18 |
+
LIBIMOBILEDEVICE_SO_VERSION=7:0:1
|
| 19 |
+
|
| 20 |
+
AC_SUBST(LIBIMOBILEDEVICE_SO_VERSION)
|
| 21 |
+
|
| 22 |
+
# Check if we have a version defined
|
| 23 |
+
if test -z $PACKAGE_VERSION; then
|
| 24 |
+
AC_MSG_ERROR([PACKAGE_VERSION is not defined. Make sure to configure a source tree checked out from git or that .tarball-version is present.])
|
| 25 |
+
fi
|
| 26 |
+
|
| 27 |
+
dnl Minimum package versions
|
| 28 |
+
LIBUSBMUXD_VERSION=2.0.2
|
| 29 |
+
LIBPLIST_VERSION=2.3.0
|
| 30 |
+
LIMD_GLUE_VERSION=1.3.0
|
| 31 |
+
LIBTATSU_VERSION=1.0.3
|
| 32 |
+
|
| 33 |
+
AC_SUBST(LIBUSBMUXD_VERSION)
|
| 34 |
+
AC_SUBST(LIBPLIST_VERSION)
|
| 35 |
+
AC_SUBST(LIMD_GLUE_VERSION)
|
| 36 |
+
|
| 37 |
+
# Checks for programs.
|
| 38 |
+
AC_PROG_CC
|
| 39 |
+
AC_PROG_CXX
|
| 40 |
+
AM_PROG_CC_C_O
|
| 41 |
+
LT_INIT
|
| 42 |
+
|
| 43 |
+
# Checks for libraries.
|
| 44 |
+
PKG_CHECK_MODULES(libusbmuxd, libusbmuxd-2.0 >= $LIBUSBMUXD_VERSION)
|
| 45 |
+
PKG_CHECK_MODULES(libplist, libplist-2.0 >= $LIBPLIST_VERSION)
|
| 46 |
+
PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= $LIMD_GLUE_VERSION)
|
| 47 |
+
PKG_CHECK_MODULES(libtatsu, libtatsu-1.0 >= $LIBTATSU_VERSION)
|
| 48 |
+
AC_ARG_WITH([readline],
|
| 49 |
+
[AS_HELP_STRING([--without-readline],
|
| 50 |
+
[build without support for libreadline (default is yes)])],
|
| 51 |
+
[check_libreadline=false],
|
| 52 |
+
[check_libreadline=true])
|
| 53 |
+
if test "$check_libreadline" = "true"; then
|
| 54 |
+
PKG_CHECK_MODULES(readline, readline >= 1.0, have_readline=yes, have_readline=no)
|
| 55 |
+
if test "x$have_readline" = "xyes"; then
|
| 56 |
+
AC_DEFINE(HAVE_READLINE, 1, [Define if readline library is available])
|
| 57 |
+
fi
|
| 58 |
+
fi
|
| 59 |
+
AM_CONDITIONAL([HAVE_READLINE],[test "x$have_readline" = "xyes"])
|
| 60 |
+
|
| 61 |
+
# Checks for header files.
|
| 62 |
+
AC_CHECK_HEADERS([stdint.h stdlib.h string.h sys/time.h])
|
| 63 |
+
|
| 64 |
+
# Checks for typedefs, structures, and compiler characteristics.
|
| 65 |
+
AC_C_CONST
|
| 66 |
+
AC_TYPE_SIZE_T
|
| 67 |
+
AC_TYPE_SSIZE_T
|
| 68 |
+
AC_TYPE_UINT16_T
|
| 69 |
+
AC_TYPE_UINT32_T
|
| 70 |
+
AC_TYPE_UINT8_T
|
| 71 |
+
|
| 72 |
+
# Checks for library functions.
|
| 73 |
+
AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf getifaddrs gettimeofday localtime_r])
|
| 74 |
+
|
| 75 |
+
AC_CHECK_HEADER(endian.h, [ac_cv_have_endian_h="yes"], [ac_cv_have_endian_h="no"])
|
| 76 |
+
if test "x$ac_cv_have_endian_h" = "xno"; then
|
| 77 |
+
AC_DEFINE(__LITTLE_ENDIAN,1234,[little endian])
|
| 78 |
+
AC_DEFINE(__BIG_ENDIAN,4321,[big endian])
|
| 79 |
+
AC_C_BIGENDIAN([ac_cv_c_bigendian="yes"], [ac_cv_c_bigendian="no"], [], [])
|
| 80 |
+
if test "x$ac_cv_c_bigendian" = "xyes"; then
|
| 81 |
+
AC_DEFINE(__BYTE_ORDER,4321,[big endian byte order])
|
| 82 |
+
else
|
| 83 |
+
AC_DEFINE(__BYTE_ORDER,1234,[little endian byte order])
|
| 84 |
+
fi
|
| 85 |
+
fi
|
| 86 |
+
|
| 87 |
+
CACHED_CFLAGS="$CFLAGS"
|
| 88 |
+
CFLAGS+=" $libplist_CFLAGS -Werror"
|
| 89 |
+
|
| 90 |
+
AC_CHECK_DECL([plist_from_json], [AC_DEFINE([HAVE_PLIST_JSON], [1], [Define if libplist has JSON support])], [], [[#include <plist/plist.h>]])
|
| 91 |
+
|
| 92 |
+
# check if libplist has plist_new_unix_date()
|
| 93 |
+
AC_CACHE_CHECK(for plist_new_unix_date, ac_cv_plist_unix_date,
|
| 94 |
+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
| 95 |
+
#include <plist/plist.h>
|
| 96 |
+
]], [[
|
| 97 |
+
return plist_new_unix_date(0) ? 0 : 1
|
| 98 |
+
]])],[ac_cv_plist_unix_date=yes],[ac_cv_plist_unix_date=no]))
|
| 99 |
+
if test "$ac_cv_plist_unix_date" = "yes"; then
|
| 100 |
+
AC_DEFINE(HAVE_PLIST_UNIX_DATE, 1, [Define if libplist has new unix date API (>= 2.7.0)])
|
| 101 |
+
fi
|
| 102 |
+
|
| 103 |
+
CFLAGS="$CACHED_CFLAGS"
|
| 104 |
+
|
| 105 |
+
# Check for operating system
|
| 106 |
+
AC_MSG_CHECKING([for platform-specific build settings])
|
| 107 |
+
case ${host_os} in
|
| 108 |
+
*mingw32*|*cygwin*)
|
| 109 |
+
AC_MSG_RESULT([${host_os}])
|
| 110 |
+
win32=true
|
| 111 |
+
AC_DEFINE(WINVER, 0x0501, [minimum Windows version])
|
| 112 |
+
deplibs_check_method='pass_all'
|
| 113 |
+
;;
|
| 114 |
+
darwin*)
|
| 115 |
+
AC_MSG_RESULT([${host_os}])
|
| 116 |
+
darwin=true
|
| 117 |
+
;;
|
| 118 |
+
*)
|
| 119 |
+
AC_MSG_RESULT([${host_os}])
|
| 120 |
+
AX_PTHREAD([], [AC_MSG_ERROR([pthread is required to build $PACKAGE_NAME])])
|
| 121 |
+
AC_CHECK_LIB(pthread, [pthread_once], [], [AC_MSG_ERROR([pthread with pthread_once required to build $PACKAGE_NAME])])
|
| 122 |
+
;;
|
| 123 |
+
esac
|
| 124 |
+
AM_CONDITIONAL(WIN32, test x$win32 = xtrue)
|
| 125 |
+
AM_CONDITIONAL(DARWIN, test x$darwin = xtrue)
|
| 126 |
+
|
| 127 |
+
AC_CHECK_MEMBER(struct dirent.d_type, AC_DEFINE(HAVE_DIRENT_D_TYPE, 1, [define if struct dirent has member d_type]),, [#include <dirent.h>])
|
| 128 |
+
|
| 129 |
+
# Cython Python Bindings
|
| 130 |
+
AC_ARG_WITH([cython],
|
| 131 |
+
[AS_HELP_STRING([--without-cython],
|
| 132 |
+
[build Python bindings using Cython (default is yes)])],
|
| 133 |
+
[build_cython=false],
|
| 134 |
+
[build_cython=true])
|
| 135 |
+
if test "$build_cython" = "true"; then
|
| 136 |
+
AC_PROG_CYTHON([3.0.0])
|
| 137 |
+
if [test "x$CYTHON" != "xfalse"]; then
|
| 138 |
+
AM_PATH_PYTHON([3.0], [
|
| 139 |
+
CYTHON_PYTHON
|
| 140 |
+
AS_COMPILER_FLAG([-Wno-cast-function-type -Werror], [
|
| 141 |
+
CYTHON_CFLAGS+=" -Wno-cast-function-type"
|
| 142 |
+
AC_SUBST([CYTHON_CFLAGS])
|
| 143 |
+
], [])
|
| 144 |
+
])
|
| 145 |
+
else
|
| 146 |
+
AC_MSG_WARN([Use the "--without-cython" option to avoid this warning.])
|
| 147 |
+
fi
|
| 148 |
+
else
|
| 149 |
+
CYTHON=false
|
| 150 |
+
fi
|
| 151 |
+
if [test "x$CYTHON" != "xfalse"]; then
|
| 152 |
+
PKG_PROG_PKG_CONFIG
|
| 153 |
+
AC_MSG_CHECKING([for libplist Cython bindings])
|
| 154 |
+
CYTHON_PLIST_INCLUDE_DIR=$($PKG_CONFIG --variable=includedir libplist-2.0)/plist/cython
|
| 155 |
+
if [test ! -d "$CYTHON_PLIST_INCLUDE_DIR"]; then
|
| 156 |
+
CYTHON=false
|
| 157 |
+
CYTHON_SUB=
|
| 158 |
+
cython_python_bindings=no
|
| 159 |
+
AC_MSG_RESULT([no])
|
| 160 |
+
AC_MSG_WARN([Unable to find libplist Cython bindings. You should install your distribution specific libplist Cython bindings package.])
|
| 161 |
+
else
|
| 162 |
+
AC_SUBST([CYTHON_PLIST_INCLUDE_DIR])
|
| 163 |
+
AC_MSG_RESULT([$CYTHON_PLIST_INCLUDE_DIR])
|
| 164 |
+
CYTHON_SUB=cython
|
| 165 |
+
cython_python_bindings=yes
|
| 166 |
+
fi
|
| 167 |
+
else
|
| 168 |
+
CYTHON_SUB=
|
| 169 |
+
cython_python_bindings=no
|
| 170 |
+
fi
|
| 171 |
+
AM_CONDITIONAL([HAVE_CYTHON],[test "x$CYTHON_SUB" = "xcython"])
|
| 172 |
+
AC_SUBST([CYTHON_SUB])
|
| 173 |
+
|
| 174 |
+
default_openssl=yes
|
| 175 |
+
|
| 176 |
+
AC_ARG_WITH([mbedtls],
|
| 177 |
+
[AS_HELP_STRING([--without-mbedtls],
|
| 178 |
+
[Do not look for mbedtls])],
|
| 179 |
+
[use_mbedtls=$withval],
|
| 180 |
+
[use_mbedtls=no])
|
| 181 |
+
if test "x$use_mbedtls" = "xyes"; then
|
| 182 |
+
default_openssl=no
|
| 183 |
+
fi
|
| 184 |
+
AC_ARG_WITH([gnutls],
|
| 185 |
+
[AS_HELP_STRING([--without-gnutls],
|
| 186 |
+
[Do not look for GnuTLS])],
|
| 187 |
+
[use_gnutls=$withval],
|
| 188 |
+
[use_gnutls=no])
|
| 189 |
+
if test "x$use_gnutls" = "xyes"; then
|
| 190 |
+
default_openssl=no
|
| 191 |
+
fi
|
| 192 |
+
AC_ARG_WITH([openssl],
|
| 193 |
+
[AS_HELP_STRING([--without-openssl],
|
| 194 |
+
[Do not look for OpenSSL])],
|
| 195 |
+
[use_openssl=$withval],
|
| 196 |
+
[use_openssl=$default_openssl])
|
| 197 |
+
|
| 198 |
+
if test "x$use_mbedtls" = "xyes"; then
|
| 199 |
+
CACHED_CFLAGS="$CFLAGS"
|
| 200 |
+
conf_mbedtls_CFLAGS=""
|
| 201 |
+
if test -n "$mbedtls_INCLUDES"; then
|
| 202 |
+
CFLAGS=" -I$mbedtls_INCLUDES"
|
| 203 |
+
conf_mbedtls_CFLAGS="-I$mbedtls_INCLUDES"
|
| 204 |
+
fi
|
| 205 |
+
conf_mbedtls_LIBS=""
|
| 206 |
+
if test -n "$mbedtls_LIBDIR"; then
|
| 207 |
+
conf_mbedtls_LIBS+=" -L$mbedtls_LIBDIR"
|
| 208 |
+
fi
|
| 209 |
+
if test -n "$mbedtls_LIBS"; then
|
| 210 |
+
conf_mbedtls_LIBS+=" $mbedtls_LIBS"
|
| 211 |
+
else
|
| 212 |
+
conf_mbedtls_LIBS+=" -lmbedtls -lmbedx509 -lmbedcrypto"
|
| 213 |
+
fi
|
| 214 |
+
AC_CHECK_HEADER(mbedtls/ssl.h, [break], [AC_MSG_ERROR([MbedTLS support explicitly requested, but includes could not be found. Try setting mbedtls_INCLUDES=/path/to/mbedtls/include])])
|
| 215 |
+
CFLAGS="$CACHED_CFLAGS"
|
| 216 |
+
AC_DEFINE(HAVE_MBEDTLS, 1, [Define if you have MbedTLS support])
|
| 217 |
+
ssl_lib_CFLAGS="$conf_mbedtls_CFLAGS"
|
| 218 |
+
ssl_lib_LIBS="$conf_mbedtls_LIBS"
|
| 219 |
+
AC_SUBST(ssl_lib_CFLAGS)
|
| 220 |
+
AC_SUBST(ssl_lib_LIBS)
|
| 221 |
+
ssl_provider="MbedTLS";
|
| 222 |
+
ssl_requires=""
|
| 223 |
+
AC_SUBST(ssl_requires)
|
| 224 |
+
else
|
| 225 |
+
if test "x$use_openssl" = "xyes"; then
|
| 226 |
+
pkg_req_openssl="openssl >= 0.9.8"
|
| 227 |
+
PKG_CHECK_MODULES(openssl, $pkg_req_openssl, have_openssl=yes, have_openssl=no)
|
| 228 |
+
if test "x$have_openssl" != "xyes"; then
|
| 229 |
+
AC_MSG_ERROR([OpenSSL support explicitly requested but OpenSSL could not be found])
|
| 230 |
+
else
|
| 231 |
+
AC_DEFINE(HAVE_OPENSSL, 1, [Define if you have OpenSSL support])
|
| 232 |
+
ssl_lib_CFLAGS="$openssl_CFLAGS"
|
| 233 |
+
ssl_lib_LIBS="$openssl_LIBS"
|
| 234 |
+
AC_SUBST(ssl_lib_CFLAGS)
|
| 235 |
+
AC_SUBST(ssl_lib_LIBS)
|
| 236 |
+
ssl_provider="OpenSSL";
|
| 237 |
+
ssl_requires="$pkg_req_openssl"
|
| 238 |
+
# test if we have LibreSSL
|
| 239 |
+
CACHED_CFLAGS="$CFLAGS"
|
| 240 |
+
CFLAGS="$openssl_CFLAGS"
|
| 241 |
+
ac_cv_is_libressl=no
|
| 242 |
+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
| 243 |
+
[[
|
| 244 |
+
#include <openssl/opensslv.h>
|
| 245 |
+
]], [
|
| 246 |
+
#ifndef LIBRESSL_VERSION_NUMBER
|
| 247 |
+
#error No LibreSSL
|
| 248 |
+
#endif
|
| 249 |
+
])],
|
| 250 |
+
[
|
| 251 |
+
ac_cv_is_libressl=yes
|
| 252 |
+
],
|
| 253 |
+
)
|
| 254 |
+
CFLAGS="$CACHED_CFLAGS"
|
| 255 |
+
if test "x$ac_cv_is_libressl" = "xyes"; then
|
| 256 |
+
ssl_provider="LibreSSL"
|
| 257 |
+
case ${host_os} in
|
| 258 |
+
darwin*)
|
| 259 |
+
case ${openssl_LIBS} in
|
| 260 |
+
*.tbd*)
|
| 261 |
+
# using system LibreSSL on Darwin
|
| 262 |
+
ssl_requires=""
|
| 263 |
+
;;
|
| 264 |
+
esac
|
| 265 |
+
;;
|
| 266 |
+
esac
|
| 267 |
+
fi
|
| 268 |
+
AC_SUBST(ssl_requires)
|
| 269 |
+
fi
|
| 270 |
+
else
|
| 271 |
+
if test "x$use_gnutls" = "xyes"; then
|
| 272 |
+
pkg_req_gnutls="gnutls >= 2.2.0"
|
| 273 |
+
pkg_req_libtasn1="libtasn1 >= 1.1"
|
| 274 |
+
PKG_CHECK_MODULES(libgnutls, $pkg_req_gnutls)
|
| 275 |
+
AC_CHECK_HEADERS([gcrypt.h])
|
| 276 |
+
AC_CHECK_LIB(gcrypt, gcry_control, [AC_SUBST(libgcrypt_LIBS,[-lgcrypt])], [AC_MSG_ERROR([libgcrypt is required to build libimobiledevice with GnuTLS])])
|
| 277 |
+
PKG_CHECK_MODULES(libtasn1, $pkg_req_libtasn1)
|
| 278 |
+
AC_DEFINE(HAVE_GCRYPT, 1, [Define if you have libgcrypt support])
|
| 279 |
+
AC_DEFINE(HAVE_GNUTLS, 1, [Define if you have GnuTLS support])
|
| 280 |
+
ssl_lib_CFLAGS="$libgnutls_CFLAGS $libtasn1_CFLAGS $libgcrypt_CFLAGS"
|
| 281 |
+
ssl_lib_LIBS="$libgnutls_LIBS $libtasn1_LIBS $libgcrypt_LIBS"
|
| 282 |
+
AC_SUBST(ssl_lib_CFLAGS)
|
| 283 |
+
AC_SUBST(ssl_lib_LIBS)
|
| 284 |
+
ssl_provider="GnuTLS"
|
| 285 |
+
ssl_requires="$pkg_req_gnutls $pkg_req_libtasn1"
|
| 286 |
+
AC_SUBST(ssl_requires)
|
| 287 |
+
else
|
| 288 |
+
AC_MSG_ERROR([No SSL library configured. $PACKAGE cannot be built without a supported SSL library.])
|
| 289 |
+
fi
|
| 290 |
+
fi
|
| 291 |
+
fi
|
| 292 |
+
AM_CONDITIONAL(HAVE_MBEDTLS, test "x$use_mbedtls" = "xyes")
|
| 293 |
+
AM_CONDITIONAL(HAVE_OPENSSL, test "x$use_openssl" = "xyes")
|
| 294 |
+
AM_CONDITIONAL(HAVE_GCRYPT, test "x$use_gnutls" = "xyes")
|
| 295 |
+
|
| 296 |
+
AC_ARG_ENABLE([wireless-pairing],
|
| 297 |
+
[AS_HELP_STRING([--disable-wireless-pairing],
|
| 298 |
+
[Do not build with wirless pairing support (default is yes)])])
|
| 299 |
+
if test "$enable_wireless_pairing" != "no"; then
|
| 300 |
+
AC_DEFINE(HAVE_WIRELESS_PAIRING,1,[Define if building with wireless pairing support])
|
| 301 |
+
fi
|
| 302 |
+
AM_CONDITIONAL(HAVE_WIRELESS_PAIRING, test "$enable_wireless_pairing" != "no")
|
| 303 |
+
|
| 304 |
+
AC_ARG_ENABLE([debug],
|
| 305 |
+
[AS_HELP_STRING([--enable-debug],
|
| 306 |
+
[build debug message output code (default is no)])],
|
| 307 |
+
[no_debug_code=false],
|
| 308 |
+
[no_debug_code=true])
|
| 309 |
+
if test "$no_debug_code" = true; then
|
| 310 |
+
building_debug_code=no
|
| 311 |
+
AC_DEFINE(STRIP_DEBUG_CODE,1,[Define if debug message output code should not be built.])
|
| 312 |
+
else
|
| 313 |
+
building_debug_code=yes
|
| 314 |
+
fi
|
| 315 |
+
|
| 316 |
+
AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -fsigned-char -fvisibility=hidden")
|
| 317 |
+
|
| 318 |
+
if test "x$enable_static" = "xyes" -a "x$enable_shared" = "xno"; then
|
| 319 |
+
GLOBAL_CFLAGS+=" -DLIBIMOBILEDEVICE_STATIC"
|
| 320 |
+
fi
|
| 321 |
+
|
| 322 |
+
AC_SUBST(GLOBAL_CFLAGS)
|
| 323 |
+
|
| 324 |
+
# check for large file support
|
| 325 |
+
AC_SYS_LARGEFILE
|
| 326 |
+
|
| 327 |
+
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
| 328 |
+
|
| 329 |
+
AC_CONFIG_FILES([
|
| 330 |
+
Makefile
|
| 331 |
+
3rd_party/Makefile
|
| 332 |
+
3rd_party/ed25519/Makefile
|
| 333 |
+
3rd_party/libsrp6a-sha512/Makefile
|
| 334 |
+
common/Makefile
|
| 335 |
+
src/Makefile
|
| 336 |
+
src/libimobiledevice-1.0.pc
|
| 337 |
+
include/Makefile
|
| 338 |
+
tools/Makefile
|
| 339 |
+
cython/Makefile
|
| 340 |
+
docs/Makefile
|
| 341 |
+
doxygen.cfg
|
| 342 |
+
])
|
| 343 |
+
AC_OUTPUT
|
| 344 |
+
|
| 345 |
+
echo "
|
| 346 |
+
Configuration for $PACKAGE $VERSION:
|
| 347 |
+
-------------------------------------------
|
| 348 |
+
|
| 349 |
+
Install prefix: .........: $prefix
|
| 350 |
+
Debug code ..............: $building_debug_code
|
| 351 |
+
Python bindings .........: $cython_python_bindings
|
| 352 |
+
SSL support backend .....: $ssl_provider
|
| 353 |
+
|
| 354 |
+
Now type 'make' to build $PACKAGE $VERSION,
|
| 355 |
+
and then 'make install' for installation.
|
| 356 |
+
"
|
cython_python.m4
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
AC_DEFUN([CYTHON_PYTHON],[
|
| 2 |
+
AC_REQUIRE([AC_PROG_CYTHON])
|
| 3 |
+
AC_REQUIRE([AX_PYTHON_DEVEL])
|
| 4 |
+
test "x$1" != "xno" || cython_shadow=" -noproxy"
|
| 5 |
+
AC_SUBST([CYTHON_PYTHON_OPT],[-python$cython_shadow])
|
| 6 |
+
AC_SUBST([CYTHON_PYTHON_CPPFLAGS],[$PYTHON_CPPFLAGS])
|
| 7 |
+
])
|
debug.c
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* debug.c
|
| 3 |
+
* contains utilitary functions for debugging
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2008 Jonathan Beck All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2010 Martin S. All Rights Reserved.
|
| 7 |
+
*
|
| 8 |
+
* This library is free software; you can redistribute it and/or
|
| 9 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 10 |
+
* License as published by the Free Software Foundation; either
|
| 11 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 12 |
+
*
|
| 13 |
+
* This library is distributed in the hope that it will be useful,
|
| 14 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 15 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 16 |
+
* Lesser General Public License for more details.
|
| 17 |
+
*
|
| 18 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 19 |
+
* License along with this library; if not, write to the Free Software
|
| 20 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 21 |
+
*/
|
| 22 |
+
|
| 23 |
+
#ifdef HAVE_CONFIG_H
|
| 24 |
+
#include <config.h>
|
| 25 |
+
#endif
|
| 26 |
+
#include <stdarg.h>
|
| 27 |
+
#define _GNU_SOURCE 1
|
| 28 |
+
#define __USE_GNU 1
|
| 29 |
+
#include <stdio.h>
|
| 30 |
+
#include <stdint.h>
|
| 31 |
+
#include <stdlib.h>
|
| 32 |
+
#include <time.h>
|
| 33 |
+
#ifndef _WIN32
|
| 34 |
+
#include <sys/time.h>
|
| 35 |
+
#endif
|
| 36 |
+
|
| 37 |
+
#include "src/idevice.h"
|
| 38 |
+
#include "debug.h"
|
| 39 |
+
#include "libimobiledevice/libimobiledevice.h"
|
| 40 |
+
|
| 41 |
+
#ifndef STRIP_DEBUG_CODE
|
| 42 |
+
#include "asprintf.h"
|
| 43 |
+
#endif
|
| 44 |
+
|
| 45 |
+
static int debug_level;
|
| 46 |
+
|
| 47 |
+
void internal_set_debug_level(int level)
|
| 48 |
+
{
|
| 49 |
+
debug_level = level;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
#define MAX_PRINT_LEN (16*1024)
|
| 53 |
+
|
| 54 |
+
#ifndef STRIP_DEBUG_CODE
|
| 55 |
+
static void debug_print_line(const char *func, const char *file, int line, const char *buffer)
|
| 56 |
+
{
|
| 57 |
+
char str_time[24];
|
| 58 |
+
#ifdef _WIN32
|
| 59 |
+
SYSTEMTIME lt;
|
| 60 |
+
GetLocalTime(<);
|
| 61 |
+
snprintf(str_time, 24, "%02d:%02d:%02d.%03d", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds);
|
| 62 |
+
#else
|
| 63 |
+
#ifdef HAVE_GETTIMEOFDAY
|
| 64 |
+
struct timeval tv;
|
| 65 |
+
struct tm *tp;
|
| 66 |
+
gettimeofday(&tv, NULL);
|
| 67 |
+
#ifdef HAVE_LOCALTIME_R
|
| 68 |
+
struct tm tp_;
|
| 69 |
+
tp = localtime_r(&tv.tv_sec, &tp_);
|
| 70 |
+
#else
|
| 71 |
+
tp = localtime(&tv.tv_sec);
|
| 72 |
+
#endif
|
| 73 |
+
strftime(str_time, 9, "%H:%M:%S", tp);
|
| 74 |
+
snprintf(str_time+8, 10, ".%03d", (int)tv.tv_usec/1000);
|
| 75 |
+
#else
|
| 76 |
+
time_t the_time;
|
| 77 |
+
time(&the_time);
|
| 78 |
+
strftime(str_time, 15, "%H:%M:%S", localtime (&the_time));
|
| 79 |
+
#endif
|
| 80 |
+
#endif
|
| 81 |
+
fprintf(stderr, "%s %s:%d %s(): %s\n", str_time, file, line, func, buffer);
|
| 82 |
+
}
|
| 83 |
+
#endif
|
| 84 |
+
|
| 85 |
+
void debug_info_real(const char *func, const char *file, int line, const char *format, ...)
|
| 86 |
+
{
|
| 87 |
+
#ifndef STRIP_DEBUG_CODE
|
| 88 |
+
va_list args;
|
| 89 |
+
char *buffer = NULL;
|
| 90 |
+
|
| 91 |
+
if (!debug_level)
|
| 92 |
+
return;
|
| 93 |
+
|
| 94 |
+
/* run the real fprintf */
|
| 95 |
+
va_start(args, format);
|
| 96 |
+
if(vasprintf(&buffer, format, args)<0){}
|
| 97 |
+
va_end(args);
|
| 98 |
+
|
| 99 |
+
debug_print_line(func, file, line, buffer);
|
| 100 |
+
|
| 101 |
+
free(buffer);
|
| 102 |
+
#endif
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
void debug_buffer(const char *data, const int length)
|
| 106 |
+
{
|
| 107 |
+
#ifndef STRIP_DEBUG_CODE
|
| 108 |
+
int i;
|
| 109 |
+
int j;
|
| 110 |
+
unsigned char c;
|
| 111 |
+
|
| 112 |
+
if (debug_level) {
|
| 113 |
+
for (i = 0; i < length; i += 16) {
|
| 114 |
+
fprintf(stderr, "%04x: ", i);
|
| 115 |
+
for (j = 0; j < 16; j++) {
|
| 116 |
+
if (i + j >= length) {
|
| 117 |
+
fprintf(stderr, " ");
|
| 118 |
+
continue;
|
| 119 |
+
}
|
| 120 |
+
fprintf(stderr, "%02x ", *(data + i + j) & 0xff);
|
| 121 |
+
}
|
| 122 |
+
fprintf(stderr, " | ");
|
| 123 |
+
for (j = 0; j < 16; j++) {
|
| 124 |
+
if (i + j >= length)
|
| 125 |
+
break;
|
| 126 |
+
c = *(data + i + j);
|
| 127 |
+
if ((c < 32) || (c > 127)) {
|
| 128 |
+
fprintf(stderr, ".");
|
| 129 |
+
continue;
|
| 130 |
+
}
|
| 131 |
+
fprintf(stderr, "%c", c);
|
| 132 |
+
}
|
| 133 |
+
fprintf(stderr, "\n");
|
| 134 |
+
}
|
| 135 |
+
fprintf(stderr, "\n");
|
| 136 |
+
}
|
| 137 |
+
#endif
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
void debug_buffer_to_file(const char *file, const char *data, const int length)
|
| 141 |
+
{
|
| 142 |
+
#ifndef STRIP_DEBUG_CODE
|
| 143 |
+
if (debug_level) {
|
| 144 |
+
FILE *f = fopen(file, "wb");
|
| 145 |
+
fwrite(data, 1, length, f);
|
| 146 |
+
fflush(f);
|
| 147 |
+
fclose(f);
|
| 148 |
+
}
|
| 149 |
+
#endif
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
void debug_plist_real(const char *func, const char *file, int line, plist_t plist)
|
| 153 |
+
{
|
| 154 |
+
#ifndef STRIP_DEBUG_CODE
|
| 155 |
+
if (!plist)
|
| 156 |
+
return;
|
| 157 |
+
|
| 158 |
+
char *buffer = NULL;
|
| 159 |
+
uint32_t length = 0;
|
| 160 |
+
plist_to_xml(plist, &buffer, &length);
|
| 161 |
+
|
| 162 |
+
/* get rid of ending newline as one is already added in the debug line */
|
| 163 |
+
if (buffer[length-1] == '\n')
|
| 164 |
+
buffer[length-1] = '\0';
|
| 165 |
+
|
| 166 |
+
if (length <= MAX_PRINT_LEN)
|
| 167 |
+
debug_info_real(func, file, line, "printing %i bytes plist:\n%s", length, buffer);
|
| 168 |
+
else
|
| 169 |
+
debug_info_real(func, file, line, "supress printing %i bytes plist...\n", length);
|
| 170 |
+
|
| 171 |
+
free(buffer);
|
| 172 |
+
#endif
|
| 173 |
+
}
|
| 174 |
+
|
debug.h
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* debug.h
|
| 3 |
+
* contains utilitary functions for debugging
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2008 Jonathan Beck All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2010 Martin S. All Rights Reserved.
|
| 7 |
+
*
|
| 8 |
+
* This library is free software; you can redistribute it and/or
|
| 9 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 10 |
+
* License as published by the Free Software Foundation; either
|
| 11 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 12 |
+
*
|
| 13 |
+
* This library is distributed in the hope that it will be useful,
|
| 14 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 15 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 16 |
+
* Lesser General Public License for more details.
|
| 17 |
+
*
|
| 18 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 19 |
+
* License along with this library; if not, write to the Free Software
|
| 20 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 21 |
+
*/
|
| 22 |
+
|
| 23 |
+
#ifndef __DEBUG_H
|
| 24 |
+
#define __DEBUG_H
|
| 25 |
+
|
| 26 |
+
#include <plist/plist.h>
|
| 27 |
+
|
| 28 |
+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && !defined(STRIP_DEBUG_CODE)
|
| 29 |
+
#define debug_info(...) debug_info_real (__func__, __FILE__, __LINE__, __VA_ARGS__)
|
| 30 |
+
#define debug_plist(a) debug_plist_real (__func__, __FILE__, __LINE__, a)
|
| 31 |
+
#elif defined(__GNUC__) && __GNUC__ >= 3 && !defined(STRIP_DEBUG_CODE)
|
| 32 |
+
#define debug_info(...) debug_info_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
|
| 33 |
+
#define debug_plist(a) debug_plist_real (__FUNCTION__, __FILE__, __LINE__, a)
|
| 34 |
+
#else
|
| 35 |
+
#define debug_info(...)
|
| 36 |
+
#define debug_plist(a)
|
| 37 |
+
#endif
|
| 38 |
+
|
| 39 |
+
void debug_info_real(const char *func,
|
| 40 |
+
const char *file,
|
| 41 |
+
int line,
|
| 42 |
+
const char *format, ...);
|
| 43 |
+
|
| 44 |
+
void debug_buffer(const char *data, const int length);
|
| 45 |
+
void debug_buffer_to_file(const char *file, const char *data, const int length);
|
| 46 |
+
void debug_plist_real(const char *func,
|
| 47 |
+
const char *file,
|
| 48 |
+
int line,
|
| 49 |
+
plist_t plist);
|
| 50 |
+
|
| 51 |
+
void internal_set_debug_level(int level);
|
| 52 |
+
|
| 53 |
+
#endif
|
debugserver.c
ADDED
|
@@ -0,0 +1,657 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* debugserver.c
|
| 3 |
+
* com.apple.debugserver service implementation.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2019 Nikias Bassen, All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2014-2015 Martin Szulecki All Rights Reserved.
|
| 7 |
+
*
|
| 8 |
+
* This library is free software; you can redistribute it and/or
|
| 9 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 10 |
+
* License as published by the Free Software Foundation; either
|
| 11 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 12 |
+
*
|
| 13 |
+
* This library is distributed in the hope that it will be useful,
|
| 14 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 15 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 16 |
+
* Lesser General Public License for more details.
|
| 17 |
+
*
|
| 18 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 19 |
+
* License along with this library; if not, write to the Free Software
|
| 20 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 21 |
+
*/
|
| 22 |
+
|
| 23 |
+
#ifdef HAVE_CONFIG_H
|
| 24 |
+
#include <config.h>
|
| 25 |
+
#endif
|
| 26 |
+
#include <string.h>
|
| 27 |
+
#include <stdlib.h>
|
| 28 |
+
#define _GNU_SOURCE 1
|
| 29 |
+
#define __USE_GNU 1
|
| 30 |
+
#include <stdio.h>
|
| 31 |
+
|
| 32 |
+
#include <libimobiledevice-glue/utils.h>
|
| 33 |
+
|
| 34 |
+
#include "debugserver.h"
|
| 35 |
+
#include "lockdown.h"
|
| 36 |
+
#include "common/debug.h"
|
| 37 |
+
#include "asprintf.h"
|
| 38 |
+
|
| 39 |
+
/**
|
| 40 |
+
* Convert a service_error_t value to a debugserver_error_t value.
|
| 41 |
+
* Used internally to get correct error codes.
|
| 42 |
+
*
|
| 43 |
+
* @param err An service_error_t error code
|
| 44 |
+
*
|
| 45 |
+
* @return A matching debugserver_error_t error code,
|
| 46 |
+
* DEBUGSERVER_E_UNKNOWN_ERROR otherwise.
|
| 47 |
+
*/
|
| 48 |
+
static debugserver_error_t debugserver_error(service_error_t err)
|
| 49 |
+
{
|
| 50 |
+
switch (err) {
|
| 51 |
+
case SERVICE_E_SUCCESS:
|
| 52 |
+
return DEBUGSERVER_E_SUCCESS;
|
| 53 |
+
case SERVICE_E_INVALID_ARG:
|
| 54 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 55 |
+
case SERVICE_E_MUX_ERROR:
|
| 56 |
+
return DEBUGSERVER_E_MUX_ERROR;
|
| 57 |
+
case SERVICE_E_SSL_ERROR:
|
| 58 |
+
return DEBUGSERVER_E_SSL_ERROR;
|
| 59 |
+
case SERVICE_E_TIMEOUT:
|
| 60 |
+
return DEBUGSERVER_E_TIMEOUT;
|
| 61 |
+
default:
|
| 62 |
+
break;
|
| 63 |
+
}
|
| 64 |
+
return DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t* client)
|
| 68 |
+
{
|
| 69 |
+
*client = NULL;
|
| 70 |
+
|
| 71 |
+
if (!device || !service || service->port == 0 || !client || *client) {
|
| 72 |
+
debug_info("Incorrect parameter passed to debugserver_client_new.");
|
| 73 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
debug_info("Creating debugserver_client, port = %d.", service->port);
|
| 77 |
+
|
| 78 |
+
service_client_t parent = NULL;
|
| 79 |
+
debugserver_error_t ret = debugserver_error(service_client_new(device, service, &parent));
|
| 80 |
+
if (ret != DEBUGSERVER_E_SUCCESS) {
|
| 81 |
+
debug_info("Creating base service client failed. Error: %i", ret);
|
| 82 |
+
return ret;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
if (service->identifier && (strcmp(service->identifier, DEBUGSERVER_SECURE_SERVICE_NAME) != 0)) {
|
| 86 |
+
service_disable_bypass_ssl(parent, 1);
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
debugserver_client_t client_loc = (debugserver_client_t) malloc(sizeof(struct debugserver_client_private));
|
| 90 |
+
client_loc->parent = parent;
|
| 91 |
+
client_loc->noack_mode = 0;
|
| 92 |
+
client_loc->cancel_receive = NULL;
|
| 93 |
+
client_loc->receive_loop_timeout = 1000;
|
| 94 |
+
|
| 95 |
+
*client = client_loc;
|
| 96 |
+
|
| 97 |
+
debug_info("debugserver_client successfully created.");
|
| 98 |
+
return DEBUGSERVER_E_SUCCESS;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label)
|
| 102 |
+
{
|
| 103 |
+
debugserver_error_t err = DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 104 |
+
service_client_factory_start_service(device, DEBUGSERVER_SECURE_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err);
|
| 105 |
+
if (err != DEBUGSERVER_E_SUCCESS) {
|
| 106 |
+
err = DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 107 |
+
service_client_factory_start_service(device, DEBUGSERVER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err);
|
| 108 |
+
}
|
| 109 |
+
return err;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
debugserver_error_t debugserver_client_free(debugserver_client_t client)
|
| 113 |
+
{
|
| 114 |
+
if (!client)
|
| 115 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 116 |
+
|
| 117 |
+
debugserver_error_t err = debugserver_error(service_client_free(client->parent));
|
| 118 |
+
client->parent = NULL;
|
| 119 |
+
free(client);
|
| 120 |
+
|
| 121 |
+
return err;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent)
|
| 125 |
+
{
|
| 126 |
+
debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 127 |
+
int bytes = 0;
|
| 128 |
+
|
| 129 |
+
if (!client || !data || (size == 0)) {
|
| 130 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
debug_info("sending %d bytes", size);
|
| 134 |
+
res = debugserver_error(service_send(client->parent, data, size, (uint32_t*)&bytes));
|
| 135 |
+
if (bytes <= 0) {
|
| 136 |
+
debug_info("ERROR: sending to device failed.");
|
| 137 |
+
}
|
| 138 |
+
if (sent) {
|
| 139 |
+
*sent = (uint32_t)bytes;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
return res;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
|
| 146 |
+
{
|
| 147 |
+
debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 148 |
+
int bytes = 0;
|
| 149 |
+
|
| 150 |
+
if (!client || !data || (size == 0)) {
|
| 151 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
res = debugserver_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
|
| 155 |
+
if (bytes <= 0 && res != DEBUGSERVER_E_TIMEOUT) {
|
| 156 |
+
debug_info("Could not read data, error %d", res);
|
| 157 |
+
}
|
| 158 |
+
if (received) {
|
| 159 |
+
*received = (uint32_t)bytes;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
return (bytes > 0) ? DEBUGSERVER_E_SUCCESS : res;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received)
|
| 166 |
+
{
|
| 167 |
+
debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 168 |
+
do {
|
| 169 |
+
/* Is this allowed to return DEBUGSERVER_E_TIMEOUT and also set data and received? */
|
| 170 |
+
res = debugserver_client_receive_with_timeout(client, data, size, received, client->receive_loop_timeout);
|
| 171 |
+
} while (res == DEBUGSERVER_E_TIMEOUT && client->cancel_receive != NULL && !client->cancel_receive());
|
| 172 |
+
return res;
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command)
|
| 176 |
+
{
|
| 177 |
+
int i;
|
| 178 |
+
debugserver_command_t tmp = (debugserver_command_t) malloc(sizeof(struct debugserver_command_private));
|
| 179 |
+
|
| 180 |
+
/* copy name */
|
| 181 |
+
tmp->name = strdup(name);
|
| 182 |
+
|
| 183 |
+
/* copy arguments */
|
| 184 |
+
tmp->argc = argc;
|
| 185 |
+
tmp->argv = NULL;
|
| 186 |
+
if (argc > 0) {
|
| 187 |
+
tmp->argv = malloc(sizeof(char*) * (argc + 2));
|
| 188 |
+
for (i = 0; i < argc; i++) {
|
| 189 |
+
tmp->argv[i] = strdup(argv[i]);
|
| 190 |
+
}
|
| 191 |
+
tmp->argv[i+1] = NULL;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
/* return */
|
| 195 |
+
*command = tmp;
|
| 196 |
+
|
| 197 |
+
return DEBUGSERVER_E_SUCCESS;
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
debugserver_error_t debugserver_command_free(debugserver_command_t command)
|
| 201 |
+
{
|
| 202 |
+
int i;
|
| 203 |
+
debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 204 |
+
|
| 205 |
+
if (!command)
|
| 206 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 207 |
+
|
| 208 |
+
if (command) {
|
| 209 |
+
if (command->name)
|
| 210 |
+
free(command->name);
|
| 211 |
+
if (command->argv && command->argc) {
|
| 212 |
+
for (i = 0; i < command->argc; i++) {
|
| 213 |
+
free(command->argv[i]);
|
| 214 |
+
}
|
| 215 |
+
free(command->argv);
|
| 216 |
+
}
|
| 217 |
+
free(command);
|
| 218 |
+
res = DEBUGSERVER_E_SUCCESS;
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
return res;
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
static int debugserver_hex2int(char c)
|
| 225 |
+
{
|
| 226 |
+
if (c >= '0' && c <= '9')
|
| 227 |
+
return c - '0';
|
| 228 |
+
else if (c >= 'a' && c <= 'f')
|
| 229 |
+
return 10 + c - 'a';
|
| 230 |
+
else if (c >= 'A' && c <= 'F')
|
| 231 |
+
return 10 + c - 'A';
|
| 232 |
+
else
|
| 233 |
+
return c;
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
static char debugserver_int2hex(int x)
|
| 237 |
+
{
|
| 238 |
+
const char *hexchars = "0123456789ABCDEF";
|
| 239 |
+
return hexchars[x];
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
#define DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(byte) debugserver_int2hex(((byte) >> 0x4) & 0xf)
|
| 243 |
+
#define DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(byte) debugserver_int2hex((byte) & 0xf)
|
| 244 |
+
#define DEBUGSERVER_HEX_DECODE_FIRST_BYTE(byte) (((byte) >> 0x4) & 0xf)
|
| 245 |
+
#define DEBUGSERVER_HEX_DECODE_SECOND_BYTE(byte) ((byte) & 0xf)
|
| 246 |
+
|
| 247 |
+
static uint32_t debugserver_get_checksum_for_buffer(const char* buffer, uint32_t size)
|
| 248 |
+
{
|
| 249 |
+
uint32_t checksum = 0;
|
| 250 |
+
uint32_t i;
|
| 251 |
+
|
| 252 |
+
for (i = 0; i < size; i++) {
|
| 253 |
+
checksum += buffer[i];
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
return checksum;
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
static int debugserver_response_is_checksum_valid(const char* response, uint32_t size)
|
| 260 |
+
{
|
| 261 |
+
uint32_t checksum = 0;
|
| 262 |
+
if ((size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1) > 0)
|
| 263 |
+
checksum = debugserver_get_checksum_for_buffer(&response[1], size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1);
|
| 264 |
+
|
| 265 |
+
debug_info("checksum: 0x%x", checksum);
|
| 266 |
+
|
| 267 |
+
if ((unsigned)debugserver_hex2int(response[size - 2]) != DEBUGSERVER_HEX_DECODE_FIRST_BYTE(checksum))
|
| 268 |
+
return 0;
|
| 269 |
+
|
| 270 |
+
if ((unsigned)debugserver_hex2int(response[size - 1]) != DEBUGSERVER_HEX_DECODE_SECOND_BYTE(checksum))
|
| 271 |
+
return 0;
|
| 272 |
+
|
| 273 |
+
debug_info("valid checksum");
|
| 274 |
+
|
| 275 |
+
return 1;
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length)
|
| 279 |
+
{
|
| 280 |
+
uint32_t position;
|
| 281 |
+
uint32_t index;
|
| 282 |
+
uint32_t length = strlen(buffer);
|
| 283 |
+
*encoded_length = (2 * length) + DEBUGSERVER_CHECKSUM_HASH_LENGTH + 1;
|
| 284 |
+
|
| 285 |
+
*encoded_buffer = malloc(sizeof(char) * (*encoded_length));
|
| 286 |
+
memset(*encoded_buffer, '\0', *encoded_length);
|
| 287 |
+
for (position = 0, index = 0; index < length; index++) {
|
| 288 |
+
position = (index * (2 * sizeof(char)));
|
| 289 |
+
(*encoded_buffer)[position] = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(buffer[index]);
|
| 290 |
+
(*encoded_buffer)[position + 1] = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(buffer[index]);
|
| 291 |
+
}
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer)
|
| 295 |
+
{
|
| 296 |
+
*buffer = malloc(sizeof(char) * ((encoded_length / 2)+1));
|
| 297 |
+
char* t = *buffer;
|
| 298 |
+
const char *f = encoded_buffer;
|
| 299 |
+
const char *fend = f + encoded_length;
|
| 300 |
+
while (f < fend) {
|
| 301 |
+
*t++ = debugserver_hex2int(*f) << 4 | debugserver_hex2int(f[1]);
|
| 302 |
+
f += 2;
|
| 303 |
+
}
|
| 304 |
+
*t = '\0';
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
static void debugserver_format_command(const char* prefix, const char* command, const char* arguments, int calculate_checksum, char** buffer, uint32_t* size)
|
| 308 |
+
{
|
| 309 |
+
char checksum_hash[DEBUGSERVER_CHECKSUM_HASH_LENGTH + 1] = {'#', '0', '0', '\0'};
|
| 310 |
+
char* encoded = NULL;
|
| 311 |
+
uint32_t encoded_length = 0;
|
| 312 |
+
|
| 313 |
+
if (arguments) {
|
| 314 |
+
/* arguments must be hex encoded */
|
| 315 |
+
debugserver_encode_string(arguments, &encoded, &encoded_length);
|
| 316 |
+
} else {
|
| 317 |
+
encoded = NULL;
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
char* encoded_command = string_concat(command, encoded, NULL);
|
| 321 |
+
encoded_length = strlen(encoded_command);
|
| 322 |
+
|
| 323 |
+
if (calculate_checksum) {
|
| 324 |
+
uint32_t checksum = debugserver_get_checksum_for_buffer(encoded_command, encoded_length);
|
| 325 |
+
checksum_hash[1] = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(checksum);
|
| 326 |
+
checksum_hash[2] = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(checksum);
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
*buffer = string_concat(prefix, encoded_command, checksum_hash, NULL);
|
| 330 |
+
*size = strlen(prefix) + strlen(encoded_command) + DEBUGSERVER_CHECKSUM_HASH_LENGTH;
|
| 331 |
+
|
| 332 |
+
debug_info("formatted command: %s size: %d checksum: 0x%s", *buffer, *size, checksum_hash);
|
| 333 |
+
|
| 334 |
+
if (encoded_command)
|
| 335 |
+
free(encoded_command);
|
| 336 |
+
|
| 337 |
+
if (encoded)
|
| 338 |
+
free(encoded);
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
static debugserver_error_t debugserver_client_send_ack(debugserver_client_t client)
|
| 342 |
+
{
|
| 343 |
+
debug_info("sending ACK");
|
| 344 |
+
return debugserver_client_send(client, "+", sizeof(char), NULL);
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
static debugserver_error_t debugserver_client_send_noack(debugserver_client_t client)
|
| 348 |
+
{
|
| 349 |
+
debug_info("sending !ACK");
|
| 350 |
+
return debugserver_client_send(client, "-", sizeof(char), NULL);
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled)
|
| 354 |
+
{
|
| 355 |
+
if (!client)
|
| 356 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 357 |
+
|
| 358 |
+
client->noack_mode = (enabled == 0)? 1: 0;
|
| 359 |
+
|
| 360 |
+
debug_info("ack mode: %s", client->noack_mode == 0 ? "on": "off");
|
| 361 |
+
|
| 362 |
+
return DEBUGSERVER_E_SUCCESS;
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
debugserver_error_t debugserver_client_set_receive_params(debugserver_client_t client, int (*cancel_receive)(), int receive_loop_timeout)
|
| 366 |
+
{
|
| 367 |
+
if (!client)
|
| 368 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 369 |
+
|
| 370 |
+
client->cancel_receive = cancel_receive;
|
| 371 |
+
client->receive_loop_timeout = receive_loop_timeout;
|
| 372 |
+
|
| 373 |
+
debug_info("receive params: cancel_receive %s, receive_loop_timeout %dms", (client->cancel_receive == NULL ? "unset": "set"), client->receive_loop_timeout);
|
| 374 |
+
|
| 375 |
+
return DEBUGSERVER_E_SUCCESS;
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
static debugserver_error_t debugserver_client_receive_internal_char(debugserver_client_t client, char* received_char)
|
| 379 |
+
{
|
| 380 |
+
debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
|
| 381 |
+
uint32_t bytes = 0;
|
| 382 |
+
|
| 383 |
+
/* we loop here as we expect an answer */
|
| 384 |
+
res = debugserver_client_receive(client, received_char, sizeof(char), &bytes);
|
| 385 |
+
if (res != DEBUGSERVER_E_SUCCESS) {
|
| 386 |
+
return res;
|
| 387 |
+
}
|
| 388 |
+
if (bytes != 1) {
|
| 389 |
+
debug_info("received %d bytes when asking for %d!", bytes, sizeof(char));
|
| 390 |
+
return DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 391 |
+
}
|
| 392 |
+
return res;
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size)
|
| 396 |
+
{
|
| 397 |
+
debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
|
| 398 |
+
|
| 399 |
+
char data = '\0';
|
| 400 |
+
int skip_prefix = 0;
|
| 401 |
+
|
| 402 |
+
char* buffer = malloc(1024);
|
| 403 |
+
uint32_t buffer_size = 0;
|
| 404 |
+
uint32_t buffer_capacity = 1024;
|
| 405 |
+
|
| 406 |
+
if (response)
|
| 407 |
+
*response = NULL;
|
| 408 |
+
|
| 409 |
+
if (!client->noack_mode) {
|
| 410 |
+
debug_info("attempting to receive ACK (+)");
|
| 411 |
+
res = debugserver_client_receive_internal_char(client, &data);
|
| 412 |
+
if (res != DEBUGSERVER_E_SUCCESS) {
|
| 413 |
+
goto cleanup;
|
| 414 |
+
}
|
| 415 |
+
if (data == '+') {
|
| 416 |
+
debug_info("received ACK (+)");
|
| 417 |
+
} else if (data == '$') {
|
| 418 |
+
debug_info("received prefix ($)");
|
| 419 |
+
buffer[0] = '$';
|
| 420 |
+
buffer_size = 1;
|
| 421 |
+
skip_prefix = 1;
|
| 422 |
+
} else {
|
| 423 |
+
debug_info("unrecognized response when looking for ACK: %c", data);
|
| 424 |
+
goto cleanup;
|
| 425 |
+
}
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
debug_info("skip_prefix: %d", skip_prefix);
|
| 429 |
+
|
| 430 |
+
if (!skip_prefix) {
|
| 431 |
+
debug_info("attempting to receive prefix ($)");
|
| 432 |
+
res = debugserver_client_receive_internal_char(client, &data);
|
| 433 |
+
if (res != DEBUGSERVER_E_SUCCESS) {
|
| 434 |
+
goto cleanup;
|
| 435 |
+
}
|
| 436 |
+
if (data == '$') {
|
| 437 |
+
debug_info("received prefix ($)");
|
| 438 |
+
buffer[0] = '$';
|
| 439 |
+
buffer_size = 1;
|
| 440 |
+
} else {
|
| 441 |
+
debug_info("unrecognized response when looking for prefix: %c", data);
|
| 442 |
+
goto cleanup;
|
| 443 |
+
}
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH;
|
| 447 |
+
int receiving_checksum_response = 0;
|
| 448 |
+
debug_info("attempting to read up response until checksum");
|
| 449 |
+
|
| 450 |
+
while ((checksum_length > 0)) {
|
| 451 |
+
res = debugserver_client_receive_internal_char(client, &data);
|
| 452 |
+
if (res != DEBUGSERVER_E_SUCCESS) {
|
| 453 |
+
goto cleanup;
|
| 454 |
+
}
|
| 455 |
+
if (data == '#') {
|
| 456 |
+
receiving_checksum_response = 1;
|
| 457 |
+
}
|
| 458 |
+
if (receiving_checksum_response) {
|
| 459 |
+
checksum_length--;
|
| 460 |
+
}
|
| 461 |
+
if (buffer_size + 1 >= buffer_capacity) {
|
| 462 |
+
char* newbuffer = realloc(buffer, buffer_capacity+1024);
|
| 463 |
+
if (!newbuffer) {
|
| 464 |
+
return DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 465 |
+
}
|
| 466 |
+
buffer = newbuffer;
|
| 467 |
+
buffer_capacity += 1024;
|
| 468 |
+
}
|
| 469 |
+
buffer[buffer_size] = data;
|
| 470 |
+
buffer_size += sizeof(char);
|
| 471 |
+
}
|
| 472 |
+
debug_info("validating response checksum...");
|
| 473 |
+
if (client->noack_mode || debugserver_response_is_checksum_valid(buffer, buffer_size)) {
|
| 474 |
+
if (response) {
|
| 475 |
+
/* assemble response string */
|
| 476 |
+
uint32_t resp_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1);
|
| 477 |
+
*response = (char*)malloc(resp_size + 1);
|
| 478 |
+
memcpy(*response, buffer + 1, resp_size);
|
| 479 |
+
(*response)[resp_size] = '\0';
|
| 480 |
+
if (response_size) *response_size = resp_size;
|
| 481 |
+
}
|
| 482 |
+
if (!client->noack_mode) {
|
| 483 |
+
/* confirm valid command */
|
| 484 |
+
debugserver_client_send_ack(client);
|
| 485 |
+
}
|
| 486 |
+
} else {
|
| 487 |
+
/* response was invalid */
|
| 488 |
+
res = DEBUGSERVER_E_RESPONSE_ERROR;
|
| 489 |
+
if (!client->noack_mode) {
|
| 490 |
+
/* report invalid command */
|
| 491 |
+
debugserver_client_send_noack(client);
|
| 492 |
+
}
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
cleanup:
|
| 496 |
+
if (response) {
|
| 497 |
+
debug_info("response: %s", *response);
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
if (buffer)
|
| 501 |
+
free(buffer);
|
| 502 |
+
|
| 503 |
+
return res;
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size)
|
| 507 |
+
{
|
| 508 |
+
debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
|
| 509 |
+
int i;
|
| 510 |
+
uint32_t bytes = 0;
|
| 511 |
+
|
| 512 |
+
char* send_buffer = NULL;
|
| 513 |
+
uint32_t send_buffer_size = 0;
|
| 514 |
+
|
| 515 |
+
char* command_arguments = NULL;
|
| 516 |
+
|
| 517 |
+
/* concat all arguments */
|
| 518 |
+
for (i = 0; i < command->argc; i++) {
|
| 519 |
+
debug_info("argv[%d]: %s", i, command->argv[i]);
|
| 520 |
+
command_arguments = string_append(command_arguments, command->argv[i], NULL);
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
debug_info("command_arguments(%d): %s", command->argc, command_arguments);
|
| 524 |
+
|
| 525 |
+
/* encode command arguments, add checksum if required and assemble entire command */
|
| 526 |
+
debugserver_format_command("$", command->name, command_arguments, 1, &send_buffer, &send_buffer_size);
|
| 527 |
+
|
| 528 |
+
debug_info("sending encoded command: %s", send_buffer);
|
| 529 |
+
|
| 530 |
+
res = debugserver_client_send(client, send_buffer, send_buffer_size, &bytes);
|
| 531 |
+
debug_info("command result: %d", res);
|
| 532 |
+
if (res != DEBUGSERVER_E_SUCCESS) {
|
| 533 |
+
goto cleanup;
|
| 534 |
+
}
|
| 535 |
+
|
| 536 |
+
/* receive response */
|
| 537 |
+
res = debugserver_client_receive_response(client, response, response_size);
|
| 538 |
+
debug_info("response result: %d", res);
|
| 539 |
+
if (res != DEBUGSERVER_E_SUCCESS) {
|
| 540 |
+
goto cleanup;
|
| 541 |
+
}
|
| 542 |
+
|
| 543 |
+
if (response) {
|
| 544 |
+
debug_info("received response: %s", *response);
|
| 545 |
+
}
|
| 546 |
+
|
| 547 |
+
/* disable sending ack on the client */
|
| 548 |
+
if (!strncmp(command->name, "QStartNoAckMode", 16)) {
|
| 549 |
+
debugserver_client_set_ack_mode(client, 0);
|
| 550 |
+
}
|
| 551 |
+
|
| 552 |
+
cleanup:
|
| 553 |
+
if (command_arguments)
|
| 554 |
+
free(command_arguments);
|
| 555 |
+
|
| 556 |
+
if (send_buffer)
|
| 557 |
+
free(send_buffer);
|
| 558 |
+
|
| 559 |
+
return res;
|
| 560 |
+
}
|
| 561 |
+
|
| 562 |
+
debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response)
|
| 563 |
+
{
|
| 564 |
+
if (!client || !env)
|
| 565 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 566 |
+
|
| 567 |
+
debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 568 |
+
char* env_tmp = strdup(env);
|
| 569 |
+
char* env_arg[2] = { env_tmp, NULL };
|
| 570 |
+
|
| 571 |
+
debugserver_command_t command = NULL;
|
| 572 |
+
debugserver_command_new("QEnvironmentHexEncoded:", 1, env_arg, &command);
|
| 573 |
+
result = debugserver_client_send_command(client, command, response, NULL);
|
| 574 |
+
debugserver_command_free(command);
|
| 575 |
+
|
| 576 |
+
free(env_tmp);
|
| 577 |
+
|
| 578 |
+
return result;
|
| 579 |
+
}
|
| 580 |
+
|
| 581 |
+
debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response)
|
| 582 |
+
{
|
| 583 |
+
if (!client || !argc)
|
| 584 |
+
return DEBUGSERVER_E_INVALID_ARG;
|
| 585 |
+
|
| 586 |
+
debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 587 |
+
char *pkt = NULL;
|
| 588 |
+
size_t pkt_len = 0;
|
| 589 |
+
int i = 0;
|
| 590 |
+
|
| 591 |
+
/* calculate total length */
|
| 592 |
+
while (i < argc && argv && argv[i]) {
|
| 593 |
+
char *prefix = NULL;
|
| 594 |
+
int ret = asprintf(&prefix, ",%zu,%d,", strlen(argv[i]) * 2, i);
|
| 595 |
+
if (ret < 0 || prefix == NULL) {
|
| 596 |
+
debug_info("asprintf failed, out of memory?");
|
| 597 |
+
return DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 598 |
+
}
|
| 599 |
+
pkt_len += strlen(prefix) + strlen(argv[i]) * 2;
|
| 600 |
+
free(prefix);
|
| 601 |
+
i++;
|
| 602 |
+
}
|
| 603 |
+
|
| 604 |
+
/* allocate packet and initialize it */
|
| 605 |
+
pkt = (char *) malloc(pkt_len + 1);
|
| 606 |
+
memset(pkt, 0, pkt_len + 1);
|
| 607 |
+
|
| 608 |
+
char *pktp = pkt;
|
| 609 |
+
|
| 610 |
+
i = 0;
|
| 611 |
+
while (i < argc && argv && argv[i]) {
|
| 612 |
+
debug_info("argv[%d] = \"%s\"", i, argv[i]);
|
| 613 |
+
|
| 614 |
+
char *prefix = NULL;
|
| 615 |
+
char *m = NULL;
|
| 616 |
+
size_t arg_len = strlen(argv[i]);
|
| 617 |
+
size_t arg_hexlen = arg_len * 2;
|
| 618 |
+
|
| 619 |
+
int ret = asprintf(&prefix, ",%zu,%d,", arg_hexlen, i);
|
| 620 |
+
if (ret < 0 || prefix == NULL) {
|
| 621 |
+
debug_info("asprintf failed, out of memory?");
|
| 622 |
+
return DEBUGSERVER_E_UNKNOWN_ERROR;
|
| 623 |
+
}
|
| 624 |
+
|
| 625 |
+
m = (char *) malloc(arg_hexlen);
|
| 626 |
+
char *p = m;
|
| 627 |
+
char *q = (char*)argv[i];
|
| 628 |
+
while (*q) {
|
| 629 |
+
*p++ = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(*q);
|
| 630 |
+
*p++ = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(*q);
|
| 631 |
+
q++;
|
| 632 |
+
}
|
| 633 |
+
|
| 634 |
+
memcpy(pktp, prefix, strlen(prefix));
|
| 635 |
+
pktp += strlen(prefix);
|
| 636 |
+
|
| 637 |
+
memcpy(pktp, m, arg_hexlen);
|
| 638 |
+
pktp += arg_hexlen;
|
| 639 |
+
|
| 640 |
+
free(prefix);
|
| 641 |
+
free(m);
|
| 642 |
+
|
| 643 |
+
i++;
|
| 644 |
+
}
|
| 645 |
+
|
| 646 |
+
pkt[0] = 'A';
|
| 647 |
+
|
| 648 |
+
debugserver_command_t command = NULL;
|
| 649 |
+
debugserver_command_new(pkt, 0, NULL, &command);
|
| 650 |
+
result = debugserver_client_send_command(client, command, response, NULL);
|
| 651 |
+
debugserver_command_free(command);
|
| 652 |
+
|
| 653 |
+
if (pkt)
|
| 654 |
+
free(pkt);
|
| 655 |
+
|
| 656 |
+
return result;
|
| 657 |
+
}
|
debugserver.h
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* debugserver.h
|
| 3 |
+
* com.apple.debugserver service header file.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2014 Martin Szulecki All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifndef _DEBUGSERVER_H
|
| 23 |
+
#define _DEBUGSERVER_H
|
| 24 |
+
|
| 25 |
+
#include "idevice.h"
|
| 26 |
+
#include "libimobiledevice/debugserver.h"
|
| 27 |
+
#include "service.h"
|
| 28 |
+
|
| 29 |
+
#define DEBUGSERVER_CHECKSUM_HASH_LENGTH 0x3
|
| 30 |
+
|
| 31 |
+
struct debugserver_client_private {
|
| 32 |
+
service_client_t parent;
|
| 33 |
+
int noack_mode;
|
| 34 |
+
int (*cancel_receive)();
|
| 35 |
+
int receive_loop_timeout;
|
| 36 |
+
};
|
| 37 |
+
|
| 38 |
+
struct debugserver_command_private {
|
| 39 |
+
char* name;
|
| 40 |
+
int argc;
|
| 41 |
+
char** argv;
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
+
#endif
|
debugserver.pxi
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cdef extern from "libimobiledevice/debugserver.h":
|
| 2 |
+
cdef struct debugserver_client_private:
|
| 3 |
+
pass
|
| 4 |
+
ctypedef debugserver_client_private *debugserver_client_t
|
| 5 |
+
cdef struct debugserver_command_private:
|
| 6 |
+
pass
|
| 7 |
+
ctypedef debugserver_command_private *debugserver_command_t
|
| 8 |
+
ctypedef enum debugserver_error_t:
|
| 9 |
+
DEBUGSERVER_E_SUCCESS = 0
|
| 10 |
+
DEBUGSERVER_E_INVALID_ARG = -1
|
| 11 |
+
DEBUGSERVER_E_MUX_ERROR = -2
|
| 12 |
+
DEBUGSERVER_E_SSL_ERROR = -3
|
| 13 |
+
DEBUGSERVER_E_RESPONSE_ERROR = -4
|
| 14 |
+
DEBUGSERVER_E_UNKNOWN_ERROR = -256
|
| 15 |
+
|
| 16 |
+
debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t * client)
|
| 17 |
+
debugserver_error_t debugserver_client_free(debugserver_client_t client)
|
| 18 |
+
|
| 19 |
+
debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent)
|
| 20 |
+
debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size)
|
| 21 |
+
debugserver_error_t debugserver_client_receive(debugserver_client_t client, char *data, uint32_t size, uint32_t *received)
|
| 22 |
+
debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout)
|
| 23 |
+
debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size)
|
| 24 |
+
debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response)
|
| 25 |
+
debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response)
|
| 26 |
+
|
| 27 |
+
debugserver_error_t debugserver_command_new(const char* name, int argc, const char* argv[], debugserver_command_t* command)
|
| 28 |
+
debugserver_error_t debugserver_command_free(debugserver_command_t command)
|
| 29 |
+
void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length)
|
| 30 |
+
void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
cdef class DebugServerError(BaseError):
|
| 34 |
+
def __init__(self, *args, **kwargs):
|
| 35 |
+
self._lookup_table = {
|
| 36 |
+
DEBUGSERVER_E_SUCCESS: "Success",
|
| 37 |
+
DEBUGSERVER_E_INVALID_ARG: "Invalid argument",
|
| 38 |
+
DEBUGSERVER_E_MUX_ERROR: "MUX error",
|
| 39 |
+
DEBUGSERVER_E_SSL_ERROR: "SSL error",
|
| 40 |
+
DEBUGSERVER_E_RESPONSE_ERROR: "Response error",
|
| 41 |
+
DEBUGSERVER_E_UNKNOWN_ERROR: "Unknown error",
|
| 42 |
+
}
|
| 43 |
+
BaseError.__init__(self, *args, **kwargs)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
from cpython.bytes cimport PyBytes_AsString as PyString_AsString
|
| 47 |
+
cdef char ** to_cstring_array(list_str):
|
| 48 |
+
if not list_str:
|
| 49 |
+
return NULL
|
| 50 |
+
cdef char **ret = <char **>malloc(len(list_str) * sizeof(char *))
|
| 51 |
+
for i in xrange(len(list_str)):
|
| 52 |
+
ret[i] = PyString_AsString(list_str[i])
|
| 53 |
+
return ret
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
cdef class DebugServerCommand(Base):
|
| 57 |
+
cdef debugserver_command_t _c_command
|
| 58 |
+
|
| 59 |
+
def __init__(self, bytes name, int argc = 0, argv = None, *args, **kwargs):
|
| 60 |
+
cdef:
|
| 61 |
+
char* c_name = name
|
| 62 |
+
char** c_argv = to_cstring_array(argv)
|
| 63 |
+
|
| 64 |
+
try:
|
| 65 |
+
self.handle_error(debugserver_command_new(c_name, argc, c_argv, &self._c_command))
|
| 66 |
+
except BaseError, e:
|
| 67 |
+
raise
|
| 68 |
+
finally:
|
| 69 |
+
free(c_argv)
|
| 70 |
+
|
| 71 |
+
def __enter__(self):
|
| 72 |
+
return self
|
| 73 |
+
|
| 74 |
+
def __exit__(self, type, value, traceback):
|
| 75 |
+
self.free()
|
| 76 |
+
|
| 77 |
+
cdef free(self):
|
| 78 |
+
cdef debugserver_error_t err
|
| 79 |
+
if self._c_command is not NULL:
|
| 80 |
+
err = debugserver_command_free(self._c_command)
|
| 81 |
+
self.handle_error(err)
|
| 82 |
+
|
| 83 |
+
cdef inline BaseError _error(self, int16_t ret):
|
| 84 |
+
return DebugServerError(ret)
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
cdef class DebugServerClient(BaseService):
|
| 88 |
+
__service_name__ = "com.apple.debugserver"
|
| 89 |
+
cdef debugserver_client_t _c_client
|
| 90 |
+
|
| 91 |
+
def __cinit__(self, iDevice device = None, LockdownServiceDescriptor descriptor = None, *args, **kwargs):
|
| 92 |
+
if (device is not None and descriptor is not None):
|
| 93 |
+
self.handle_error(debugserver_client_new(device._c_dev, descriptor._c_service_descriptor, &(self._c_client)))
|
| 94 |
+
|
| 95 |
+
def __dealloc__(self):
|
| 96 |
+
cdef debugserver_error_t err
|
| 97 |
+
if self._c_client is not NULL:
|
| 98 |
+
err = debugserver_client_free(self._c_client)
|
| 99 |
+
self.handle_error(err)
|
| 100 |
+
|
| 101 |
+
cdef BaseError _error(self, int16_t ret):
|
| 102 |
+
return DebugServerError(ret)
|
| 103 |
+
|
| 104 |
+
cpdef uint32_t send(self, bytes data):
|
| 105 |
+
cdef:
|
| 106 |
+
uint32_t bytes_send
|
| 107 |
+
char* c_data = data
|
| 108 |
+
try:
|
| 109 |
+
self.handle_error(debugserver_client_send(self._c_client, c_data, len(data), &bytes_send))
|
| 110 |
+
except BaseError, e:
|
| 111 |
+
raise
|
| 112 |
+
|
| 113 |
+
return bytes_send
|
| 114 |
+
|
| 115 |
+
cpdef bytes send_command(self, DebugServerCommand command):
|
| 116 |
+
cdef:
|
| 117 |
+
char* c_response = NULL
|
| 118 |
+
bytes result
|
| 119 |
+
|
| 120 |
+
try:
|
| 121 |
+
self.handle_error(debugserver_client_send_command(self._c_client, command._c_command, &c_response, NULL))
|
| 122 |
+
if c_response:
|
| 123 |
+
result = c_response
|
| 124 |
+
return result
|
| 125 |
+
else:
|
| 126 |
+
return None
|
| 127 |
+
except BaseError, e:
|
| 128 |
+
raise
|
| 129 |
+
finally:
|
| 130 |
+
free(c_response)
|
| 131 |
+
|
| 132 |
+
cpdef bytes receive(self, uint32_t size):
|
| 133 |
+
cdef:
|
| 134 |
+
uint32_t bytes_received
|
| 135 |
+
char* c_data = <char *>malloc(size)
|
| 136 |
+
bytes result
|
| 137 |
+
|
| 138 |
+
try:
|
| 139 |
+
self.handle_error(debugserver_client_receive(self._c_client, c_data, size, &bytes_received))
|
| 140 |
+
result = c_data[:bytes_received]
|
| 141 |
+
return result
|
| 142 |
+
except BaseError, e:
|
| 143 |
+
raise
|
| 144 |
+
finally:
|
| 145 |
+
free(c_data)
|
| 146 |
+
|
| 147 |
+
cpdef bytes receive_with_timeout(self, uint32_t size, unsigned int timeout):
|
| 148 |
+
cdef:
|
| 149 |
+
uint32_t bytes_received
|
| 150 |
+
char* c_data = <char *>malloc(size)
|
| 151 |
+
bytes result
|
| 152 |
+
|
| 153 |
+
try:
|
| 154 |
+
self.handle_error(debugserver_client_receive_with_timeout(self._c_client, c_data, size, &bytes_received, timeout))
|
| 155 |
+
result = c_data[:bytes_received]
|
| 156 |
+
return result
|
| 157 |
+
except BaseError, e:
|
| 158 |
+
raise
|
| 159 |
+
finally:
|
| 160 |
+
free(c_data)
|
| 161 |
+
|
| 162 |
+
cpdef bytes receive_response(self):
|
| 163 |
+
cdef:
|
| 164 |
+
char* c_response = NULL
|
| 165 |
+
bytes result
|
| 166 |
+
|
| 167 |
+
try:
|
| 168 |
+
self.handle_error(debugserver_client_receive_response(self._c_client, &c_response, NULL))
|
| 169 |
+
if c_response:
|
| 170 |
+
result = c_response
|
| 171 |
+
return result
|
| 172 |
+
else:
|
| 173 |
+
return None
|
| 174 |
+
except BaseError, e:
|
| 175 |
+
raise
|
| 176 |
+
finally:
|
| 177 |
+
free(c_response)
|
| 178 |
+
|
| 179 |
+
cpdef bytes set_argv(self, int argc, argv):
|
| 180 |
+
cdef:
|
| 181 |
+
char** c_argv = to_cstring_array(argv)
|
| 182 |
+
char* c_response = NULL
|
| 183 |
+
bytes result
|
| 184 |
+
|
| 185 |
+
try:
|
| 186 |
+
self.handle_error(debugserver_client_set_argv(self._c_client, argc, c_argv, &c_response))
|
| 187 |
+
if c_response:
|
| 188 |
+
result = c_response
|
| 189 |
+
return result
|
| 190 |
+
else:
|
| 191 |
+
return None
|
| 192 |
+
except BaseError, e:
|
| 193 |
+
raise
|
| 194 |
+
finally:
|
| 195 |
+
free(c_argv)
|
| 196 |
+
free(c_response)
|
| 197 |
+
|
| 198 |
+
cpdef bytes set_environment_hex_encoded(self, bytes env):
|
| 199 |
+
cdef:
|
| 200 |
+
char* c_env = env
|
| 201 |
+
char* c_response = NULL
|
| 202 |
+
bytes result
|
| 203 |
+
|
| 204 |
+
try:
|
| 205 |
+
self.handle_error(debugserver_client_set_environment_hex_encoded(self._c_client, c_env, &c_response))
|
| 206 |
+
if c_response:
|
| 207 |
+
result = c_response
|
| 208 |
+
return result
|
| 209 |
+
else:
|
| 210 |
+
return None
|
| 211 |
+
except BaseError, e:
|
| 212 |
+
raise
|
| 213 |
+
finally:
|
| 214 |
+
free(c_response)
|
| 215 |
+
|
| 216 |
+
cpdef bytes encode_string(self, bytes buffer):
|
| 217 |
+
cdef:
|
| 218 |
+
char *c_buffer = buffer
|
| 219 |
+
uint32_t encoded_length = len(c_buffer) * 2 + 0x3 + 1
|
| 220 |
+
char* c_encoded_buffer = <char *>malloc(encoded_length)
|
| 221 |
+
bytes result
|
| 222 |
+
|
| 223 |
+
try:
|
| 224 |
+
debugserver_encode_string(c_buffer, &c_encoded_buffer, &encoded_length)
|
| 225 |
+
result = c_encoded_buffer[:encoded_length]
|
| 226 |
+
return result
|
| 227 |
+
except BaseError, e:
|
| 228 |
+
raise
|
| 229 |
+
finally:
|
| 230 |
+
free(c_encoded_buffer)
|
| 231 |
+
|
| 232 |
+
cpdef bytes decode_string(self, bytes encoded_buffer):
|
| 233 |
+
cdef:
|
| 234 |
+
char* c_encoded_buffer = encoded_buffer
|
| 235 |
+
uint32_t encoded_length = len(c_encoded_buffer)
|
| 236 |
+
char *c_buffer = <char *>malloc(encoded_length)
|
| 237 |
+
bytes result
|
| 238 |
+
|
| 239 |
+
try:
|
| 240 |
+
debugserver_decode_string(c_encoded_buffer, encoded_length, &c_buffer)
|
| 241 |
+
result = c_buffer
|
| 242 |
+
return result
|
| 243 |
+
except BaseError, e:
|
| 244 |
+
raise
|
| 245 |
+
finally:
|
| 246 |
+
free(c_buffer)
|
device_link_service.c
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* device_link_service.c
|
| 3 |
+
* DeviceLink service implementation.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifdef HAVE_CONFIG_H
|
| 23 |
+
#include <config.h>
|
| 24 |
+
#endif
|
| 25 |
+
#include <string.h>
|
| 26 |
+
#include <stdlib.h>
|
| 27 |
+
#include "device_link_service.h"
|
| 28 |
+
#include "property_list_service.h"
|
| 29 |
+
#include "common/debug.h"
|
| 30 |
+
|
| 31 |
+
static device_link_service_error_t device_link_error(property_list_service_error_t err)
|
| 32 |
+
{
|
| 33 |
+
switch (err) {
|
| 34 |
+
case PROPERTY_LIST_SERVICE_E_SUCCESS:
|
| 35 |
+
return DEVICE_LINK_SERVICE_E_SUCCESS;
|
| 36 |
+
case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
|
| 37 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 38 |
+
case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
|
| 39 |
+
return DEVICE_LINK_SERVICE_E_PLIST_ERROR;
|
| 40 |
+
case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
|
| 41 |
+
return DEVICE_LINK_SERVICE_E_MUX_ERROR;
|
| 42 |
+
case PROPERTY_LIST_SERVICE_E_SSL_ERROR:
|
| 43 |
+
return DEVICE_LINK_SERVICE_E_SSL_ERROR;
|
| 44 |
+
case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT:
|
| 45 |
+
return DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT;
|
| 46 |
+
default:
|
| 47 |
+
break;
|
| 48 |
+
}
|
| 49 |
+
return DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
/**
|
| 53 |
+
* Internally used function to extract the message string from a DL* message
|
| 54 |
+
* plist.
|
| 55 |
+
*
|
| 56 |
+
* @param dl_msg The DeviceLink property list to parse.
|
| 57 |
+
* @param message A pointer that will be set to a newly allocated char*
|
| 58 |
+
* containing the DLMessage* string from the given plist. It is up to
|
| 59 |
+
* the caller to free the allocated memory. If this parameter is NULL
|
| 60 |
+
* it will be ignored.
|
| 61 |
+
*
|
| 62 |
+
* @return 1 if the given plist is a DL* message, or 0 if the plist does not
|
| 63 |
+
* contain any DL* message.
|
| 64 |
+
*/
|
| 65 |
+
static int device_link_service_get_message(plist_t dl_msg, char **message)
|
| 66 |
+
{
|
| 67 |
+
plist_t cmd = NULL;
|
| 68 |
+
char *cmd_str = NULL;
|
| 69 |
+
|
| 70 |
+
/* sanity check */
|
| 71 |
+
if ((plist_get_node_type(dl_msg) != PLIST_ARRAY) || (plist_array_get_size(dl_msg) < 1)) {
|
| 72 |
+
return 0;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
/* get dl command */
|
| 76 |
+
cmd = plist_array_get_item(dl_msg, 0);
|
| 77 |
+
if (!cmd || (plist_get_node_type(cmd) != PLIST_STRING)) {
|
| 78 |
+
return 0;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
plist_get_string_val(cmd, &cmd_str);
|
| 82 |
+
if (!cmd_str) {
|
| 83 |
+
return 0;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
if ((strlen(cmd_str) < 9) || (strncmp(cmd_str, "DL", 2) != 0)) {
|
| 87 |
+
free(cmd_str);
|
| 88 |
+
return 0;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
if (message)
|
| 92 |
+
*message = cmd_str;
|
| 93 |
+
|
| 94 |
+
/* we got a DL* message */
|
| 95 |
+
return 1;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
/**
|
| 99 |
+
* Creates a new device link service client.
|
| 100 |
+
*
|
| 101 |
+
* @param device The device to connect to.
|
| 102 |
+
* @param service The service descriptor returned by lockdownd_start_service.
|
| 103 |
+
* @param client Reference that will point to a newly allocated
|
| 104 |
+
* device_link_service_client_t upon successful return.
|
| 105 |
+
*
|
| 106 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
|
| 107 |
+
* DEVICE_LINK_SERVICE_E_INVALID_ARG when one of the parameters is invalid,
|
| 108 |
+
* or DEVICE_LINK_SERVICE_E_MUX_ERROR when the connection failed.
|
| 109 |
+
*/
|
| 110 |
+
device_link_service_error_t device_link_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, device_link_service_client_t *client)
|
| 111 |
+
{
|
| 112 |
+
if (!device || !service || service->port == 0 || !client || *client) {
|
| 113 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
property_list_service_client_t plistclient = NULL;
|
| 117 |
+
device_link_service_error_t err = device_link_error(property_list_service_client_new(device, service, &plistclient));
|
| 118 |
+
if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
|
| 119 |
+
return err;
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
/* create client object */
|
| 123 |
+
device_link_service_client_t client_loc = (device_link_service_client_t) malloc(sizeof(struct device_link_service_client_private));
|
| 124 |
+
client_loc->parent = plistclient;
|
| 125 |
+
|
| 126 |
+
/* all done, return success */
|
| 127 |
+
*client = client_loc;
|
| 128 |
+
return DEVICE_LINK_SERVICE_E_SUCCESS;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
/**
|
| 132 |
+
* Frees a device link service client.
|
| 133 |
+
*
|
| 134 |
+
* @param client The device_link_service_client_t to free.
|
| 135 |
+
*
|
| 136 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
|
| 137 |
+
* DEVICE_LINK_SERVICE_E_INVALID_ARG when one of client or client->parent
|
| 138 |
+
* is invalid, or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR when the was an error
|
| 139 |
+
* freeing the parent property_list_service client.
|
| 140 |
+
*/
|
| 141 |
+
device_link_service_error_t device_link_service_client_free(device_link_service_client_t client)
|
| 142 |
+
{
|
| 143 |
+
if (!client)
|
| 144 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 145 |
+
|
| 146 |
+
device_link_service_error_t err = device_link_error(property_list_service_client_free(client->parent));
|
| 147 |
+
free(client);
|
| 148 |
+
|
| 149 |
+
return err;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
/**
|
| 153 |
+
* Performs the DLMessageVersionExchange with the connected device.
|
| 154 |
+
* This should be the first operation to be executed by an implemented
|
| 155 |
+
* device link service client.
|
| 156 |
+
*
|
| 157 |
+
* @param client The device_link_service client to use.
|
| 158 |
+
* @param version_major The major version number to check.
|
| 159 |
+
* @param version_minor The minor version number to check.
|
| 160 |
+
*
|
| 161 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
|
| 162 |
+
* DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL,
|
| 163 |
+
* DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs,
|
| 164 |
+
* DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the
|
| 165 |
+
* expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version
|
| 166 |
+
* given by the device is larger than the given version,
|
| 167 |
+
* or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise.
|
| 168 |
+
*/
|
| 169 |
+
device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor)
|
| 170 |
+
{
|
| 171 |
+
if (!client)
|
| 172 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 173 |
+
|
| 174 |
+
device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
|
| 175 |
+
|
| 176 |
+
/* perform version exchange */
|
| 177 |
+
plist_t array = NULL;
|
| 178 |
+
char *msg = NULL;
|
| 179 |
+
|
| 180 |
+
/* receive DLMessageVersionExchange from device */
|
| 181 |
+
err = device_link_error(property_list_service_receive_plist(client->parent, &array));
|
| 182 |
+
if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
|
| 183 |
+
debug_info("Did not receive initial message from device!");
|
| 184 |
+
goto leave;
|
| 185 |
+
}
|
| 186 |
+
device_link_service_get_message(array, &msg);
|
| 187 |
+
if (!msg || strcmp(msg, "DLMessageVersionExchange") != 0) {
|
| 188 |
+
debug_info("Did not receive DLMessageVersionExchange from device!");
|
| 189 |
+
err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
|
| 190 |
+
goto leave;
|
| 191 |
+
}
|
| 192 |
+
free(msg);
|
| 193 |
+
msg = NULL;
|
| 194 |
+
|
| 195 |
+
/* get major and minor version number */
|
| 196 |
+
if (plist_array_get_size(array) < 3) {
|
| 197 |
+
debug_info("DLMessageVersionExchange has unexpected format!");
|
| 198 |
+
err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
|
| 199 |
+
goto leave;
|
| 200 |
+
}
|
| 201 |
+
plist_t maj = plist_array_get_item(array, 1);
|
| 202 |
+
plist_t min = plist_array_get_item(array, 2);
|
| 203 |
+
uint64_t vmajor = 0;
|
| 204 |
+
uint64_t vminor = 0;
|
| 205 |
+
if (maj) {
|
| 206 |
+
plist_get_uint_val(maj, &vmajor);
|
| 207 |
+
}
|
| 208 |
+
if (min) {
|
| 209 |
+
plist_get_uint_val(min, &vminor);
|
| 210 |
+
}
|
| 211 |
+
if (vmajor > version_major) {
|
| 212 |
+
debug_info("Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
|
| 213 |
+
err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
|
| 214 |
+
goto leave;
|
| 215 |
+
} else if ((vmajor == version_major) && (vminor > version_minor)) {
|
| 216 |
+
debug_info("WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
|
| 217 |
+
err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
|
| 218 |
+
goto leave;
|
| 219 |
+
}
|
| 220 |
+
plist_free(array);
|
| 221 |
+
|
| 222 |
+
/* version is ok, send reply */
|
| 223 |
+
array = plist_new_array();
|
| 224 |
+
plist_array_append_item(array, plist_new_string("DLMessageVersionExchange"));
|
| 225 |
+
plist_array_append_item(array, plist_new_string("DLVersionsOk"));
|
| 226 |
+
plist_array_append_item(array, plist_new_uint(version_major));
|
| 227 |
+
err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
|
| 228 |
+
if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
|
| 229 |
+
debug_info("Error when sending DLVersionsOk");
|
| 230 |
+
goto leave;
|
| 231 |
+
}
|
| 232 |
+
plist_free(array);
|
| 233 |
+
|
| 234 |
+
/* receive DeviceReady message */
|
| 235 |
+
array = NULL;
|
| 236 |
+
err = device_link_error(property_list_service_receive_plist(client->parent, &array));
|
| 237 |
+
if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
|
| 238 |
+
debug_info("Error when receiving DLMessageDeviceReady!");
|
| 239 |
+
goto leave;
|
| 240 |
+
}
|
| 241 |
+
device_link_service_get_message(array, &msg);
|
| 242 |
+
if (!msg || strcmp(msg, "DLMessageDeviceReady") != 0) {
|
| 243 |
+
debug_info("Did not get DLMessageDeviceReady!");
|
| 244 |
+
err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
|
| 245 |
+
goto leave;
|
| 246 |
+
}
|
| 247 |
+
err = DEVICE_LINK_SERVICE_E_SUCCESS;
|
| 248 |
+
|
| 249 |
+
leave:
|
| 250 |
+
if (msg) {
|
| 251 |
+
free(msg);
|
| 252 |
+
}
|
| 253 |
+
if (array) {
|
| 254 |
+
plist_free(array);
|
| 255 |
+
}
|
| 256 |
+
return err;
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
/**
|
| 260 |
+
* Performs a disconnect with the connected device link service client.
|
| 261 |
+
*
|
| 262 |
+
* @param client The device link service client to disconnect.
|
| 263 |
+
* @param message Optional message to send send to the device or NULL.
|
| 264 |
+
*
|
| 265 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
|
| 266 |
+
* DEVICE_LINK_SERVICE_E_INVALID_ARG if client is NULL,
|
| 267 |
+
* or DEVICE_LINK_SERVICE_E_MUX_ERROR when there's an error when sending
|
| 268 |
+
* the the disconnect message.
|
| 269 |
+
*/
|
| 270 |
+
device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client, const char *message)
|
| 271 |
+
{
|
| 272 |
+
if (!client)
|
| 273 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 274 |
+
|
| 275 |
+
plist_t array = plist_new_array();
|
| 276 |
+
plist_array_append_item(array, plist_new_string("DLMessageDisconnect"));
|
| 277 |
+
if (message)
|
| 278 |
+
plist_array_append_item(array, plist_new_string(message));
|
| 279 |
+
else
|
| 280 |
+
plist_array_append_item(array, plist_new_string("___EmptyParameterString___"));
|
| 281 |
+
|
| 282 |
+
device_link_service_error_t err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
|
| 283 |
+
plist_free(array);
|
| 284 |
+
|
| 285 |
+
return err;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
/**
|
| 289 |
+
* Sends a DLMessagePing plist.
|
| 290 |
+
*
|
| 291 |
+
* @param client The device link service client to use.
|
| 292 |
+
* @param message String to send as ping message.
|
| 293 |
+
*
|
| 294 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
|
| 295 |
+
* DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid,
|
| 296 |
+
* or DEVICE_LINK_SERVICE_E_MUX_ERROR if the DLMessagePing plist could
|
| 297 |
+
* not be sent.
|
| 298 |
+
*/
|
| 299 |
+
device_link_service_error_t device_link_service_send_ping(device_link_service_client_t client, const char *message)
|
| 300 |
+
{
|
| 301 |
+
if (!client || !client->parent || !message)
|
| 302 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 303 |
+
|
| 304 |
+
plist_t array = plist_new_array();
|
| 305 |
+
plist_array_append_item(array, plist_new_string("DLMessagePing"));
|
| 306 |
+
plist_array_append_item(array, plist_new_string(message));
|
| 307 |
+
|
| 308 |
+
device_link_service_error_t err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
|
| 309 |
+
plist_free(array);
|
| 310 |
+
|
| 311 |
+
return err;
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
/**
|
| 315 |
+
* Sends a DLMessageProcessMessage plist.
|
| 316 |
+
*
|
| 317 |
+
* @param client The device link service client to use.
|
| 318 |
+
* @param message PLIST_DICT to send.
|
| 319 |
+
*
|
| 320 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
|
| 321 |
+
* DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid or
|
| 322 |
+
* message is not a PLIST_DICT, or DEVICE_LINK_SERVICE_E_MUX_ERROR if
|
| 323 |
+
* the DLMessageProcessMessage plist could not be sent.
|
| 324 |
+
*/
|
| 325 |
+
device_link_service_error_t device_link_service_send_process_message(device_link_service_client_t client, plist_t message)
|
| 326 |
+
{
|
| 327 |
+
if (!client || !client->parent || !message)
|
| 328 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 329 |
+
|
| 330 |
+
if (plist_get_node_type(message) != PLIST_DICT)
|
| 331 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 332 |
+
|
| 333 |
+
plist_t array = plist_new_array();
|
| 334 |
+
plist_array_append_item(array, plist_new_string("DLMessageProcessMessage"));
|
| 335 |
+
plist_array_append_item(array, plist_copy(message));
|
| 336 |
+
|
| 337 |
+
device_link_service_error_t err = device_link_error(property_list_service_send_binary_plist(client->parent, array));
|
| 338 |
+
plist_free(array);
|
| 339 |
+
|
| 340 |
+
return err;
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
/**
|
| 344 |
+
* Receives a DL* message plist
|
| 345 |
+
*
|
| 346 |
+
* @param client The connected device link service client used for receiving.
|
| 347 |
+
* @param msg_plist Pointer to a plist that will be set to the contents of the
|
| 348 |
+
* message plist upon successful return.
|
| 349 |
+
* @param dlmessage A pointer that will be set to a newly allocated char*
|
| 350 |
+
* containing the DL* string from the given plist. It is up to the caller
|
| 351 |
+
* to free the allocated memory. If this parameter is NULL
|
| 352 |
+
* it will be ignored.
|
| 353 |
+
*
|
| 354 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS if a DL* message was received,
|
| 355 |
+
* DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid,
|
| 356 |
+
* DEVICE_LINK_SERVICE_E_PLIST_ERROR if the received plist is invalid
|
| 357 |
+
* or is not a DL* message plist, or DEVICE_LINK_SERVICE_E_MUX_ERROR if
|
| 358 |
+
* receiving from the device failed.
|
| 359 |
+
*/
|
| 360 |
+
device_link_service_error_t device_link_service_receive_message(device_link_service_client_t client, plist_t *msg_plist, char **dlmessage)
|
| 361 |
+
{
|
| 362 |
+
if (!client || !client->parent || !msg_plist)
|
| 363 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 364 |
+
|
| 365 |
+
*msg_plist = NULL;
|
| 366 |
+
device_link_service_error_t err = device_link_error(property_list_service_receive_plist(client->parent, msg_plist));
|
| 367 |
+
if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
|
| 368 |
+
return err;
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
if (!device_link_service_get_message(*msg_plist, dlmessage)) {
|
| 372 |
+
debug_info("Did not receive a DL* message as expected!");
|
| 373 |
+
return DEVICE_LINK_SERVICE_E_PLIST_ERROR;
|
| 374 |
+
}
|
| 375 |
+
return DEVICE_LINK_SERVICE_E_SUCCESS;
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
/**
|
| 379 |
+
* Receives a DLMessageProcessMessage plist.
|
| 380 |
+
*
|
| 381 |
+
* @param client The connected device link service client used for receiving.
|
| 382 |
+
* @param message Pointer to a plist that will be set to the contents of the
|
| 383 |
+
* message contents upon successful return.
|
| 384 |
+
*
|
| 385 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS when a DLMessageProcessMessage was
|
| 386 |
+
* received, DEVICE_LINK_SERVICE_E_INVALID_ARG when client or message is
|
| 387 |
+
* invalid, DEVICE_LINK_SERVICE_E_PLIST_ERROR if the received plist is
|
| 388 |
+
* invalid or is not a DLMessageProcessMessage,
|
| 389 |
+
* or DEVICE_LINK_SERVICE_E_MUX_ERROR if receiving from device fails.
|
| 390 |
+
*/
|
| 391 |
+
device_link_service_error_t device_link_service_receive_process_message(device_link_service_client_t client, plist_t *message)
|
| 392 |
+
{
|
| 393 |
+
if (!client || !client->parent || !message)
|
| 394 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 395 |
+
|
| 396 |
+
plist_t pmsg = NULL;
|
| 397 |
+
device_link_service_error_t err = device_link_error(property_list_service_receive_plist(client->parent, &pmsg));
|
| 398 |
+
if (err != DEVICE_LINK_SERVICE_E_SUCCESS) {
|
| 399 |
+
return err;
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;
|
| 403 |
+
|
| 404 |
+
char *msg = NULL;
|
| 405 |
+
device_link_service_get_message(pmsg, &msg);
|
| 406 |
+
if (!msg || strcmp(msg, "DLMessageProcessMessage") != 0) {
|
| 407 |
+
debug_info("Did not receive DLMessageProcessMessage as expected!");
|
| 408 |
+
err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
|
| 409 |
+
goto leave;
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
if (plist_array_get_size(pmsg) != 2) {
|
| 413 |
+
debug_info("Malformed plist received for DLMessageProcessMessage");
|
| 414 |
+
err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
|
| 415 |
+
goto leave;
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
plist_t msg_loc = plist_array_get_item(pmsg, 1);
|
| 419 |
+
if (msg_loc) {
|
| 420 |
+
*message = plist_copy(msg_loc);
|
| 421 |
+
err = DEVICE_LINK_SERVICE_E_SUCCESS;
|
| 422 |
+
} else {
|
| 423 |
+
*message = NULL;
|
| 424 |
+
err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
leave:
|
| 428 |
+
if (msg)
|
| 429 |
+
free(msg);
|
| 430 |
+
if (pmsg)
|
| 431 |
+
plist_free(pmsg);
|
| 432 |
+
|
| 433 |
+
return err;
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
/**
|
| 437 |
+
* Generic device link service send function.
|
| 438 |
+
*
|
| 439 |
+
* @param client The device link service client to use for sending
|
| 440 |
+
* @param plist The property list to send
|
| 441 |
+
*
|
| 442 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
|
| 443 |
+
* DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL,
|
| 444 |
+
* or DEVICE_LINK_SERVICE_E_MUX_ERROR when the given property list could
|
| 445 |
+
* not be sent.
|
| 446 |
+
*/
|
| 447 |
+
device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist)
|
| 448 |
+
{
|
| 449 |
+
if (!client || !plist) {
|
| 450 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 451 |
+
}
|
| 452 |
+
return device_link_error(property_list_service_send_binary_plist(client->parent, plist));
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
/* Generic device link service receive function.
|
| 456 |
+
*
|
| 457 |
+
* @param client The device link service client to use for sending
|
| 458 |
+
* @param plist Pointer that will point to the property list received upon
|
| 459 |
+
* successful return.
|
| 460 |
+
*
|
| 461 |
+
* @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
|
| 462 |
+
* DEVICE_LINK_SERVICE_E_INVALID_ARG when client or plist is NULL,
|
| 463 |
+
* or DEVICE_LINK_SERVICE_E_MUX_ERROR when no property list could be
|
| 464 |
+
* received.
|
| 465 |
+
*/
|
| 466 |
+
device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist)
|
| 467 |
+
{
|
| 468 |
+
if (!client || !plist || (plist && *plist)) {
|
| 469 |
+
return DEVICE_LINK_SERVICE_E_INVALID_ARG;
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
return device_link_error(property_list_service_receive_plist(client->parent, plist));
|
| 473 |
+
}
|
| 474 |
+
|
device_link_service.h
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* device_link_service.h
|
| 3 |
+
* Definitions for the DeviceLink service
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifndef __DEVICE_LINK_SERVICE_H
|
| 23 |
+
#define __DEVICE_LINK_SERVICE_H
|
| 24 |
+
|
| 25 |
+
#include "idevice.h"
|
| 26 |
+
#include "property_list_service.h"
|
| 27 |
+
|
| 28 |
+
/* Error Codes */
|
| 29 |
+
typedef enum {
|
| 30 |
+
DEVICE_LINK_SERVICE_E_SUCCESS = 0,
|
| 31 |
+
DEVICE_LINK_SERVICE_E_INVALID_ARG = -1,
|
| 32 |
+
DEVICE_LINK_SERVICE_E_PLIST_ERROR = -2,
|
| 33 |
+
DEVICE_LINK_SERVICE_E_MUX_ERROR = -3,
|
| 34 |
+
DEVICE_LINK_SERVICE_E_SSL_ERROR = -4,
|
| 35 |
+
DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT = -5,
|
| 36 |
+
DEVICE_LINK_SERVICE_E_BAD_VERSION = -6,
|
| 37 |
+
DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR = -256
|
| 38 |
+
} device_link_service_error_t;
|
| 39 |
+
|
| 40 |
+
struct device_link_service_client_private {
|
| 41 |
+
property_list_service_client_t parent;
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
+
typedef struct device_link_service_client_private *device_link_service_client_t;
|
| 45 |
+
|
| 46 |
+
device_link_service_error_t device_link_service_client_new(idevice_t device, lockdownd_service_descriptor_t service, device_link_service_client_t *client);
|
| 47 |
+
device_link_service_error_t device_link_service_client_free(device_link_service_client_t client);
|
| 48 |
+
device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor);
|
| 49 |
+
device_link_service_error_t device_link_service_send_ping(device_link_service_client_t client, const char *message);
|
| 50 |
+
device_link_service_error_t device_link_service_receive_message(device_link_service_client_t client, plist_t *msg_plist, char **dlmessage);
|
| 51 |
+
device_link_service_error_t device_link_service_send_process_message(device_link_service_client_t client, plist_t message);
|
| 52 |
+
device_link_service_error_t device_link_service_receive_process_message(device_link_service_client_t client, plist_t *message);
|
| 53 |
+
device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client, const char *message);
|
| 54 |
+
device_link_service_error_t device_link_service_send(device_link_service_client_t client, plist_t plist);
|
| 55 |
+
device_link_service_error_t device_link_service_receive(device_link_service_client_t client, plist_t *plist);
|
| 56 |
+
|
| 57 |
+
#endif
|
dfu.c
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* dfu.c
|
| 3 |
+
* Functions for handling idevices in DFU mode
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved.
|
| 7 |
+
* Copyright (c) 2010 Joshua Hill. All Rights Reserved.
|
| 8 |
+
*
|
| 9 |
+
* This library is free software; you can redistribute it and/or
|
| 10 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 11 |
+
* License as published by the Free Software Foundation; either
|
| 12 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This library is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 17 |
+
* Lesser General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 20 |
+
* License along with this library; if not, write to the Free Software
|
| 21 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 22 |
+
*/
|
| 23 |
+
|
| 24 |
+
#include <stdio.h>
|
| 25 |
+
#include <stdlib.h>
|
| 26 |
+
#include <string.h>
|
| 27 |
+
#include <unistd.h>
|
| 28 |
+
#include <libirecovery.h>
|
| 29 |
+
|
| 30 |
+
#include "dfu.h"
|
| 31 |
+
#include "tss.h"
|
| 32 |
+
#include "recovery.h"
|
| 33 |
+
#include "idevicerestore.h"
|
| 34 |
+
#include "common.h"
|
| 35 |
+
|
| 36 |
+
static int dfu_progress_callback(irecv_client_t client, const irecv_event_t* event) {
|
| 37 |
+
if (event->type == IRECV_PROGRESS) {
|
| 38 |
+
print_progress_bar(event->progress);
|
| 39 |
+
}
|
| 40 |
+
return 0;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
int dfu_client_new(struct idevicerestore_client_t* client) {
|
| 44 |
+
int i = 0;
|
| 45 |
+
int attempts = 10;
|
| 46 |
+
irecv_client_t dfu = NULL;
|
| 47 |
+
|
| 48 |
+
if (client->dfu == NULL) {
|
| 49 |
+
client->dfu = (struct dfu_client_t*)malloc(sizeof(struct dfu_client_t));
|
| 50 |
+
memset(client->dfu, 0, sizeof(struct dfu_client_t));
|
| 51 |
+
if (client->dfu == NULL) {
|
| 52 |
+
error("ERROR: Out of memory\n");
|
| 53 |
+
return -1;
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
for (i = 1; i <= attempts; i++) {
|
| 58 |
+
if (irecv_open_with_ecid(&dfu, client->ecid) == IRECV_E_SUCCESS) {
|
| 59 |
+
break;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
if (i >= attempts) {
|
| 63 |
+
error("ERROR: Unable to connect to device in DFU mode\n");
|
| 64 |
+
return -1;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
sleep(1);
|
| 68 |
+
debug("Retrying connection...\n");
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
irecv_event_subscribe(dfu, IRECV_PROGRESS, &dfu_progress_callback, NULL);
|
| 72 |
+
client->dfu->client = dfu;
|
| 73 |
+
return 0;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
void dfu_client_free(struct idevicerestore_client_t* client) {
|
| 77 |
+
if(client != NULL) {
|
| 78 |
+
if (client->dfu != NULL) {
|
| 79 |
+
if(client->dfu->client != NULL) {
|
| 80 |
+
irecv_close(client->dfu->client);
|
| 81 |
+
client->dfu->client = NULL;
|
| 82 |
+
}
|
| 83 |
+
free(client->dfu);
|
| 84 |
+
}
|
| 85 |
+
client->dfu = NULL;
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
int dfu_check_mode(struct idevicerestore_client_t* client, int* mode) {
|
| 90 |
+
irecv_client_t dfu = NULL;
|
| 91 |
+
int probe_mode = -1;
|
| 92 |
+
|
| 93 |
+
if (client->udid && client->ecid == 0) {
|
| 94 |
+
/* if we have a UDID but no ECID we can't make sure this is the correct device */
|
| 95 |
+
return -1;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
irecv_init();
|
| 99 |
+
if (irecv_open_with_ecid(&dfu, client->ecid) != IRECV_E_SUCCESS) {
|
| 100 |
+
return -1;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
irecv_get_mode(dfu, &probe_mode);
|
| 104 |
+
|
| 105 |
+
if ((probe_mode != IRECV_K_DFU_MODE) && (probe_mode != IRECV_K_WTF_MODE)) {
|
| 106 |
+
irecv_close(dfu);
|
| 107 |
+
return -1;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
*mode = (probe_mode == IRECV_K_WTF_MODE) ? MODE_WTF : MODE_DFU;
|
| 111 |
+
|
| 112 |
+
irecv_close(dfu);
|
| 113 |
+
|
| 114 |
+
return 0;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client) {
|
| 118 |
+
irecv_client_t dfu = NULL;
|
| 119 |
+
irecv_error_t dfu_error = IRECV_E_SUCCESS;
|
| 120 |
+
irecv_device_t device = NULL;
|
| 121 |
+
|
| 122 |
+
irecv_init();
|
| 123 |
+
if (irecv_open_with_ecid(&dfu, client->ecid) != IRECV_E_SUCCESS) {
|
| 124 |
+
return NULL;
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
dfu_error = irecv_devices_get_device_by_client(dfu, &device);
|
| 128 |
+
irecv_close(dfu);
|
| 129 |
+
if (dfu_error != IRECV_E_SUCCESS) {
|
| 130 |
+
return NULL;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
return device;
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size)
|
| 137 |
+
{
|
| 138 |
+
irecv_error_t err = 0;
|
| 139 |
+
|
| 140 |
+
info("Sending data (%d bytes)...\n", size);
|
| 141 |
+
|
| 142 |
+
err = irecv_send_buffer(client->dfu->client, buffer, size, 1);
|
| 143 |
+
if (err != IRECV_E_SUCCESS) {
|
| 144 |
+
error("ERROR: Unable to send data: %s\n", irecv_strerror(err));
|
| 145 |
+
return -1;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
return 0;
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) {
|
| 152 |
+
char* path = NULL;
|
| 153 |
+
|
| 154 |
+
if (client->tss) {
|
| 155 |
+
if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) {
|
| 156 |
+
debug("NOTE: No path for component %s in TSS, will fetch from build_identity\n", component);
|
| 157 |
+
}
|
| 158 |
+
}
|
| 159 |
+
if (!path) {
|
| 160 |
+
if (build_identity_get_component_path(build_identity, component, &path) < 0) {
|
| 161 |
+
error("ERROR: Unable to get path for component '%s'\n", component);
|
| 162 |
+
free(path);
|
| 163 |
+
return -1;
|
| 164 |
+
}
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
unsigned char* component_data = NULL;
|
| 168 |
+
unsigned int component_size = 0;
|
| 169 |
+
|
| 170 |
+
if (extract_component(client->ipsw, path, &component_data, &component_size) < 0) {
|
| 171 |
+
error("ERROR: Unable to extract component: %s\n", component);
|
| 172 |
+
free(path);
|
| 173 |
+
return -1;
|
| 174 |
+
}
|
| 175 |
+
free(path);
|
| 176 |
+
path = NULL;
|
| 177 |
+
|
| 178 |
+
unsigned char* data = NULL;
|
| 179 |
+
uint32_t size = 0;
|
| 180 |
+
|
| 181 |
+
if (personalize_component(component, component_data, component_size, client->tss, &data, &size) < 0) {
|
| 182 |
+
error("ERROR: Unable to get personalized component: %s\n", component);
|
| 183 |
+
free(component_data);
|
| 184 |
+
return -1;
|
| 185 |
+
}
|
| 186 |
+
free(component_data);
|
| 187 |
+
component_data = NULL;
|
| 188 |
+
|
| 189 |
+
if (!client->image4supported && client->build_major > 8 && !(client->flags & FLAG_CUSTOM) && !strcmp(component, "iBEC")) {
|
| 190 |
+
unsigned char* ticket = NULL;
|
| 191 |
+
unsigned int tsize = 0;
|
| 192 |
+
if (tss_response_get_ap_ticket(client->tss, &ticket, &tsize) < 0) {
|
| 193 |
+
error("ERROR: Unable to get ApTicket from TSS request\n");
|
| 194 |
+
return -1;
|
| 195 |
+
}
|
| 196 |
+
uint32_t fillsize = 0;
|
| 197 |
+
if (tsize % 64 != 0) {
|
| 198 |
+
fillsize = ((tsize / 64) + 1) * 64;
|
| 199 |
+
}
|
| 200 |
+
debug("ticket size = %d\nfillsize = %d\n", tsize, fillsize);
|
| 201 |
+
unsigned char* newdata = (unsigned char*)malloc(size + fillsize);
|
| 202 |
+
memcpy(newdata, ticket, tsize);
|
| 203 |
+
memset(newdata + tsize, '\xFF', fillsize - tsize);
|
| 204 |
+
memcpy(newdata + fillsize, data, size);
|
| 205 |
+
free(data);
|
| 206 |
+
data = newdata;
|
| 207 |
+
size += fillsize;
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
info("Sending %s (%d bytes)...\n", component, size);
|
| 211 |
+
|
| 212 |
+
// FIXME: Did I do this right????
|
| 213 |
+
irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, 1);
|
| 214 |
+
if (err != IRECV_E_SUCCESS) {
|
| 215 |
+
error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err));
|
| 216 |
+
free(data);
|
| 217 |
+
return -1;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
free(data);
|
| 221 |
+
return 0;
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) {
|
| 225 |
+
if(client->dfu == NULL) {
|
| 226 |
+
if (dfu_client_new(client) < 0) {
|
| 227 |
+
return -1;
|
| 228 |
+
}
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
|
| 232 |
+
if (!device_info) {
|
| 233 |
+
return -1;
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
*cpid = device_info->cpid;
|
| 237 |
+
|
| 238 |
+
return 0;
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) {
|
| 242 |
+
if(client->dfu == NULL) {
|
| 243 |
+
if (dfu_client_new(client) < 0) {
|
| 244 |
+
return -1;
|
| 245 |
+
}
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
|
| 249 |
+
if (!device_info) {
|
| 250 |
+
return -1;
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
*ecid = device_info->ecid;
|
| 254 |
+
|
| 255 |
+
return 0;
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
int dfu_is_image4_supported(struct idevicerestore_client_t* client)
|
| 259 |
+
{
|
| 260 |
+
if(client->dfu == NULL) {
|
| 261 |
+
if (dfu_client_new(client) < 0) {
|
| 262 |
+
return 0;
|
| 263 |
+
}
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
|
| 267 |
+
if (!device_info) {
|
| 268 |
+
return 0;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE);
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) {
|
| 275 |
+
if(client->dfu == NULL) {
|
| 276 |
+
if (dfu_client_new(client) < 0) {
|
| 277 |
+
return -1;
|
| 278 |
+
}
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
|
| 282 |
+
if (!device_info) {
|
| 283 |
+
return -1;
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
if (device_info->ap_nonce && device_info->ap_nonce_size > 0) {
|
| 287 |
+
*nonce = (unsigned char*)malloc(device_info->ap_nonce_size);
|
| 288 |
+
if (!*nonce) {
|
| 289 |
+
return -1;
|
| 290 |
+
}
|
| 291 |
+
*nonce_size = device_info->ap_nonce_size;
|
| 292 |
+
memcpy(*nonce, device_info->ap_nonce, *nonce_size);
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
return 0;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) {
|
| 299 |
+
if(client->dfu == NULL) {
|
| 300 |
+
if (dfu_client_new(client) < 0) {
|
| 301 |
+
return -1;
|
| 302 |
+
}
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client);
|
| 306 |
+
if (!device_info) {
|
| 307 |
+
return -1;
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
if (device_info->sep_nonce && device_info->sep_nonce_size > 0) {
|
| 311 |
+
*nonce = (unsigned char*)malloc(device_info->sep_nonce_size);
|
| 312 |
+
if (!*nonce) {
|
| 313 |
+
return -1;
|
| 314 |
+
}
|
| 315 |
+
*nonce_size = device_info->sep_nonce_size;
|
| 316 |
+
memcpy(*nonce, device_info->sep_nonce, *nonce_size);
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
return 0;
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity)
|
| 323 |
+
{
|
| 324 |
+
int mode = 0;
|
| 325 |
+
|
| 326 |
+
if (dfu_client_new(client) < 0) {
|
| 327 |
+
error("ERROR: Unable to connect to DFU device\n");
|
| 328 |
+
return -1;
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
irecv_get_mode(client->dfu->client, &mode);
|
| 332 |
+
|
| 333 |
+
if (mode != IRECV_K_DFU_MODE) {
|
| 334 |
+
info("NOTE: device is not in DFU mode, assuming recovery mode.\n");
|
| 335 |
+
client->mode = &idevicerestore_modes[MODE_RECOVERY];
|
| 336 |
+
return 0;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
mutex_lock(&client->device_event_mutex);
|
| 340 |
+
|
| 341 |
+
if (dfu_send_component(client, build_identity, "iBSS") < 0) {
|
| 342 |
+
error("ERROR: Unable to send iBSS to device\n");
|
| 343 |
+
irecv_close(client->dfu->client);
|
| 344 |
+
client->dfu->client = NULL;
|
| 345 |
+
return -1;
|
| 346 |
+
}
|
| 347 |
+
dfu_client_free(client);
|
| 348 |
+
|
| 349 |
+
if (client->build_major > 8) {
|
| 350 |
+
/* reconnect */
|
| 351 |
+
debug("Waiting for device to disconnect...\n");
|
| 352 |
+
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
|
| 353 |
+
if (client->mode != &idevicerestore_modes[MODE_UNKNOWN] || (client->flags & FLAG_QUIT)) {
|
| 354 |
+
mutex_unlock(&client->device_event_mutex);
|
| 355 |
+
if (!(client->flags & FLAG_QUIT)) {
|
| 356 |
+
error("ERROR: Device did not disconnect. Possibly invalid iBSS. Reset device and try again.\n");
|
| 357 |
+
}
|
| 358 |
+
return -1;
|
| 359 |
+
}
|
| 360 |
+
debug("Waiting for device to reconnect...\n");
|
| 361 |
+
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
|
| 362 |
+
if ((client->mode != &idevicerestore_modes[MODE_DFU] && client->mode != &idevicerestore_modes[MODE_RECOVERY]) || (client->flags & FLAG_QUIT)) {
|
| 363 |
+
mutex_unlock(&client->device_event_mutex);
|
| 364 |
+
if (!(client->flags & FLAG_QUIT)) {
|
| 365 |
+
error("ERROR: Device did not reconnect in DFU or recovery mode. Possibly invalid iBSS. Reset device and try again.\n");
|
| 366 |
+
}
|
| 367 |
+
return -1;
|
| 368 |
+
}
|
| 369 |
+
mutex_unlock(&client->device_event_mutex);
|
| 370 |
+
dfu_client_new(client);
|
| 371 |
+
|
| 372 |
+
/* get nonce */
|
| 373 |
+
unsigned char* nonce = NULL;
|
| 374 |
+
int nonce_size = 0;
|
| 375 |
+
int nonce_changed = 0;
|
| 376 |
+
if (dfu_get_ap_nonce(client, &nonce, &nonce_size) < 0) {
|
| 377 |
+
error("ERROR: Unable to get ApNonce from device!\n");
|
| 378 |
+
return -1;
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
|
| 382 |
+
nonce_changed = 1;
|
| 383 |
+
if (client->nonce) {
|
| 384 |
+
free(client->nonce);
|
| 385 |
+
}
|
| 386 |
+
client->nonce = nonce;
|
| 387 |
+
client->nonce_size = nonce_size;
|
| 388 |
+
} else {
|
| 389 |
+
free(nonce);
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
info("Nonce: ");
|
| 393 |
+
int i;
|
| 394 |
+
for (i = 0; i < client->nonce_size; i++) {
|
| 395 |
+
info("%02x ", client->nonce[i]);
|
| 396 |
+
}
|
| 397 |
+
info("\n");
|
| 398 |
+
|
| 399 |
+
if (nonce_changed && !(client->flags & FLAG_CUSTOM)) {
|
| 400 |
+
// Welcome iOS5. We have to re-request the TSS with our nonce.
|
| 401 |
+
plist_free(client->tss);
|
| 402 |
+
if (get_tss_response(client, build_identity, &client->tss) < 0) {
|
| 403 |
+
error("ERROR: Unable to get SHSH blobs for this device\n");
|
| 404 |
+
return -1;
|
| 405 |
+
}
|
| 406 |
+
if (!client->tss) {
|
| 407 |
+
error("ERROR: can't continue without TSS\n");
|
| 408 |
+
return -1;
|
| 409 |
+
}
|
| 410 |
+
fixup_tss(client->tss);
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
if (irecv_usb_set_configuration(client->dfu->client, 1) < 0) {
|
| 414 |
+
error("ERROR: set configuration failed\n");
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
mutex_lock(&client->device_event_mutex);
|
| 418 |
+
|
| 419 |
+
/* send iBEC */
|
| 420 |
+
if (dfu_send_component(client, build_identity, "iBEC") < 0) {
|
| 421 |
+
mutex_unlock(&client->device_event_mutex);
|
| 422 |
+
error("ERROR: Unable to send iBEC to device\n");
|
| 423 |
+
irecv_close(client->dfu->client);
|
| 424 |
+
client->dfu->client = NULL;
|
| 425 |
+
return -1;
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
if (client->mode == &idevicerestore_modes[MODE_RECOVERY]) {
|
| 429 |
+
if (irecv_send_command(client->dfu->client, "go") != IRECV_E_SUCCESS) {
|
| 430 |
+
mutex_unlock(&client->device_event_mutex);
|
| 431 |
+
error("ERROR: Unable to execute iBEC\n");
|
| 432 |
+
return -1;
|
| 433 |
+
}
|
| 434 |
+
irecv_usb_control_transfer(client->dfu->client, 0x21, 1, 0, 0, 0, 0, 5000);
|
| 435 |
+
}
|
| 436 |
+
dfu_client_free(client);
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
debug("Waiting for device to disconnect...\n");
|
| 440 |
+
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
|
| 441 |
+
if (client->mode != &idevicerestore_modes[MODE_UNKNOWN] || (client->flags & FLAG_QUIT)) {
|
| 442 |
+
mutex_unlock(&client->device_event_mutex);
|
| 443 |
+
if (!(client->flags & FLAG_QUIT)) {
|
| 444 |
+
error("ERROR: Device did not disconnect. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS");
|
| 445 |
+
}
|
| 446 |
+
return -1;
|
| 447 |
+
}
|
| 448 |
+
debug("Waiting for device to reconnect in recovery mode...\n");
|
| 449 |
+
cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
|
| 450 |
+
if (client->mode != &idevicerestore_modes[MODE_RECOVERY] || (client->flags & FLAG_QUIT)) {
|
| 451 |
+
mutex_unlock(&client->device_event_mutex);
|
| 452 |
+
if (!(client->flags & FLAG_QUIT)) {
|
| 453 |
+
error("ERROR: Device did not reconnect in recovery mode. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS");
|
| 454 |
+
}
|
| 455 |
+
return -1;
|
| 456 |
+
}
|
| 457 |
+
mutex_unlock(&client->device_event_mutex);
|
| 458 |
+
|
| 459 |
+
if (recovery_client_new(client) < 0) {
|
| 460 |
+
error("ERROR: Unable to connect to recovery device\n");
|
| 461 |
+
if (client->recovery->client) {
|
| 462 |
+
irecv_close(client->recovery->client);
|
| 463 |
+
client->recovery->client = NULL;
|
| 464 |
+
}
|
| 465 |
+
return -1;
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
return 0;
|
| 469 |
+
}
|
| 470 |
+
|
dfu.h
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* dfu.h
|
| 3 |
+
* Functions for handling idevices in DFU mode
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2012-2015 Nikias Bassen. All Rights Reserved.
|
| 7 |
+
* Copyright (c) 2010 Joshua Hill. All Rights Reserved.
|
| 8 |
+
*
|
| 9 |
+
* This library is free software; you can redistribute it and/or
|
| 10 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 11 |
+
* License as published by the Free Software Foundation; either
|
| 12 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This library is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 17 |
+
* Lesser General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 20 |
+
* License along with this library; if not, write to the Free Software
|
| 21 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 22 |
+
*/
|
| 23 |
+
|
| 24 |
+
#ifndef IDEVICERESTORE_DFU_H
|
| 25 |
+
#define IDEVICERESTORE_DFU_H
|
| 26 |
+
|
| 27 |
+
#ifdef __cplusplus
|
| 28 |
+
extern "C" {
|
| 29 |
+
#endif
|
| 30 |
+
|
| 31 |
+
#include <libirecovery.h>
|
| 32 |
+
#include "common.h"
|
| 33 |
+
|
| 34 |
+
struct dfu_client_t {
|
| 35 |
+
irecv_client_t client;
|
| 36 |
+
const char* ipsw;
|
| 37 |
+
plist_t tss;
|
| 38 |
+
};
|
| 39 |
+
|
| 40 |
+
int dfu_client_new(struct idevicerestore_client_t* client);
|
| 41 |
+
void dfu_client_free(struct idevicerestore_client_t* client);
|
| 42 |
+
int dfu_check_mode(struct idevicerestore_client_t* client, int* mode);
|
| 43 |
+
irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client);
|
| 44 |
+
int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size);
|
| 45 |
+
int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component);
|
| 46 |
+
int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid);
|
| 47 |
+
int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
|
| 48 |
+
int dfu_is_image4_supported(struct idevicerestore_client_t* client);
|
| 49 |
+
int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
|
| 50 |
+
int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
|
| 51 |
+
int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity);
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
#ifdef __cplusplus
|
| 55 |
+
}
|
| 56 |
+
#endif
|
| 57 |
+
|
| 58 |
+
#endif
|
diagnostics_relay.c
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* diagnostics_relay.c
|
| 3 |
+
* com.apple.mobile.diagnostics_relay service implementation.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012 Martin Szulecki, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifdef HAVE_CONFIG_H
|
| 23 |
+
#include <config.h>
|
| 24 |
+
#endif
|
| 25 |
+
#include <string.h>
|
| 26 |
+
#include <stdlib.h>
|
| 27 |
+
#include "diagnostics_relay.h"
|
| 28 |
+
#include "property_list_service.h"
|
| 29 |
+
#include "common/debug.h"
|
| 30 |
+
|
| 31 |
+
#define RESULT_SUCCESS 0
|
| 32 |
+
#define RESULT_FAILURE 1
|
| 33 |
+
#define RESULT_UNKNOWN_REQUEST 2
|
| 34 |
+
|
| 35 |
+
/**
|
| 36 |
+
* Internally used function for checking the result from a service response
|
| 37 |
+
* plist to a previously sent request.
|
| 38 |
+
*
|
| 39 |
+
* @param dict The plist to evaluate.
|
| 40 |
+
*
|
| 41 |
+
* @return RESULT_SUCCESS when the result is 'Success',
|
| 42 |
+
* RESULT_FAILURE when the result is 'Failure',
|
| 43 |
+
* or a negative value if an error occurred during evaluation.
|
| 44 |
+
*/
|
| 45 |
+
static int diagnostics_relay_check_result(plist_t dict)
|
| 46 |
+
{
|
| 47 |
+
int ret = -1;
|
| 48 |
+
|
| 49 |
+
plist_t result_node = plist_dict_get_item(dict, "Status");
|
| 50 |
+
if (!result_node)
|
| 51 |
+
return ret;
|
| 52 |
+
|
| 53 |
+
plist_type result_type = plist_get_node_type(result_node);
|
| 54 |
+
if (result_type == PLIST_STRING) {
|
| 55 |
+
char *result_value = NULL;
|
| 56 |
+
|
| 57 |
+
plist_get_string_val(result_node, &result_value);
|
| 58 |
+
|
| 59 |
+
if (result_value) {
|
| 60 |
+
if (!strcmp(result_value, "Success")) {
|
| 61 |
+
ret = RESULT_SUCCESS;
|
| 62 |
+
} else if (!strcmp(result_value, "Failure")) {
|
| 63 |
+
ret = RESULT_FAILURE;
|
| 64 |
+
} else if (!strcmp(result_value, "UnknownRequest")) {
|
| 65 |
+
ret = RESULT_UNKNOWN_REQUEST;
|
| 66 |
+
} else {
|
| 67 |
+
debug_info("ERROR: unknown result value '%s'", result_value);
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
if (result_value)
|
| 71 |
+
free(result_value);
|
| 72 |
+
}
|
| 73 |
+
return ret;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, diagnostics_relay_client_t *client)
|
| 77 |
+
{
|
| 78 |
+
if (!device || !service || service->port == 0 || !client || *client) {
|
| 79 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
property_list_service_client_t plistclient = NULL;
|
| 83 |
+
if (property_list_service_client_new(device, service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
|
| 84 |
+
return DIAGNOSTICS_RELAY_E_MUX_ERROR;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
/* create client object */
|
| 88 |
+
diagnostics_relay_client_t client_loc = (diagnostics_relay_client_t) malloc(sizeof(struct diagnostics_relay_client_private));
|
| 89 |
+
client_loc->parent = plistclient;
|
| 90 |
+
|
| 91 |
+
/* all done, return success */
|
| 92 |
+
*client = client_loc;
|
| 93 |
+
return DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
diagnostics_relay_error_t diagnostics_relay_client_start_service(idevice_t device, diagnostics_relay_client_t * client, const char* label)
|
| 97 |
+
{
|
| 98 |
+
diagnostics_relay_error_t err = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 99 |
+
service_client_factory_start_service(device, DIAGNOSTICS_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(diagnostics_relay_client_new), &err);
|
| 100 |
+
return err;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client)
|
| 104 |
+
{
|
| 105 |
+
if (!client)
|
| 106 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 107 |
+
|
| 108 |
+
if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
|
| 109 |
+
return DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 110 |
+
}
|
| 111 |
+
free(client);
|
| 112 |
+
return DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
/**
|
| 116 |
+
* Receives a plist from the service.
|
| 117 |
+
*
|
| 118 |
+
* @param client The diagnostics_relay client
|
| 119 |
+
* @param plist The plist to store the received data
|
| 120 |
+
*
|
| 121 |
+
* @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
|
| 122 |
+
* DIAGNOSTICS_RELAY_E_INVALID_ARG when client or plist is NULL
|
| 123 |
+
*/
|
| 124 |
+
static diagnostics_relay_error_t diagnostics_relay_receive(diagnostics_relay_client_t client, plist_t *plist)
|
| 125 |
+
{
|
| 126 |
+
if (!client || !plist || (plist && *plist))
|
| 127 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 128 |
+
|
| 129 |
+
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 130 |
+
property_list_service_error_t err;
|
| 131 |
+
|
| 132 |
+
err = property_list_service_receive_plist(client->parent, plist);
|
| 133 |
+
if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
|
| 134 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
if (!*plist)
|
| 138 |
+
ret = DIAGNOSTICS_RELAY_E_PLIST_ERROR;
|
| 139 |
+
|
| 140 |
+
return ret;
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
/**
|
| 144 |
+
* Sends a plist to the service.
|
| 145 |
+
*
|
| 146 |
+
* @note This function is low-level and should only be used if you need to send
|
| 147 |
+
* a new type of message.
|
| 148 |
+
*
|
| 149 |
+
* @param client The diagnostics_relay client
|
| 150 |
+
* @param plist The plist to send
|
| 151 |
+
*
|
| 152 |
+
* @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
|
| 153 |
+
* DIAGNOSTICS_RELAY_E_INVALID_ARG when client or plist is NULL
|
| 154 |
+
*/
|
| 155 |
+
static diagnostics_relay_error_t diagnostics_relay_send(diagnostics_relay_client_t client, plist_t plist)
|
| 156 |
+
{
|
| 157 |
+
if (!client || !plist)
|
| 158 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 159 |
+
|
| 160 |
+
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 161 |
+
property_list_service_error_t err;
|
| 162 |
+
|
| 163 |
+
err = property_list_service_send_xml_plist(client->parent, plist);
|
| 164 |
+
if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
|
| 165 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 166 |
+
}
|
| 167 |
+
return ret;
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client)
|
| 171 |
+
{
|
| 172 |
+
if (!client)
|
| 173 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 174 |
+
|
| 175 |
+
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 176 |
+
|
| 177 |
+
plist_t dict = plist_new_dict();
|
| 178 |
+
plist_dict_set_item(dict, "Request", plist_new_string("Goodbye"));
|
| 179 |
+
|
| 180 |
+
ret = diagnostics_relay_send(client, dict);
|
| 181 |
+
plist_free(dict);
|
| 182 |
+
dict = NULL;
|
| 183 |
+
|
| 184 |
+
ret = diagnostics_relay_receive(client, &dict);
|
| 185 |
+
if (!dict) {
|
| 186 |
+
debug_info("did not get goodbye response back");
|
| 187 |
+
return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
int check = diagnostics_relay_check_result(dict);
|
| 191 |
+
if (check == RESULT_SUCCESS) {
|
| 192 |
+
ret = DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 193 |
+
} else if (check == RESULT_UNKNOWN_REQUEST) {
|
| 194 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
|
| 195 |
+
} else {
|
| 196 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
plist_free(dict);
|
| 200 |
+
dict = NULL;
|
| 201 |
+
return ret;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
|
| 205 |
+
{
|
| 206 |
+
if (!client)
|
| 207 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 208 |
+
|
| 209 |
+
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 210 |
+
|
| 211 |
+
plist_t dict = plist_new_dict();
|
| 212 |
+
|
| 213 |
+
plist_dict_set_item(dict,"Request", plist_new_string("Sleep"));
|
| 214 |
+
ret = diagnostics_relay_send(client, dict);
|
| 215 |
+
plist_free(dict);
|
| 216 |
+
dict = NULL;
|
| 217 |
+
|
| 218 |
+
ret = diagnostics_relay_receive(client, &dict);
|
| 219 |
+
if (!dict) {
|
| 220 |
+
return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
int check = diagnostics_relay_check_result(dict);
|
| 224 |
+
if (check == RESULT_SUCCESS) {
|
| 225 |
+
ret = DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 226 |
+
} else if (check == RESULT_UNKNOWN_REQUEST) {
|
| 227 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
|
| 228 |
+
} else {
|
| 229 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
plist_free(dict);
|
| 233 |
+
return ret;
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_relay_client_t client, const char* name, diagnostics_relay_action_t flags)
|
| 237 |
+
{
|
| 238 |
+
if (!client)
|
| 239 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 240 |
+
|
| 241 |
+
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 242 |
+
|
| 243 |
+
plist_t dict = plist_new_dict();
|
| 244 |
+
plist_dict_set_item(dict,"Request", plist_new_string(name));
|
| 245 |
+
|
| 246 |
+
if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) {
|
| 247 |
+
plist_dict_set_item(dict, "WaitForDisconnect", plist_new_bool(1));
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS) {
|
| 251 |
+
plist_dict_set_item(dict, "DisplayPass", plist_new_bool(1));
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL) {
|
| 255 |
+
plist_dict_set_item(dict, "DisplayFail", plist_new_bool(1));
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
ret = diagnostics_relay_send(client, dict);
|
| 259 |
+
plist_free(dict);
|
| 260 |
+
dict = NULL;
|
| 261 |
+
|
| 262 |
+
ret = diagnostics_relay_receive(client, &dict);
|
| 263 |
+
if (!dict) {
|
| 264 |
+
return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
int check = diagnostics_relay_check_result(dict);
|
| 268 |
+
if (check == RESULT_SUCCESS) {
|
| 269 |
+
ret = DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 270 |
+
} else if (check == RESULT_UNKNOWN_REQUEST) {
|
| 271 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
|
| 272 |
+
} else {
|
| 273 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
plist_free(dict);
|
| 277 |
+
return ret;
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
|
| 281 |
+
{
|
| 282 |
+
return internal_diagnostics_relay_action(client, "Restart", flags);
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
|
| 286 |
+
{
|
| 287 |
+
return internal_diagnostics_relay_action(client, "Shutdown", flags);
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics)
|
| 291 |
+
{
|
| 292 |
+
if (!client || diagnostics == NULL)
|
| 293 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 294 |
+
|
| 295 |
+
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 296 |
+
|
| 297 |
+
plist_t dict = plist_new_dict();
|
| 298 |
+
plist_dict_set_item(dict,"Request", plist_new_string(type));
|
| 299 |
+
ret = diagnostics_relay_send(client, dict);
|
| 300 |
+
plist_free(dict);
|
| 301 |
+
dict = NULL;
|
| 302 |
+
if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
|
| 303 |
+
return ret;
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
ret = diagnostics_relay_receive(client, &dict);
|
| 307 |
+
if (!dict) {
|
| 308 |
+
return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
int check = diagnostics_relay_check_result(dict);
|
| 312 |
+
if (check == RESULT_SUCCESS) {
|
| 313 |
+
ret = DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 314 |
+
} else if (check == RESULT_UNKNOWN_REQUEST) {
|
| 315 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
|
| 316 |
+
} else {
|
| 317 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
|
| 321 |
+
plist_free(dict);
|
| 322 |
+
return ret;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
|
| 326 |
+
if (value_node) {
|
| 327 |
+
*diagnostics = plist_copy(value_node);
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
plist_free(dict);
|
| 331 |
+
return ret;
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result)
|
| 335 |
+
{
|
| 336 |
+
if (!client || plist_get_node_type(keys) != PLIST_ARRAY || result == NULL)
|
| 337 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 338 |
+
|
| 339 |
+
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 340 |
+
|
| 341 |
+
plist_t dict = plist_new_dict();
|
| 342 |
+
plist_dict_set_item(dict,"MobileGestaltKeys", plist_copy(keys));
|
| 343 |
+
plist_dict_set_item(dict,"Request", plist_new_string("MobileGestalt"));
|
| 344 |
+
ret = diagnostics_relay_send(client, dict);
|
| 345 |
+
plist_free(dict);
|
| 346 |
+
dict = NULL;
|
| 347 |
+
if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
|
| 348 |
+
return ret;
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
ret = diagnostics_relay_receive(client, &dict);
|
| 352 |
+
if (!dict) {
|
| 353 |
+
return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
int check = diagnostics_relay_check_result(dict);
|
| 357 |
+
if (check == RESULT_SUCCESS) {
|
| 358 |
+
ret = DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 359 |
+
} else if (check == RESULT_UNKNOWN_REQUEST) {
|
| 360 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
|
| 361 |
+
} else {
|
| 362 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
|
| 366 |
+
plist_free(dict);
|
| 367 |
+
return ret;
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
|
| 371 |
+
if (value_node) {
|
| 372 |
+
*result = plist_copy(value_node);
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
plist_free(dict);
|
| 376 |
+
return ret;
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* entry_name, const char* entry_class, plist_t* result)
|
| 380 |
+
{
|
| 381 |
+
if (!client || (entry_name == NULL && entry_class == NULL) || result == NULL)
|
| 382 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 383 |
+
|
| 384 |
+
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 385 |
+
|
| 386 |
+
plist_t dict = plist_new_dict();
|
| 387 |
+
if (entry_name)
|
| 388 |
+
plist_dict_set_item(dict,"EntryName", plist_new_string(entry_name));
|
| 389 |
+
if (entry_class)
|
| 390 |
+
plist_dict_set_item(dict,"EntryClass", plist_new_string(entry_class));
|
| 391 |
+
plist_dict_set_item(dict,"Request", plist_new_string("IORegistry"));
|
| 392 |
+
ret = diagnostics_relay_send(client, dict);
|
| 393 |
+
plist_free(dict);
|
| 394 |
+
dict = NULL;
|
| 395 |
+
if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
|
| 396 |
+
return ret;
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
ret = diagnostics_relay_receive(client, &dict);
|
| 400 |
+
if (!dict) {
|
| 401 |
+
return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
int check = diagnostics_relay_check_result(dict);
|
| 405 |
+
if (check == RESULT_SUCCESS) {
|
| 406 |
+
ret = DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 407 |
+
} else if (check == RESULT_UNKNOWN_REQUEST) {
|
| 408 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
|
| 409 |
+
} else {
|
| 410 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
|
| 414 |
+
plist_free(dict);
|
| 415 |
+
return ret;
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
|
| 419 |
+
if (value_node) {
|
| 420 |
+
*result = plist_copy(value_node);
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
plist_free(dict);
|
| 424 |
+
return ret;
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, const char* plane, plist_t* result)
|
| 428 |
+
{
|
| 429 |
+
if (!client || plane == NULL || result == NULL)
|
| 430 |
+
return DIAGNOSTICS_RELAY_E_INVALID_ARG;
|
| 431 |
+
|
| 432 |
+
diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 433 |
+
|
| 434 |
+
plist_t dict = plist_new_dict();
|
| 435 |
+
plist_dict_set_item(dict,"CurrentPlane", plist_new_string(plane));
|
| 436 |
+
plist_dict_set_item(dict,"Request", plist_new_string("IORegistry"));
|
| 437 |
+
ret = diagnostics_relay_send(client, dict);
|
| 438 |
+
plist_free(dict);
|
| 439 |
+
dict = NULL;
|
| 440 |
+
|
| 441 |
+
ret = diagnostics_relay_receive(client, &dict);
|
| 442 |
+
if (!dict) {
|
| 443 |
+
return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
int check = diagnostics_relay_check_result(dict);
|
| 447 |
+
if (check == RESULT_SUCCESS) {
|
| 448 |
+
ret = DIAGNOSTICS_RELAY_E_SUCCESS;
|
| 449 |
+
} else if (check == RESULT_UNKNOWN_REQUEST) {
|
| 450 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST;
|
| 451 |
+
} else {
|
| 452 |
+
ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
|
| 456 |
+
plist_free(dict);
|
| 457 |
+
return ret;
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
|
| 461 |
+
if (value_node) {
|
| 462 |
+
*result = plist_copy(value_node);
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
plist_free(dict);
|
| 466 |
+
return ret;
|
| 467 |
+
}
|
diagnostics_relay.h
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* diagnostics_relay.h
|
| 3 |
+
* com.apple.mobile.diagnostics_relay service header file.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012 Martin Szulecki, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifndef __DIAGNOSTICS_RELAY_H
|
| 23 |
+
#define __DIAGNOSTICS_RELAY_H
|
| 24 |
+
|
| 25 |
+
#include "idevice.h"
|
| 26 |
+
#include "libimobiledevice/diagnostics_relay.h"
|
| 27 |
+
#include "property_list_service.h"
|
| 28 |
+
|
| 29 |
+
struct diagnostics_relay_client_private {
|
| 30 |
+
property_list_service_client_t parent;
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
#endif
|
diagnostics_relay.pxi
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
REQUEST_TYPE_ALL = "All"
|
| 2 |
+
REQUEST_TYPE_WIFI = "WiFi"
|
| 3 |
+
REQUEST_TYPE_GAS_GAUGE = "GasGauge"
|
| 4 |
+
REQUEST_TYPE_NAND = "NAND"
|
| 5 |
+
|
| 6 |
+
cdef extern from "libimobiledevice/diagnostics_relay.h":
|
| 7 |
+
cdef struct diagnostics_relay_client_private:
|
| 8 |
+
pass
|
| 9 |
+
ctypedef diagnostics_relay_client_private *diagnostics_relay_client_t
|
| 10 |
+
|
| 11 |
+
ctypedef enum diagnostics_relay_error_t:
|
| 12 |
+
DIAGNOSTICS_RELAY_E_SUCCESS = 0
|
| 13 |
+
DIAGNOSTICS_RELAY_E_INVALID_ARG = -1
|
| 14 |
+
DIAGNOSTICS_RELAY_E_PLIST_ERROR = -2
|
| 15 |
+
DIAGNOSTICS_RELAY_E_MUX_ERROR = -3
|
| 16 |
+
DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST = -4
|
| 17 |
+
DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR = -256
|
| 18 |
+
ctypedef enum diagnostics_relay_action_t:
|
| 19 |
+
DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT = (1 << 1)
|
| 20 |
+
DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS = (1 << 2)
|
| 21 |
+
DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL = (1 << 3)
|
| 22 |
+
|
| 23 |
+
diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, diagnostics_relay_client_t * client)
|
| 24 |
+
diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client)
|
| 25 |
+
|
| 26 |
+
diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client)
|
| 27 |
+
diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
|
| 28 |
+
diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
|
| 29 |
+
diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags)
|
| 30 |
+
diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, char* type, plist.plist_t* diagnostics)
|
| 31 |
+
diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist.plist_t keys, plist.plist_t* result)
|
| 32 |
+
diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, char* name, char* class_name, plist.plist_t* result)
|
| 33 |
+
diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, char* plane, plist.plist_t* result)
|
| 34 |
+
|
| 35 |
+
cdef class DiagnosticsRelayError(BaseError):
|
| 36 |
+
def __init__(self, *args, **kwargs):
|
| 37 |
+
self._lookup_table = {
|
| 38 |
+
DIAGNOSTICS_RELAY_E_SUCCESS: "Success",
|
| 39 |
+
DIAGNOSTICS_RELAY_E_INVALID_ARG: "Invalid argument",
|
| 40 |
+
DIAGNOSTICS_RELAY_E_PLIST_ERROR: "Property list error",
|
| 41 |
+
DIAGNOSTICS_RELAY_E_MUX_ERROR: "MUX error",
|
| 42 |
+
DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST: "Unknown request",
|
| 43 |
+
DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR: "Unknown error"
|
| 44 |
+
}
|
| 45 |
+
BaseError.__init__(self, *args, **kwargs)
|
| 46 |
+
|
| 47 |
+
cdef class DiagnosticsRelayClient(PropertyListService):
|
| 48 |
+
__service_name__ = "com.apple.mobile.diagnostics_relay"
|
| 49 |
+
cdef diagnostics_relay_client_t _c_client
|
| 50 |
+
|
| 51 |
+
def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs):
|
| 52 |
+
self.handle_error(diagnostics_relay_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client))
|
| 53 |
+
|
| 54 |
+
def __dealloc__(self):
|
| 55 |
+
cdef diagnostics_relay_error_t err
|
| 56 |
+
if self._c_client is not NULL:
|
| 57 |
+
err = diagnostics_relay_client_free(self._c_client)
|
| 58 |
+
self.handle_error(err)
|
| 59 |
+
|
| 60 |
+
cdef inline BaseError _error(self, int16_t ret):
|
| 61 |
+
return DiagnosticsRelayError(ret)
|
| 62 |
+
|
| 63 |
+
cpdef goodbye(self):
|
| 64 |
+
self.handle_error(diagnostics_relay_goodbye(self._c_client))
|
| 65 |
+
|
| 66 |
+
cpdef sleep(self):
|
| 67 |
+
self.handle_error(diagnostics_relay_sleep(self._c_client))
|
| 68 |
+
|
| 69 |
+
cpdef restart(self, diagnostics_relay_action_t flags):
|
| 70 |
+
self.handle_error(diagnostics_relay_restart(self._c_client, flags))
|
| 71 |
+
|
| 72 |
+
cpdef shutdown(self, diagnostics_relay_action_t flags):
|
| 73 |
+
self.handle_error(diagnostics_relay_shutdown(self._c_client, flags))
|
| 74 |
+
|
| 75 |
+
cpdef plist.Node request_diagnostics(self, bytes type):
|
| 76 |
+
cdef:
|
| 77 |
+
plist.plist_t c_node = NULL
|
| 78 |
+
diagnostics_relay_error_t err
|
| 79 |
+
err = diagnostics_relay_request_diagnostics(self._c_client, type, &c_node)
|
| 80 |
+
try:
|
| 81 |
+
self.handle_error(err)
|
| 82 |
+
return plist.plist_t_to_node(c_node)
|
| 83 |
+
except BaseError, e:
|
| 84 |
+
if c_node != NULL:
|
| 85 |
+
plist.plist_free(c_node)
|
| 86 |
+
raise
|
| 87 |
+
|
| 88 |
+
cpdef plist.Node query_mobilegestalt(self, plist.Node keys = None):
|
| 89 |
+
cdef:
|
| 90 |
+
plist.plist_t c_node = NULL
|
| 91 |
+
diagnostics_relay_error_t err
|
| 92 |
+
plist.plist_t keys_c_node = NULL
|
| 93 |
+
if keys is not None:
|
| 94 |
+
keys_c_node = keys._c_node
|
| 95 |
+
err = diagnostics_relay_query_mobilegestalt(self._c_client, keys_c_node, &c_node)
|
| 96 |
+
try:
|
| 97 |
+
self.handle_error(err)
|
| 98 |
+
return plist.plist_t_to_node(c_node)
|
| 99 |
+
except BaseError, e:
|
| 100 |
+
if c_node != NULL:
|
| 101 |
+
plist.plist_free(c_node)
|
| 102 |
+
raise
|
| 103 |
+
|
| 104 |
+
cpdef plist.Node query_ioregistry_entry(self, bytes name, bytes class_name):
|
| 105 |
+
cdef:
|
| 106 |
+
plist.plist_t c_node = NULL
|
| 107 |
+
diagnostics_relay_error_t err
|
| 108 |
+
err = diagnostics_relay_query_ioregistry_entry(self._c_client, name, class_name, &c_node)
|
| 109 |
+
try:
|
| 110 |
+
self.handle_error(err)
|
| 111 |
+
return plist.plist_t_to_node(c_node)
|
| 112 |
+
except BaseError, e:
|
| 113 |
+
if c_node != NULL:
|
| 114 |
+
plist.plist_free(c_node)
|
| 115 |
+
raise
|
| 116 |
+
|
| 117 |
+
cpdef plist.Node query_ioregistry_plane(self, bytes plane = None):
|
| 118 |
+
cdef:
|
| 119 |
+
plist.plist_t c_node = NULL
|
| 120 |
+
diagnostics_relay_error_t err
|
| 121 |
+
err = diagnostics_relay_query_ioregistry_plane(self._c_client, plane, &c_node)
|
| 122 |
+
try:
|
| 123 |
+
self.handle_error(err)
|
| 124 |
+
return plist.plist_t_to_node(c_node)
|
| 125 |
+
except BaseError, e:
|
| 126 |
+
if c_node != NULL:
|
| 127 |
+
plist.plist_free(c_node)
|
| 128 |
+
raise
|
download.c
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* download.c
|
| 3 |
+
* file download helper functions
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2012-2013 Martin Szulecki. All Rights Reserved.
|
| 7 |
+
*
|
| 8 |
+
* This library is free software; you can redistribute it and/or
|
| 9 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 10 |
+
* License as published by the Free Software Foundation; either
|
| 11 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 12 |
+
*
|
| 13 |
+
* This library is distributed in the hope that it will be useful,
|
| 14 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 15 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 16 |
+
* Lesser General Public License for more details.
|
| 17 |
+
*
|
| 18 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 19 |
+
* License along with this library; if not, write to the Free Software
|
| 20 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 21 |
+
*/
|
| 22 |
+
#include <stdint.h>
|
| 23 |
+
#include <stdlib.h>
|
| 24 |
+
#include <string.h>
|
| 25 |
+
#include <curl/curl.h>
|
| 26 |
+
|
| 27 |
+
#include "download.h"
|
| 28 |
+
#include "common.h"
|
| 29 |
+
|
| 30 |
+
typedef struct {
|
| 31 |
+
int length;
|
| 32 |
+
char* content;
|
| 33 |
+
} curl_response;
|
| 34 |
+
|
| 35 |
+
static size_t download_write_buffer_callback(char* data, size_t size, size_t nmemb, curl_response* response) {
|
| 36 |
+
size_t total = size * nmemb;
|
| 37 |
+
if (total != 0) {
|
| 38 |
+
response->content = realloc(response->content, response->length + total + 1);
|
| 39 |
+
memcpy(response->content + response->length, data, total);
|
| 40 |
+
response->content[response->length + total] = '\0';
|
| 41 |
+
response->length += total;
|
| 42 |
+
}
|
| 43 |
+
return total;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
int download_to_buffer(const char* url, char** buf, uint32_t* length)
|
| 47 |
+
{
|
| 48 |
+
int res = 0;
|
| 49 |
+
CURL* handle = curl_easy_init();
|
| 50 |
+
if (handle == NULL) {
|
| 51 |
+
error("ERROR: could not initialize CURL\n");
|
| 52 |
+
return -1;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
curl_response response;
|
| 56 |
+
response.length = 0;
|
| 57 |
+
response.content = malloc(1);
|
| 58 |
+
response.content[0] = '\0';
|
| 59 |
+
|
| 60 |
+
if (idevicerestore_debug)
|
| 61 |
+
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
|
| 62 |
+
|
| 63 |
+
/* disable SSL verification to allow download from untrusted https locations */
|
| 64 |
+
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
|
| 65 |
+
|
| 66 |
+
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&download_write_buffer_callback);
|
| 67 |
+
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);
|
| 68 |
+
if (strncmp(url, "https://api.ipsw.me/", 20) == 0) {
|
| 69 |
+
curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING " idevicerestore/" PACKAGE_VERSION);
|
| 70 |
+
} else {
|
| 71 |
+
curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING);
|
| 72 |
+
}
|
| 73 |
+
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
|
| 74 |
+
curl_easy_setopt(handle, CURLOPT_URL, url);
|
| 75 |
+
|
| 76 |
+
curl_easy_perform(handle);
|
| 77 |
+
curl_easy_cleanup(handle);
|
| 78 |
+
|
| 79 |
+
if (response.length > 0) {
|
| 80 |
+
*length = response.length;
|
| 81 |
+
*buf = response.content;
|
| 82 |
+
} else {
|
| 83 |
+
res = -1;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
return res;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
static int lastprogress = 0;
|
| 90 |
+
|
| 91 |
+
static int download_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
|
| 92 |
+
{
|
| 93 |
+
double p = (dlnow / dltotal) * 100;
|
| 94 |
+
|
| 95 |
+
if (p < 100.0) {
|
| 96 |
+
if ((int)p > lastprogress) {
|
| 97 |
+
info("downloading: %d%%\n", (int)p);
|
| 98 |
+
lastprogress = (int)p;
|
| 99 |
+
}
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
return 0;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
int download_to_file(const char* url, const char* filename, int enable_progress)
|
| 106 |
+
{
|
| 107 |
+
int res = 0;
|
| 108 |
+
CURL* handle = curl_easy_init();
|
| 109 |
+
if (handle == NULL) {
|
| 110 |
+
error("ERROR: could not initialize CURL\n");
|
| 111 |
+
return -1;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
FILE* f = fopen(filename, "wb");
|
| 115 |
+
if (!f) {
|
| 116 |
+
error("ERROR: cannot open '%s' for writing\n", filename);
|
| 117 |
+
return -1;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
lastprogress = 0;
|
| 121 |
+
|
| 122 |
+
if (idevicerestore_debug)
|
| 123 |
+
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
|
| 124 |
+
|
| 125 |
+
/* disable SSL verification to allow download from untrusted https locations */
|
| 126 |
+
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
|
| 127 |
+
|
| 128 |
+
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL);
|
| 129 |
+
curl_easy_setopt(handle, CURLOPT_WRITEDATA, f);
|
| 130 |
+
|
| 131 |
+
if (enable_progress > 0)
|
| 132 |
+
curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&download_progress);
|
| 133 |
+
|
| 134 |
+
curl_easy_setopt(handle, CURLOPT_NOPROGRESS, enable_progress > 0 ? 0: 1);
|
| 135 |
+
curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING);
|
| 136 |
+
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
|
| 137 |
+
curl_easy_setopt(handle, CURLOPT_URL, url);
|
| 138 |
+
|
| 139 |
+
curl_easy_perform(handle);
|
| 140 |
+
curl_easy_cleanup(handle);
|
| 141 |
+
|
| 142 |
+
#ifdef WIN32
|
| 143 |
+
fflush(f);
|
| 144 |
+
uint64_t sz = _lseeki64(fileno(f), 0, SEEK_CUR);
|
| 145 |
+
#else
|
| 146 |
+
off_t sz = ftello(f);
|
| 147 |
+
#endif
|
| 148 |
+
fclose(f);
|
| 149 |
+
|
| 150 |
+
if ((sz == 0) || ((int64_t)sz == (int64_t)-1)) {
|
| 151 |
+
res = -1;
|
| 152 |
+
remove(filename);
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
return res;
|
| 156 |
+
}
|
download.h
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* download.h
|
| 3 |
+
* file download helper functions (header file)
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012 Martin Szulecki. All Rights Reserved.
|
| 6 |
+
* Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
|
| 7 |
+
*
|
| 8 |
+
* This library is free software; you can redistribute it and/or
|
| 9 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 10 |
+
* License as published by the Free Software Foundation; either
|
| 11 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 12 |
+
*
|
| 13 |
+
* This library is distributed in the hope that it will be useful,
|
| 14 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 15 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 16 |
+
* Lesser General Public License for more details.
|
| 17 |
+
*
|
| 18 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 19 |
+
* License along with this library; if not, write to the Free Software
|
| 20 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 21 |
+
*/
|
| 22 |
+
#ifndef IDEVICERESTORE_DOWNLOAD_H
|
| 23 |
+
#define IDEVICERESTORE_DOWNLOAD_H
|
| 24 |
+
|
| 25 |
+
#ifdef __cplusplus
|
| 26 |
+
extern "C" {
|
| 27 |
+
#endif
|
| 28 |
+
|
| 29 |
+
#include <stdint.h>
|
| 30 |
+
|
| 31 |
+
int download_to_buffer(const char* url, char** buf, uint32_t* length);
|
| 32 |
+
int download_to_file(const char* url, const char* filename, int enable_progress);
|
| 33 |
+
|
| 34 |
+
#ifdef __cplusplus
|
| 35 |
+
}
|
| 36 |
+
#endif
|
| 37 |
+
|
| 38 |
+
#endif
|
doxygen.cfg.in
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
endianness.h
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef ENDIANNESS_H
|
| 2 |
+
#define ENDIANNESS_H
|
| 3 |
+
|
| 4 |
+
#ifndef __LITTLE_ENDIAN
|
| 5 |
+
#define __LITTLE_ENDIAN 1234
|
| 6 |
+
#endif
|
| 7 |
+
|
| 8 |
+
#ifndef __BIG_ENDIAN
|
| 9 |
+
#define __BIG_ENDIAN 4321
|
| 10 |
+
#endif
|
| 11 |
+
|
| 12 |
+
#ifndef __BYTE_ORDER
|
| 13 |
+
#ifdef __LITTLE_ENDIAN__
|
| 14 |
+
#define __BYTE_ORDER __LITTLE_ENDIAN
|
| 15 |
+
#else
|
| 16 |
+
#ifdef __BIG_ENDIAN__
|
| 17 |
+
#define __BYTE_ORDER __BIG_ENDIAN
|
| 18 |
+
#endif
|
| 19 |
+
#endif
|
| 20 |
+
#endif
|
| 21 |
+
|
| 22 |
+
#ifndef be16toh
|
| 23 |
+
#if __BYTE_ORDER == __BIG_ENDIAN
|
| 24 |
+
#define be16toh(x) (x)
|
| 25 |
+
#else
|
| 26 |
+
#define be16toh(x) ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
|
| 27 |
+
#endif
|
| 28 |
+
#endif
|
| 29 |
+
|
| 30 |
+
#ifndef htobe16
|
| 31 |
+
#define htobe16 be16toh
|
| 32 |
+
#endif
|
| 33 |
+
|
| 34 |
+
#ifndef le16toh
|
| 35 |
+
#if __BYTE_ORDER == __BIG_ENDIAN
|
| 36 |
+
#define le16toh(x) ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
|
| 37 |
+
#else
|
| 38 |
+
#define le16toh(x) (x)
|
| 39 |
+
#endif
|
| 40 |
+
#endif
|
| 41 |
+
|
| 42 |
+
#ifndef htole16
|
| 43 |
+
#define htole16 le16toh
|
| 44 |
+
#endif
|
| 45 |
+
|
| 46 |
+
#ifndef __bswap_32
|
| 47 |
+
#define __bswap_32(x) ((((x) & 0xFF000000) >> 24) \
|
| 48 |
+
| (((x) & 0x00FF0000) >> 8) \
|
| 49 |
+
| (((x) & 0x0000FF00) << 8) \
|
| 50 |
+
| (((x) & 0x000000FF) << 24))
|
| 51 |
+
#endif
|
| 52 |
+
|
| 53 |
+
#ifndef be32toh
|
| 54 |
+
#if __BYTE_ORDER == __BIG_ENDIAN
|
| 55 |
+
#define be32toh(x) (x)
|
| 56 |
+
#else
|
| 57 |
+
#define be32toh(x) __bswap_32(x)
|
| 58 |
+
#endif
|
| 59 |
+
#endif
|
| 60 |
+
|
| 61 |
+
#ifndef htobe32
|
| 62 |
+
#define htobe32 be32toh
|
| 63 |
+
#endif
|
| 64 |
+
|
| 65 |
+
#ifndef le32toh
|
| 66 |
+
#if __BYTE_ORDER == __BIG_ENDIAN
|
| 67 |
+
#define le32toh(x) __bswap_32(x)
|
| 68 |
+
#else
|
| 69 |
+
#define le32toh(x) (x)
|
| 70 |
+
#endif
|
| 71 |
+
#endif
|
| 72 |
+
|
| 73 |
+
#ifndef htole32
|
| 74 |
+
#define htole32 le32toh
|
| 75 |
+
#endif
|
| 76 |
+
|
| 77 |
+
#ifndef __bswap_64
|
| 78 |
+
#define __bswap_64(x) ((((x) & 0xFF00000000000000ull) >> 56) \
|
| 79 |
+
| (((x) & 0x00FF000000000000ull) >> 40) \
|
| 80 |
+
| (((x) & 0x0000FF0000000000ull) >> 24) \
|
| 81 |
+
| (((x) & 0x000000FF00000000ull) >> 8) \
|
| 82 |
+
| (((x) & 0x00000000FF000000ull) << 8) \
|
| 83 |
+
| (((x) & 0x0000000000FF0000ull) << 24) \
|
| 84 |
+
| (((x) & 0x000000000000FF00ull) << 40) \
|
| 85 |
+
| (((x) & 0x00000000000000FFull) << 56))
|
| 86 |
+
#endif
|
| 87 |
+
|
| 88 |
+
#ifndef htobe64
|
| 89 |
+
#if __BYTE_ORDER == __BIG_ENDIAN
|
| 90 |
+
#define htobe64(x) (x)
|
| 91 |
+
#else
|
| 92 |
+
#define htobe64(x) __bswap_64(x)
|
| 93 |
+
#endif
|
| 94 |
+
#endif
|
| 95 |
+
|
| 96 |
+
#ifndef be64toh
|
| 97 |
+
#define be64toh htobe64
|
| 98 |
+
#endif
|
| 99 |
+
|
| 100 |
+
#ifndef le64toh
|
| 101 |
+
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
| 102 |
+
#define le64toh(x) (x)
|
| 103 |
+
#else
|
| 104 |
+
#define le64toh(x) __bswap_64(x)
|
| 105 |
+
#endif
|
| 106 |
+
#endif
|
| 107 |
+
|
| 108 |
+
#ifndef htole64
|
| 109 |
+
#define htole64 le64toh
|
| 110 |
+
#endif
|
| 111 |
+
|
| 112 |
+
#if (defined(__BIG_ENDIAN__) \
|
| 113 |
+
&& !defined(__FLOAT_WORD_ORDER__)) \
|
| 114 |
+
|| (defined(__FLOAT_WORD_ORDER__) \
|
| 115 |
+
&& __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
|
| 116 |
+
#define float_bswap64(x) __bswap_64(x)
|
| 117 |
+
#define float_bswap32(x) __bswap_32(x)
|
| 118 |
+
#else
|
| 119 |
+
#define float_bswap64(x) (x)
|
| 120 |
+
#define float_bswap32(x) (x)
|
| 121 |
+
#endif
|
| 122 |
+
|
| 123 |
+
#endif /* ENDIANNESS_H */
|
fdr.c
ADDED
|
@@ -0,0 +1,629 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* fdr.c
|
| 3 |
+
* Connection proxy service used by FDR
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2014 BALATON Zoltan. All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#include <sys/types.h>
|
| 23 |
+
#include <sys/stat.h>
|
| 24 |
+
#include <errno.h>
|
| 25 |
+
#include <fcntl.h>
|
| 26 |
+
#include <stdio.h>
|
| 27 |
+
#include <stdlib.h>
|
| 28 |
+
#include <string.h>
|
| 29 |
+
#include <unistd.h>
|
| 30 |
+
#include <libimobiledevice/libimobiledevice.h>
|
| 31 |
+
|
| 32 |
+
#include "socket.h" /* from libimobiledevice/common */
|
| 33 |
+
#include "common.h"
|
| 34 |
+
#include "idevicerestore.h"
|
| 35 |
+
#include "fdr.h"
|
| 36 |
+
#include <endianness.h> /* from libimobiledevice */
|
| 37 |
+
|
| 38 |
+
#define CTRL_PORT 0x43a /*1082*/
|
| 39 |
+
#define CTRLCMD "BeginCtrl"
|
| 40 |
+
#define HELLOCTRLCMD "HelloCtrl"
|
| 41 |
+
#define HELLOCMD "HelloConn"
|
| 42 |
+
|
| 43 |
+
#define FDR_SYNC_MSG 0x1
|
| 44 |
+
#define FDR_PROXY_MSG 0x105
|
| 45 |
+
#define FDR_PLIST_MSG 0xbbaa
|
| 46 |
+
|
| 47 |
+
static uint64_t conn_port;
|
| 48 |
+
static int ctrlprotoversion = 2;
|
| 49 |
+
static int serial;
|
| 50 |
+
|
| 51 |
+
static int fdr_receive_plist(fdr_client_t fdr, plist_t* data);
|
| 52 |
+
static int fdr_send_plist(fdr_client_t fdr, plist_t data);
|
| 53 |
+
static int fdr_ctrl_handshake(fdr_client_t fdr);
|
| 54 |
+
static int fdr_sync_handshake(fdr_client_t fdr);
|
| 55 |
+
static int fdr_handle_sync_cmd(fdr_client_t fdr);
|
| 56 |
+
static int fdr_handle_plist_cmd(fdr_client_t fdr);
|
| 57 |
+
static int fdr_handle_proxy_cmd(fdr_client_t fdr);
|
| 58 |
+
|
| 59 |
+
int fdr_connect(idevice_t device, fdr_type_t type, fdr_client_t* fdr)
|
| 60 |
+
{
|
| 61 |
+
int res = -1, i = 0;
|
| 62 |
+
int attempts = 10;
|
| 63 |
+
idevice_connection_t connection = NULL;
|
| 64 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 65 |
+
uint16_t port = (type == FDR_CONN ? conn_port : CTRL_PORT);
|
| 66 |
+
|
| 67 |
+
*fdr = NULL;
|
| 68 |
+
|
| 69 |
+
debug("Connecting to FDR client at port %u\n", port);
|
| 70 |
+
|
| 71 |
+
for (i = 1; i <= attempts; i++) {
|
| 72 |
+
device_error = idevice_connect(device, port, &connection);
|
| 73 |
+
if (device_error == IDEVICE_E_SUCCESS) {
|
| 74 |
+
break;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
if (i >= attempts) {
|
| 78 |
+
error("ERROR: Unable to connect to FDR client (%d)\n", device_error);
|
| 79 |
+
return -1;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
sleep(2);
|
| 83 |
+
debug("Retrying connection...\n");
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
fdr_client_t fdr_loc = calloc(1, sizeof(struct fdr_client));
|
| 87 |
+
if (!fdr_loc) {
|
| 88 |
+
error("ERROR: Unable to allocate memory\n");
|
| 89 |
+
return -1;
|
| 90 |
+
}
|
| 91 |
+
fdr_loc->connection = connection;
|
| 92 |
+
fdr_loc->device = device;
|
| 93 |
+
fdr_loc->type = type;
|
| 94 |
+
|
| 95 |
+
/* Do handshake */
|
| 96 |
+
if (type == FDR_CTRL)
|
| 97 |
+
res = fdr_ctrl_handshake(fdr_loc);
|
| 98 |
+
else if (type == FDR_CONN)
|
| 99 |
+
res = fdr_sync_handshake(fdr_loc);
|
| 100 |
+
|
| 101 |
+
if (res) {
|
| 102 |
+
fdr_free(fdr_loc);
|
| 103 |
+
return -1;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
*fdr = fdr_loc;
|
| 107 |
+
|
| 108 |
+
return 0;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
void fdr_disconnect(fdr_client_t fdr)
|
| 112 |
+
{
|
| 113 |
+
if (!fdr)
|
| 114 |
+
return;
|
| 115 |
+
|
| 116 |
+
if (fdr->connection) {
|
| 117 |
+
idevice_connection_t conn = fdr->connection;
|
| 118 |
+
fdr->connection = NULL;
|
| 119 |
+
idevice_disconnect(conn);
|
| 120 |
+
}
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
void fdr_free(fdr_client_t fdr)
|
| 124 |
+
{
|
| 125 |
+
if (!fdr)
|
| 126 |
+
return;
|
| 127 |
+
|
| 128 |
+
fdr_disconnect(fdr);
|
| 129 |
+
|
| 130 |
+
free(fdr);
|
| 131 |
+
fdr = NULL;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
int fdr_poll_and_handle_message(fdr_client_t fdr)
|
| 135 |
+
{
|
| 136 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 137 |
+
uint32_t bytes = 0;
|
| 138 |
+
uint16_t cmd;
|
| 139 |
+
|
| 140 |
+
if (!fdr) {
|
| 141 |
+
error("ERROR: Invalid FDR client\n");
|
| 142 |
+
return -1;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
device_error = idevice_connection_receive_timeout(fdr->connection, (char *)&cmd, sizeof(cmd), &bytes, 20000);
|
| 146 |
+
#ifdef HAVE_IDEVICE_E_TIMEOUT
|
| 147 |
+
if (device_error == IDEVICE_E_TIMEOUT || (device_error == IDEVICE_E_SUCCESS && bytes != sizeof(cmd)))
|
| 148 |
+
#else
|
| 149 |
+
if (device_error == IDEVICE_E_SUCCESS && bytes != sizeof(cmd))
|
| 150 |
+
#endif
|
| 151 |
+
{
|
| 152 |
+
debug("FDR %p timeout waiting for command\n", fdr);
|
| 153 |
+
return 0;
|
| 154 |
+
}
|
| 155 |
+
else if (device_error != IDEVICE_E_SUCCESS) {
|
| 156 |
+
if (fdr->connection) {
|
| 157 |
+
error("ERROR: Unable to receive message from FDR %p (%d). %u/%u bytes\n", fdr, device_error, bytes, (uint32_t)sizeof(cmd));
|
| 158 |
+
}
|
| 159 |
+
return -1;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
if (cmd == FDR_SYNC_MSG) {
|
| 163 |
+
debug("FDR %p got sync message\n", fdr);
|
| 164 |
+
return fdr_handle_sync_cmd(fdr);
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
if (cmd == FDR_PROXY_MSG) {
|
| 168 |
+
debug("FDR %p got proxy message\n", fdr);
|
| 169 |
+
return fdr_handle_proxy_cmd(fdr);
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
if (cmd == FDR_PLIST_MSG) {
|
| 173 |
+
debug("FDR %p got plist message\n", fdr);
|
| 174 |
+
return fdr_handle_plist_cmd(fdr);
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
error("WARNING: FDR %p received unknown packet %#x of size %u\n", fdr, cmd, bytes);
|
| 178 |
+
return 0;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
void *fdr_listener_thread(void *cdata)
|
| 182 |
+
{
|
| 183 |
+
fdr_client_t fdr = cdata;
|
| 184 |
+
int res;
|
| 185 |
+
|
| 186 |
+
while (fdr && fdr->connection) {
|
| 187 |
+
debug("FDR %p waiting for message...\n", fdr);
|
| 188 |
+
res = fdr_poll_and_handle_message(fdr);
|
| 189 |
+
if (fdr->type == FDR_CTRL && res >= 0)
|
| 190 |
+
continue; // main thread should always retry
|
| 191 |
+
if (res != 0)
|
| 192 |
+
break;
|
| 193 |
+
}
|
| 194 |
+
debug("FDR %p terminating...\n", fdr);
|
| 195 |
+
fdr_free(fdr);
|
| 196 |
+
return (void *)(intptr_t)res;
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
static int fdr_receive_plist(fdr_client_t fdr, plist_t* data)
|
| 200 |
+
{
|
| 201 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 202 |
+
uint32_t len, bytes = 0;
|
| 203 |
+
char* buf = NULL;
|
| 204 |
+
|
| 205 |
+
device_error = idevice_connection_receive(fdr->connection, (char*)&len, sizeof(len), &bytes);
|
| 206 |
+
if (device_error != IDEVICE_E_SUCCESS) {
|
| 207 |
+
error("ERROR: Unable to receive packet length from FDR (%d)\n", device_error);
|
| 208 |
+
return -1;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
buf = calloc(1, len);
|
| 212 |
+
if (!buf) {
|
| 213 |
+
error("ERROR: Unable to allocate memory for FDR receive buffer\n");
|
| 214 |
+
return -1;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
device_error = idevice_connection_receive(fdr->connection, buf, len, &bytes);
|
| 218 |
+
if (device_error != IDEVICE_E_SUCCESS) {
|
| 219 |
+
error("ERROR: Unable to receive data from FDR\n");
|
| 220 |
+
free(buf);
|
| 221 |
+
return -1;
|
| 222 |
+
}
|
| 223 |
+
plist_from_bin(buf, bytes, data);
|
| 224 |
+
free(buf);
|
| 225 |
+
|
| 226 |
+
debug("FDR Received %d bytes\n", bytes);
|
| 227 |
+
|
| 228 |
+
return 0;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
static int fdr_send_plist(fdr_client_t fdr, plist_t data)
|
| 232 |
+
{
|
| 233 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 234 |
+
char *buf = NULL;
|
| 235 |
+
uint32_t len = 0, bytes = 0;
|
| 236 |
+
|
| 237 |
+
if (!data)
|
| 238 |
+
return -1;
|
| 239 |
+
|
| 240 |
+
plist_to_bin(data, &buf, &len);
|
| 241 |
+
if (!buf)
|
| 242 |
+
return -1;
|
| 243 |
+
|
| 244 |
+
debug("FDR sending %d bytes:\n", len);
|
| 245 |
+
if (idevicerestore_debug)
|
| 246 |
+
debug_plist(data);
|
| 247 |
+
device_error = idevice_connection_send(fdr->connection, (char *)&len, sizeof(len), &bytes);
|
| 248 |
+
if (device_error != IDEVICE_E_SUCCESS || bytes != sizeof(len)) {
|
| 249 |
+
error("ERROR: FDR unable to send data length. (%d) Sent %u of %u bytes.\n",
|
| 250 |
+
device_error, bytes, (uint32_t)sizeof(len));
|
| 251 |
+
free(buf);
|
| 252 |
+
return -1;
|
| 253 |
+
}
|
| 254 |
+
device_error = idevice_connection_send(fdr->connection, buf, len, &bytes);
|
| 255 |
+
free(buf);
|
| 256 |
+
if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
|
| 257 |
+
error("ERROR: FDR unable to send data (%d). Sent %u of %u bytes.\n",
|
| 258 |
+
device_error, bytes, len);
|
| 259 |
+
return -1;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
debug("FDR Sent %d bytes\n", bytes);
|
| 263 |
+
return 0;
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
static int fdr_ctrl_handshake(fdr_client_t fdr)
|
| 267 |
+
{
|
| 268 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 269 |
+
uint32_t bytes = 0, len = sizeof(CTRLCMD);
|
| 270 |
+
plist_t dict, node;
|
| 271 |
+
int res;
|
| 272 |
+
|
| 273 |
+
debug("About to do ctrl handshake\n");
|
| 274 |
+
|
| 275 |
+
ctrlprotoversion = 2;
|
| 276 |
+
|
| 277 |
+
device_error = idevice_connection_send(fdr->connection, CTRLCMD, len, &bytes);
|
| 278 |
+
if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
|
| 279 |
+
debug("Hmm... lookes like the device doesn't like the newer protocol, using the old one\n");
|
| 280 |
+
ctrlprotoversion = 1;
|
| 281 |
+
len = sizeof(HELLOCTRLCMD);
|
| 282 |
+
device_error = idevice_connection_send(fdr->connection, HELLOCTRLCMD, len, &bytes);
|
| 283 |
+
if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
|
| 284 |
+
error("ERROR: FDR unable to send BeginCtrl. Sent %u of %u bytes.\n", bytes, len);
|
| 285 |
+
return -1;
|
| 286 |
+
}
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
if (ctrlprotoversion == 2) {
|
| 290 |
+
dict = plist_new_dict();
|
| 291 |
+
plist_dict_set_item(dict, "Command", plist_new_string(CTRLCMD));
|
| 292 |
+
plist_dict_set_item(dict, "CtrlProtoVersion", plist_new_uint(ctrlprotoversion));
|
| 293 |
+
res = fdr_send_plist(fdr, dict);
|
| 294 |
+
plist_free(dict);
|
| 295 |
+
if (res) {
|
| 296 |
+
error("ERROR: FDR could not send Begin command.\n");
|
| 297 |
+
return -1;
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
if (fdr_receive_plist(fdr, &dict)) {
|
| 301 |
+
error("ERROR: FDR did not get Begin command reply.\n");
|
| 302 |
+
return -1;
|
| 303 |
+
}
|
| 304 |
+
if (idevicerestore_debug)
|
| 305 |
+
debug_plist(dict);
|
| 306 |
+
node = plist_dict_get_item(dict, "ConnPort");
|
| 307 |
+
if (node && plist_get_node_type(node) == PLIST_UINT) {
|
| 308 |
+
plist_get_uint_val(node, &conn_port);
|
| 309 |
+
} else {
|
| 310 |
+
error("ERROR: Could not get FDR ConnPort value\n");
|
| 311 |
+
return -1;
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
plist_free(dict);
|
| 315 |
+
} else {
|
| 316 |
+
char buf[16];
|
| 317 |
+
uint16_t cport = 0;
|
| 318 |
+
|
| 319 |
+
memset(buf, '\0', sizeof(buf));
|
| 320 |
+
|
| 321 |
+
bytes = 0;
|
| 322 |
+
device_error = idevice_connection_receive(fdr->connection, buf, 10, &bytes);
|
| 323 |
+
if (device_error != IDEVICE_E_SUCCESS) {
|
| 324 |
+
error("ERROR: Could not receive reply to HelloCtrl command\n");
|
| 325 |
+
return -1;
|
| 326 |
+
}
|
| 327 |
+
if (memcmp(buf, "HelloCtrl", 10) != 0) {
|
| 328 |
+
buf[9] = '\0';
|
| 329 |
+
error("ERROR: Did not receive HelloCtrl as reply, but %s\n", buf);
|
| 330 |
+
return -1;
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
bytes = 0;
|
| 334 |
+
device_error = idevice_connection_receive(fdr->connection, (char*)&cport, 2, &bytes);
|
| 335 |
+
if (device_error != IDEVICE_E_SUCCESS) {
|
| 336 |
+
error("ERROR: Failed to receive conn port\n");
|
| 337 |
+
return -1;
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
conn_port = le16toh(cport);
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
debug("Ctrl handshake done (ConnPort = %" PRIu64 ")\n", (uint64_t)conn_port);
|
| 344 |
+
|
| 345 |
+
return 0;
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
static int fdr_sync_handshake(fdr_client_t fdr)
|
| 349 |
+
{
|
| 350 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 351 |
+
uint32_t bytes = 0, len = sizeof(HELLOCMD);
|
| 352 |
+
plist_t reply;
|
| 353 |
+
|
| 354 |
+
device_error = idevice_connection_send(fdr->connection, HELLOCMD, len, &bytes);
|
| 355 |
+
if (device_error != IDEVICE_E_SUCCESS || bytes != len) {
|
| 356 |
+
error("ERROR: FDR unable to send Hello. Sent %u of %u bytes.\n", bytes, len);
|
| 357 |
+
return -1;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
if (ctrlprotoversion == 2) {
|
| 361 |
+
if (fdr_receive_plist(fdr, &reply)) {
|
| 362 |
+
error("ERROR: FDR did not get HelloConn reply.\n");
|
| 363 |
+
return -1;
|
| 364 |
+
}
|
| 365 |
+
char* identifier = NULL;
|
| 366 |
+
char* cmd = NULL;
|
| 367 |
+
plist_t node = NULL;
|
| 368 |
+
node = plist_dict_get_item(reply, "Command");
|
| 369 |
+
if (node) {
|
| 370 |
+
plist_get_string_val(node, &cmd);
|
| 371 |
+
}
|
| 372 |
+
node = plist_dict_get_item(reply, "Identifier");
|
| 373 |
+
if (node) {
|
| 374 |
+
plist_get_string_val(node, &identifier);
|
| 375 |
+
}
|
| 376 |
+
plist_free(reply);
|
| 377 |
+
|
| 378 |
+
if (!cmd || (strcmp(cmd, "HelloConn") != 0)) {
|
| 379 |
+
if (cmd) {
|
| 380 |
+
free(cmd);
|
| 381 |
+
}
|
| 382 |
+
if (identifier) {
|
| 383 |
+
free(identifier);
|
| 384 |
+
}
|
| 385 |
+
error("ERROR: Did not receive HelloConn reply...\n");
|
| 386 |
+
return -1;
|
| 387 |
+
}
|
| 388 |
+
free(cmd);
|
| 389 |
+
|
| 390 |
+
if (identifier) {
|
| 391 |
+
debug("Got device identifier %s\n", identifier);
|
| 392 |
+
free(identifier);
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
} else {
|
| 396 |
+
char buf[16];
|
| 397 |
+
memset(buf, '\0', sizeof(buf));
|
| 398 |
+
bytes = 0;
|
| 399 |
+
device_error = idevice_connection_receive(fdr->connection, buf, 10, &bytes);
|
| 400 |
+
if (device_error != IDEVICE_E_SUCCESS) {
|
| 401 |
+
error("ERROR: Could not receive reply to HelloConn command\n");
|
| 402 |
+
return -1;
|
| 403 |
+
}
|
| 404 |
+
if (memcmp(buf, "HelloConn", 10) != 0) {
|
| 405 |
+
buf[9] = '\0';
|
| 406 |
+
error("ERROR: Did not receive HelloConn as reply, but %s\n", buf);
|
| 407 |
+
return -1;
|
| 408 |
+
}
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
return 0;
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
static int fdr_handle_sync_cmd(fdr_client_t fdr_ctrl)
|
| 415 |
+
{
|
| 416 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 417 |
+
fdr_client_t fdr;
|
| 418 |
+
thread_t fdr_thread = (thread_t)NULL;
|
| 419 |
+
int res = 0;
|
| 420 |
+
uint32_t bytes = 0;
|
| 421 |
+
char buf[4096];
|
| 422 |
+
|
| 423 |
+
device_error = idevice_connection_receive(fdr_ctrl->connection, buf, sizeof(buf), &bytes);
|
| 424 |
+
if (device_error != IDEVICE_E_SUCCESS || bytes != 2) {
|
| 425 |
+
error("ERROR: Unexpected data from FDR\n");
|
| 426 |
+
return -1;
|
| 427 |
+
}
|
| 428 |
+
/* Open a new connection and wait for messages on it */
|
| 429 |
+
if (fdr_connect(fdr_ctrl->device, FDR_CONN, &fdr)) {
|
| 430 |
+
error("ERROR: Failed to connect to FDR port\n");
|
| 431 |
+
return -1;
|
| 432 |
+
}
|
| 433 |
+
debug("FDR connected in reply to sync message, starting command thread\n");
|
| 434 |
+
res = thread_new(&fdr_thread, fdr_listener_thread, fdr);
|
| 435 |
+
if(res) {
|
| 436 |
+
error("ERROR: Failed to start FDR command thread\n");
|
| 437 |
+
fdr_free(fdr);
|
| 438 |
+
}
|
| 439 |
+
return res;
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
static int fdr_handle_plist_cmd(fdr_client_t fdr)
|
| 443 |
+
{
|
| 444 |
+
int res = 0;
|
| 445 |
+
plist_t dict;
|
| 446 |
+
|
| 447 |
+
if (fdr_receive_plist(fdr, &dict)) {
|
| 448 |
+
error("ERROR: FDR %p could not receive plist command.\n", fdr);
|
| 449 |
+
return -1;
|
| 450 |
+
}
|
| 451 |
+
plist_t node = plist_dict_get_item(dict, "Command");
|
| 452 |
+
if (!node || (plist_get_node_type(node) != PLIST_STRING)) {
|
| 453 |
+
error("ERROR: FDR %p Could not find Command in plist command\n", fdr);
|
| 454 |
+
plist_free(dict);
|
| 455 |
+
return -1;
|
| 456 |
+
}
|
| 457 |
+
char *command = NULL;
|
| 458 |
+
plist_get_string_val(node, &command);
|
| 459 |
+
plist_free(dict);
|
| 460 |
+
|
| 461 |
+
if (!command) {
|
| 462 |
+
info("FDR %p received empty plist command\n", fdr);
|
| 463 |
+
return -1;
|
| 464 |
+
}
|
| 465 |
+
|
| 466 |
+
if (!strcmp(command, "Ping")) {
|
| 467 |
+
dict = plist_new_dict();
|
| 468 |
+
plist_dict_set_item(dict, "Pong", plist_new_bool(1));
|
| 469 |
+
res = fdr_send_plist(fdr, dict);
|
| 470 |
+
plist_free(dict);
|
| 471 |
+
if (res) {
|
| 472 |
+
error("ERROR: FDR %p could not send Ping command reply.\n", fdr);
|
| 473 |
+
free(command);
|
| 474 |
+
return -1;
|
| 475 |
+
}
|
| 476 |
+
} else {
|
| 477 |
+
error("WARNING: FDR %p received unknown plist command: %s\n", fdr, command);
|
| 478 |
+
free(command);
|
| 479 |
+
return -1;
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
free(command);
|
| 483 |
+
/* FDR connection will be terminated remotely. Next receive will get nothing, error and terminate this worker thread. */
|
| 484 |
+
return 0;
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
static int fdr_handle_proxy_cmd(fdr_client_t fdr)
|
| 488 |
+
{
|
| 489 |
+
idevice_error_t device_error = IDEVICE_E_SUCCESS;
|
| 490 |
+
char *buf = NULL;
|
| 491 |
+
size_t bufsize = 1048576;
|
| 492 |
+
uint32_t sent = 0, bytes = 0;
|
| 493 |
+
char *host = NULL;
|
| 494 |
+
uint16_t port = 0;
|
| 495 |
+
|
| 496 |
+
buf = malloc(bufsize);
|
| 497 |
+
if (!buf) {
|
| 498 |
+
error("ERROR: %s: malloc failed\n", __func__);
|
| 499 |
+
return -1;
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
device_error = idevice_connection_receive(fdr->connection, buf, bufsize, &bytes);
|
| 503 |
+
if (device_error != IDEVICE_E_SUCCESS) {
|
| 504 |
+
free(buf);
|
| 505 |
+
error("ERROR: FDR %p failed to read data for proxy command\n", fdr);
|
| 506 |
+
return -1;
|
| 507 |
+
}
|
| 508 |
+
debug("Got proxy command with %u bytes\n", bytes);
|
| 509 |
+
|
| 510 |
+
/* Just return success here unconditionally because we don't know
|
| 511 |
+
* anything else and we will eventually abort on failure anyway */
|
| 512 |
+
uint16_t ack = 5;
|
| 513 |
+
device_error = idevice_connection_send(fdr->connection, (char *)&ack, sizeof(ack), &sent);
|
| 514 |
+
if (device_error != IDEVICE_E_SUCCESS || sent != sizeof(ack)) {
|
| 515 |
+
free(buf);
|
| 516 |
+
error("ERROR: FDR %p unable to send ack. Sent %u of %u bytes.\n",
|
| 517 |
+
fdr, sent, (uint32_t)sizeof(ack));
|
| 518 |
+
return -1;
|
| 519 |
+
}
|
| 520 |
+
|
| 521 |
+
if (bytes < 3) {
|
| 522 |
+
debug("FDR %p proxy command data too short, retrying\n", fdr);
|
| 523 |
+
return fdr_poll_and_handle_message(fdr);
|
| 524 |
+
}
|
| 525 |
+
|
| 526 |
+
/* ack command data too */
|
| 527 |
+
device_error = idevice_connection_send(fdr->connection, buf, bytes, &sent);
|
| 528 |
+
if (device_error != IDEVICE_E_SUCCESS || sent != bytes) {
|
| 529 |
+
free(buf);
|
| 530 |
+
error("ERROR: FDR %p unable to send data. Sent %u of %u bytes.\n",
|
| 531 |
+
fdr, sent, bytes);
|
| 532 |
+
return -1;
|
| 533 |
+
}
|
| 534 |
+
|
| 535 |
+
/* Now try to handle actual messages */
|
| 536 |
+
/* Connect: 0 3 hostlen <host> <port> */
|
| 537 |
+
if (buf[0] == 0 && buf[1] == 3) {
|
| 538 |
+
uint16_t *p = (uint16_t *)&buf[bytes - 2];
|
| 539 |
+
port = be16toh(*p);
|
| 540 |
+
buf[bytes - 2] = '\0';
|
| 541 |
+
host = strdup(&buf[3]);
|
| 542 |
+
debug("FDR %p Proxy connect request to %s:%u\n", fdr, host, port);
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
if (!host || !buf[2]) {
|
| 546 |
+
/* missing or zero length host name */
|
| 547 |
+
free(buf);
|
| 548 |
+
return 0;
|
| 549 |
+
}
|
| 550 |
+
|
| 551 |
+
/* else wait for messages and forward them */
|
| 552 |
+
int sockfd = socket_connect(host, port);
|
| 553 |
+
free(host);
|
| 554 |
+
if (sockfd < 0) {
|
| 555 |
+
free(buf);
|
| 556 |
+
error("ERROR: Failed to connect socket: %s\n", strerror(errno));
|
| 557 |
+
return -1;
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
int res = 0, bytes_ret;
|
| 561 |
+
while (1) {
|
| 562 |
+
bytes = 0;
|
| 563 |
+
device_error = idevice_connection_receive_timeout(fdr->connection, buf, bufsize, &bytes, 100);
|
| 564 |
+
#ifdef HAVE_IDEVICE_E_TIMEOUT
|
| 565 |
+
if (device_error == IDEVICE_E_TIMEOUT || (device_error == IDEVICE_E_SUCCESS && !bytes))
|
| 566 |
+
#else
|
| 567 |
+
if (device_error == IDEVICE_E_SUCCESS && !bytes)
|
| 568 |
+
#endif
|
| 569 |
+
{
|
| 570 |
+
//debug("WARNING: Timeout waiting for proxy payload. %p\n", fdr);
|
| 571 |
+
}
|
| 572 |
+
else if (device_error != IDEVICE_E_SUCCESS) {
|
| 573 |
+
error("ERROR: FDR %p Unable to receive proxy payload (%d)\n", fdr, device_error);
|
| 574 |
+
res = -1;
|
| 575 |
+
break;
|
| 576 |
+
}
|
| 577 |
+
if (bytes) {
|
| 578 |
+
debug("FDR %p got payload of %u bytes, now try to proxy it\n", fdr, bytes);
|
| 579 |
+
debug("Sending %u bytes of data\n", bytes);
|
| 580 |
+
sent = 0;
|
| 581 |
+
while (sent < bytes) {
|
| 582 |
+
int s = socket_send(sockfd, buf + sent, bytes - sent);
|
| 583 |
+
if (s < 0) {
|
| 584 |
+
break;
|
| 585 |
+
}
|
| 586 |
+
sent += s;
|
| 587 |
+
}
|
| 588 |
+
if (sent != bytes) {
|
| 589 |
+
error("ERROR: Sending proxy payload failed: %s. Sent %u of %u bytes. \n", strerror(errno), sent, bytes);
|
| 590 |
+
socket_close(sockfd);
|
| 591 |
+
res = -1;
|
| 592 |
+
break;
|
| 593 |
+
}
|
| 594 |
+
}
|
| 595 |
+
bytes_ret = socket_receive_timeout(sockfd, buf, bufsize, 0, 100);
|
| 596 |
+
if (bytes_ret < 0) {
|
| 597 |
+
if (errno)
|
| 598 |
+
error("ERROR: FDR %p receiving proxy payload failed: %s\n",
|
| 599 |
+
fdr, strerror(errno));
|
| 600 |
+
else
|
| 601 |
+
res = 1; /* close connection if no data with no error */
|
| 602 |
+
break;
|
| 603 |
+
}
|
| 604 |
+
|
| 605 |
+
bytes = bytes_ret;
|
| 606 |
+
if (bytes) {
|
| 607 |
+
debug("FDR %p Received %u bytes reply data,%s sending to device\n",
|
| 608 |
+
fdr, bytes, (bytes ? "" : " not"));
|
| 609 |
+
|
| 610 |
+
sent = 0;
|
| 611 |
+
while (sent < bytes) {
|
| 612 |
+
uint32_t s;
|
| 613 |
+
device_error = idevice_connection_send(fdr->connection, buf + sent, bytes - sent, &s);
|
| 614 |
+
if (device_error != IDEVICE_E_SUCCESS) {
|
| 615 |
+
break;
|
| 616 |
+
}
|
| 617 |
+
sent += s;
|
| 618 |
+
}
|
| 619 |
+
if (device_error != IDEVICE_E_SUCCESS || bytes != sent) {
|
| 620 |
+
error("ERROR: FDR %p unable to send data (%d). Sent %u of %u bytes.\n", fdr, device_error, sent, bytes);
|
| 621 |
+
res = -1;
|
| 622 |
+
break;
|
| 623 |
+
}
|
| 624 |
+
} else serial++;
|
| 625 |
+
}
|
| 626 |
+
socket_close(sockfd);
|
| 627 |
+
free(buf);
|
| 628 |
+
return res;
|
| 629 |
+
}
|
fdr.h
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* fdr.h
|
| 3 |
+
* Functions for handling FDR connections
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2014 BALATON Zoltan. All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifndef IDEVICERESTORE_FDR_H
|
| 23 |
+
#define IDEVICERESTORE_FDR_H
|
| 24 |
+
|
| 25 |
+
#ifdef __cplusplus
|
| 26 |
+
extern "C" {
|
| 27 |
+
#endif
|
| 28 |
+
|
| 29 |
+
#include <libimobiledevice/libimobiledevice.h>
|
| 30 |
+
#include "thread.h" /* from libimobiledevice/common */
|
| 31 |
+
|
| 32 |
+
typedef enum {
|
| 33 |
+
FDR_CTRL,
|
| 34 |
+
FDR_CONN
|
| 35 |
+
} fdr_type_t;
|
| 36 |
+
|
| 37 |
+
struct fdr_client {
|
| 38 |
+
idevice_connection_t connection;
|
| 39 |
+
idevice_t device;
|
| 40 |
+
fdr_type_t type;
|
| 41 |
+
};
|
| 42 |
+
typedef struct fdr_client *fdr_client_t;
|
| 43 |
+
|
| 44 |
+
int fdr_connect(idevice_t device, fdr_type_t type, fdr_client_t *fdr);
|
| 45 |
+
void fdr_disconnect(fdr_client_t fdr);
|
| 46 |
+
void fdr_free(fdr_client_t fdr);
|
| 47 |
+
int fdr_poll_and_handle_message(fdr_client_t fdr);
|
| 48 |
+
void *fdr_listener_thread(void *cdata);
|
| 49 |
+
|
| 50 |
+
#ifdef __cplusplus
|
| 51 |
+
}
|
| 52 |
+
#endif
|
| 53 |
+
|
| 54 |
+
#endif
|
file_relay.c
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* file_relay.c
|
| 3 |
+
* com.apple.mobile.file_relay service implementation.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2010 Nikias Bassen, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifdef HAVE_CONFIG_H
|
| 23 |
+
#include <config.h>
|
| 24 |
+
#endif
|
| 25 |
+
#include <string.h>
|
| 26 |
+
#include <stdlib.h>
|
| 27 |
+
#include "file_relay.h"
|
| 28 |
+
#include "property_list_service.h"
|
| 29 |
+
#include "common/debug.h"
|
| 30 |
+
|
| 31 |
+
file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t service, file_relay_client_t *client)
|
| 32 |
+
{
|
| 33 |
+
if (!device || !service || service->port == 0 || !client || *client) {
|
| 34 |
+
return FILE_RELAY_E_INVALID_ARG;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
property_list_service_client_t plistclient = NULL;
|
| 38 |
+
if (property_list_service_client_new(device, service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
|
| 39 |
+
return FILE_RELAY_E_MUX_ERROR;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
/* create client object */
|
| 43 |
+
file_relay_client_t client_loc = (file_relay_client_t) malloc(sizeof(struct file_relay_client_private));
|
| 44 |
+
client_loc->parent = plistclient;
|
| 45 |
+
|
| 46 |
+
/* all done, return success */
|
| 47 |
+
*client = client_loc;
|
| 48 |
+
return FILE_RELAY_E_SUCCESS;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
file_relay_error_t file_relay_client_start_service(idevice_t device, file_relay_client_t * client, const char* label)
|
| 52 |
+
{
|
| 53 |
+
file_relay_error_t err = FILE_RELAY_E_UNKNOWN_ERROR;
|
| 54 |
+
service_client_factory_start_service(device, FILE_RELAY_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(file_relay_client_new), &err);
|
| 55 |
+
return err;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
file_relay_error_t file_relay_client_free(file_relay_client_t client)
|
| 59 |
+
{
|
| 60 |
+
if (!client)
|
| 61 |
+
return FILE_RELAY_E_INVALID_ARG;
|
| 62 |
+
|
| 63 |
+
if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
|
| 64 |
+
return FILE_RELAY_E_UNKNOWN_ERROR;
|
| 65 |
+
}
|
| 66 |
+
free(client);
|
| 67 |
+
return FILE_RELAY_E_SUCCESS;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout)
|
| 71 |
+
{
|
| 72 |
+
if (!client || !client->parent || !sources || !sources[0]) {
|
| 73 |
+
return FILE_RELAY_E_INVALID_ARG;
|
| 74 |
+
}
|
| 75 |
+
*connection = NULL;
|
| 76 |
+
file_relay_error_t err = FILE_RELAY_E_UNKNOWN_ERROR;
|
| 77 |
+
/* set up request plist */
|
| 78 |
+
plist_t array = plist_new_array();
|
| 79 |
+
int i = 0;
|
| 80 |
+
while (sources[i]) {
|
| 81 |
+
plist_array_append_item(array, plist_new_string(sources[i]));
|
| 82 |
+
i++;
|
| 83 |
+
}
|
| 84 |
+
plist_t dict = plist_new_dict();
|
| 85 |
+
plist_dict_set_item(dict, "Sources", array);
|
| 86 |
+
|
| 87 |
+
if (property_list_service_send_xml_plist(client->parent, dict) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
|
| 88 |
+
debug_info("ERROR: Could not send request to device!");
|
| 89 |
+
err = FILE_RELAY_E_MUX_ERROR;
|
| 90 |
+
goto leave;
|
| 91 |
+
}
|
| 92 |
+
plist_free(dict);
|
| 93 |
+
|
| 94 |
+
dict = NULL;
|
| 95 |
+
if (property_list_service_receive_plist_with_timeout(client->parent, &dict, timeout) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
|
| 96 |
+
debug_info("ERROR: Could not receive answer from device!");
|
| 97 |
+
err = FILE_RELAY_E_MUX_ERROR;
|
| 98 |
+
goto leave;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
if (!dict) {
|
| 102 |
+
debug_info("ERROR: Did not receive any plist!");
|
| 103 |
+
err = FILE_RELAY_E_PLIST_ERROR;
|
| 104 |
+
goto leave;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
plist_t error = plist_dict_get_item(dict, "Error");
|
| 108 |
+
if (error) {
|
| 109 |
+
char *errmsg = NULL;
|
| 110 |
+
plist_get_string_val(error, &errmsg);
|
| 111 |
+
if (errmsg) {
|
| 112 |
+
if (!strcmp(errmsg, "InvalidSource")) {
|
| 113 |
+
debug_info("ERROR: One or more given sources are invalid!");
|
| 114 |
+
err = FILE_RELAY_E_INVALID_SOURCE;
|
| 115 |
+
} else if (!strcmp(errmsg, "StagingEmpty")) {
|
| 116 |
+
debug_info("ERROR: StagingEmpty - No data available!");
|
| 117 |
+
err = FILE_RELAY_E_STAGING_EMPTY;
|
| 118 |
+
} else if (!strcmp(errmsg, "PermissionDenied")) {
|
| 119 |
+
debug_info("ERROR: Permission denied.");
|
| 120 |
+
err = FILE_RELAY_E_PERMISSION_DENIED;
|
| 121 |
+
} else {
|
| 122 |
+
debug_info("ERROR: Unknown error '%s'", errmsg);
|
| 123 |
+
}
|
| 124 |
+
free(errmsg);
|
| 125 |
+
} else {
|
| 126 |
+
debug_info("ERROR: Could not get error message!");
|
| 127 |
+
}
|
| 128 |
+
goto leave;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
plist_t status = plist_dict_get_item(dict, "Status");
|
| 132 |
+
if (!status) {
|
| 133 |
+
debug_info("ERROR: Unexpected plist received!");
|
| 134 |
+
debug_plist(dict);
|
| 135 |
+
err = FILE_RELAY_E_PLIST_ERROR;
|
| 136 |
+
goto leave;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
char *ack = NULL;
|
| 140 |
+
plist_get_string_val(status, &ack);
|
| 141 |
+
if (!ack) {
|
| 142 |
+
debug_info("ERROR: Could not get 'Acknowledged' string!");
|
| 143 |
+
goto leave;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
if (strcmp(ack, "Acknowledged") != 0) {
|
| 147 |
+
debug_info("ERROR: Did not receive 'Acknowledged' but '%s'", ack);
|
| 148 |
+
goto leave;
|
| 149 |
+
}
|
| 150 |
+
free(ack);
|
| 151 |
+
err = FILE_RELAY_E_SUCCESS;
|
| 152 |
+
|
| 153 |
+
*connection = client->parent->parent->connection;
|
| 154 |
+
|
| 155 |
+
leave:
|
| 156 |
+
if (dict) {
|
| 157 |
+
plist_free(dict);
|
| 158 |
+
}
|
| 159 |
+
return err;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection)
|
| 163 |
+
{
|
| 164 |
+
return file_relay_request_sources_timeout(client, sources, connection, 60000);
|
| 165 |
+
}
|
file_relay.h
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* file_relay.h
|
| 3 |
+
* com.apple.mobile.file_relay service header file.
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2010 Nikias Bassen, All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#ifndef __FILE_RELAY_H
|
| 23 |
+
#define __FILE_RELAY_H
|
| 24 |
+
|
| 25 |
+
#include "idevice.h"
|
| 26 |
+
#include "libimobiledevice/file_relay.h"
|
| 27 |
+
#include "property_list_service.h"
|
| 28 |
+
|
| 29 |
+
struct file_relay_client_private {
|
| 30 |
+
property_list_service_client_t parent;
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
#endif
|
file_relay.pxi
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cdef extern from "libimobiledevice/file_relay.h":
|
| 2 |
+
cdef struct file_relay_client_private:
|
| 3 |
+
pass
|
| 4 |
+
ctypedef file_relay_client_private *file_relay_client_t
|
| 5 |
+
ctypedef char** const_sources_t "const char**"
|
| 6 |
+
|
| 7 |
+
ctypedef enum file_relay_error_t:
|
| 8 |
+
FILE_RELAY_E_SUCCESS = 0
|
| 9 |
+
FILE_RELAY_E_INVALID_ARG = -1
|
| 10 |
+
FILE_RELAY_E_PLIST_ERROR = -2
|
| 11 |
+
FILE_RELAY_E_MUX_ERROR = -3
|
| 12 |
+
FILE_RELAY_E_INVALID_SOURCE = -4
|
| 13 |
+
FILE_RELAY_E_STAGING_EMPTY = -5
|
| 14 |
+
FILE_RELAY_E_PERMISSION_DENIED = -6
|
| 15 |
+
FILE_RELAY_E_UNKNOWN_ERROR = -256
|
| 16 |
+
|
| 17 |
+
file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, file_relay_client_t *client)
|
| 18 |
+
file_relay_error_t file_relay_client_free(file_relay_client_t client)
|
| 19 |
+
|
| 20 |
+
file_relay_error_t file_relay_request_sources(file_relay_client_t client, const_sources_t sources, idevice_connection_t *connection)
|
| 21 |
+
|
| 22 |
+
cdef class FileRelayError(BaseError):
|
| 23 |
+
def __init__(self, *args, **kwargs):
|
| 24 |
+
self._lookup_table = {
|
| 25 |
+
FILE_RELAY_E_SUCCESS: "Success",
|
| 26 |
+
FILE_RELAY_E_INVALID_ARG: "Invalid argument",
|
| 27 |
+
FILE_RELAY_E_PLIST_ERROR: "Property list error",
|
| 28 |
+
FILE_RELAY_E_MUX_ERROR: "MUX error",
|
| 29 |
+
FILE_RELAY_E_INVALID_SOURCE: "Invalid source",
|
| 30 |
+
FILE_RELAY_E_STAGING_EMPTY: "Staging empty",
|
| 31 |
+
FILE_RELAY_E_PERMISSION_DENIED: "Permission denied",
|
| 32 |
+
FILE_RELAY_E_UNKNOWN_ERROR: "Unknown error"
|
| 33 |
+
}
|
| 34 |
+
BaseError.__init__(self, *args, **kwargs)
|
| 35 |
+
|
| 36 |
+
from libc.stdlib cimport *
|
| 37 |
+
|
| 38 |
+
cdef class FileRelayClient(PropertyListService):
|
| 39 |
+
__service_name__ = "com.apple.mobile.file_relay"
|
| 40 |
+
cdef file_relay_client_t _c_client
|
| 41 |
+
|
| 42 |
+
def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs):
|
| 43 |
+
self.handle_error(file_relay_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client))
|
| 44 |
+
|
| 45 |
+
def __dealloc__(self):
|
| 46 |
+
cdef file_relay_error_t err
|
| 47 |
+
if self._c_client is not NULL:
|
| 48 |
+
err = file_relay_client_free(self._c_client)
|
| 49 |
+
self.handle_error(err)
|
| 50 |
+
|
| 51 |
+
cpdef iDeviceConnection request_sources(self, list sources):
|
| 52 |
+
cdef:
|
| 53 |
+
file_relay_error_t err
|
| 54 |
+
Py_ssize_t count = len(sources)
|
| 55 |
+
char** c_sources = <char**>malloc(sizeof(char*) * (count + 1))
|
| 56 |
+
iDeviceConnection conn = iDeviceConnection.__new__(iDeviceConnection)
|
| 57 |
+
|
| 58 |
+
for i, value in enumerate(sources):
|
| 59 |
+
c_sources[i] = value
|
| 60 |
+
c_sources[count] = NULL
|
| 61 |
+
|
| 62 |
+
err = file_relay_request_sources(self._c_client, <const_sources_t>c_sources, &conn._c_connection)
|
| 63 |
+
free(c_sources)
|
| 64 |
+
self.handle_error(err)
|
| 65 |
+
return conn
|
| 66 |
+
|
| 67 |
+
cdef inline BaseError _error(self, int16_t ret):
|
| 68 |
+
return FileRelayError(ret)
|
fls.c
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* fls.c
|
| 3 |
+
* support for .fls file format (found in .bbfw files)
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
#include <stdio.h>
|
| 22 |
+
#include <stdlib.h>
|
| 23 |
+
#include <string.h>
|
| 24 |
+
#include "fls.h"
|
| 25 |
+
#include "common.h"
|
| 26 |
+
|
| 27 |
+
#ifndef offsetof
|
| 28 |
+
#define offsetof(type, member) __builtin_offsetof (type, member)
|
| 29 |
+
#endif
|
| 30 |
+
|
| 31 |
+
static void fls_parse_elements(fls_file* fls)
|
| 32 |
+
{
|
| 33 |
+
/* FIXME: the following code is not big endian safe */
|
| 34 |
+
if (!fls || !fls->data) {
|
| 35 |
+
return;
|
| 36 |
+
}
|
| 37 |
+
uint32_t offset = 0;
|
| 38 |
+
fls->max_elements = 32;
|
| 39 |
+
fls->elements = (fls_element**)malloc(sizeof(fls_element*) * fls->max_elements);
|
| 40 |
+
|
| 41 |
+
fls_element* cur = NULL;
|
| 42 |
+
do {
|
| 43 |
+
void* p = fls->data + offset;
|
| 44 |
+
uint32_t hdrsize = 0;
|
| 45 |
+
cur = (fls_element*)p;
|
| 46 |
+
if ((offset + cur->size) > fls->size) {
|
| 47 |
+
break;
|
| 48 |
+
}
|
| 49 |
+
fls_element* ne;
|
| 50 |
+
switch (cur->type) {
|
| 51 |
+
case 0x0c:
|
| 52 |
+
{
|
| 53 |
+
hdrsize = offsetof(fls_0c_element, data);
|
| 54 |
+
fls_0c_element* xe = (fls_0c_element*)malloc(sizeof(fls_0c_element));
|
| 55 |
+
memset(xe, '\0', sizeof(fls_0c_element));
|
| 56 |
+
memcpy((void*)xe, p, hdrsize);
|
| 57 |
+
xe->data = (xe->size > hdrsize) ? p + hdrsize : NULL;
|
| 58 |
+
ne = (fls_element*)xe;
|
| 59 |
+
fls->c_element = xe;
|
| 60 |
+
}
|
| 61 |
+
break;
|
| 62 |
+
case 0x10:
|
| 63 |
+
{
|
| 64 |
+
hdrsize = offsetof(fls_10_element, data);
|
| 65 |
+
fls_10_element* xe = (fls_10_element*)malloc(sizeof(fls_10_element));
|
| 66 |
+
memset(xe, '\0', sizeof(fls_10_element));
|
| 67 |
+
memcpy((void*)xe, p, hdrsize);
|
| 68 |
+
xe->data = (xe->size > hdrsize) ? p + hdrsize : NULL;
|
| 69 |
+
ne = (fls_element*)xe;
|
| 70 |
+
}
|
| 71 |
+
break;
|
| 72 |
+
case 0x14:
|
| 73 |
+
{
|
| 74 |
+
hdrsize = offsetof(fls_14_element, data);
|
| 75 |
+
fls_14_element* xe = (fls_14_element*)malloc(sizeof(fls_14_element));
|
| 76 |
+
memset(xe, '\0', sizeof(fls_14_element));
|
| 77 |
+
memcpy((void*)xe, p, hdrsize);
|
| 78 |
+
xe->data = (xe->size > hdrsize) ? p + hdrsize : NULL;
|
| 79 |
+
ne = (fls_element*)xe;
|
| 80 |
+
}
|
| 81 |
+
break;
|
| 82 |
+
default:
|
| 83 |
+
hdrsize = offsetof(fls_element, data);
|
| 84 |
+
ne = (fls_element*)malloc(sizeof(fls_element));
|
| 85 |
+
memset(ne, '\0', sizeof(fls_element));
|
| 86 |
+
ne->type = cur->type;
|
| 87 |
+
ne->size = cur->size;
|
| 88 |
+
ne->data = (ne->size > hdrsize) ? p + hdrsize : NULL;
|
| 89 |
+
break;
|
| 90 |
+
}
|
| 91 |
+
if ((fls->num_elements + 1) > fls->max_elements) {
|
| 92 |
+
fls->max_elements += 10;
|
| 93 |
+
fls->elements = (fls_element**)realloc(fls->elements, sizeof(fls_element*) * fls->max_elements);
|
| 94 |
+
}
|
| 95 |
+
fls->elements[fls->num_elements++] = ne;
|
| 96 |
+
offset += cur->size;
|
| 97 |
+
} while (offset < fls->size);
|
| 98 |
+
if (offset != fls->size) {
|
| 99 |
+
error("ERROR: %s: error parsing elements\n", __func__);
|
| 100 |
+
return;
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
fls_file* fls_parse(unsigned char* data, unsigned int size)
|
| 105 |
+
{
|
| 106 |
+
fls_file* fls = (fls_file*)malloc(sizeof(fls_file));
|
| 107 |
+
if (!fls) {
|
| 108 |
+
return NULL;
|
| 109 |
+
}
|
| 110 |
+
memset(fls, '\0', sizeof(fls_file));
|
| 111 |
+
fls->data = malloc(size);
|
| 112 |
+
fls->size = size;
|
| 113 |
+
memcpy(fls->data, data, size);
|
| 114 |
+
fls_parse_elements(fls);
|
| 115 |
+
return fls;
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
void fls_free(fls_file* fls)
|
| 119 |
+
{
|
| 120 |
+
if (fls) {
|
| 121 |
+
if (fls->num_elements > 0) {
|
| 122 |
+
int i;
|
| 123 |
+
for (i = fls->num_elements-1; i >=0; i--) {
|
| 124 |
+
free(fls->elements[i]);
|
| 125 |
+
}
|
| 126 |
+
free(fls->elements);
|
| 127 |
+
}
|
| 128 |
+
if (fls->data) {
|
| 129 |
+
free(fls->data);
|
| 130 |
+
}
|
| 131 |
+
free(fls);
|
| 132 |
+
}
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned int siglen)
|
| 136 |
+
{
|
| 137 |
+
/* FIXME: the code in this function is not big endian safe */
|
| 138 |
+
if (!fls || !fls->num_elements) {
|
| 139 |
+
error("ERROR: %s: no data\n", __func__);
|
| 140 |
+
return -1;
|
| 141 |
+
}
|
| 142 |
+
if (!fls->c_element) {
|
| 143 |
+
error("ERROR: %s: no fls_0c_element in fls data\n", __func__);
|
| 144 |
+
return -1;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
uint32_t datasize = *(uint32_t*)(fls->c_element->data + 0x10);
|
| 148 |
+
if (datasize != fls->c_element->data_size) {
|
| 149 |
+
error("ERROR: %s: data size mismatch (0x%x != 0x%x)\n", __func__, datasize, fls->c_element->data_size);
|
| 150 |
+
return -1;
|
| 151 |
+
}
|
| 152 |
+
uint32_t sigoffset = *(uint32_t*)(fls->c_element->data + 0x14);
|
| 153 |
+
if (sigoffset > datasize) {
|
| 154 |
+
error("ERROR: %s: signature offset greater than data size (0x%x > 0x%x)\n", __func__, sigoffset, datasize);
|
| 155 |
+
return -1;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
uint32_t oldsiglen = datasize - sigoffset;
|
| 159 |
+
uint32_t newsize = fls->size - oldsiglen + siglen;
|
| 160 |
+
|
| 161 |
+
unsigned int i;
|
| 162 |
+
uint32_t offset = 0;
|
| 163 |
+
void* newdata = malloc(newsize);
|
| 164 |
+
if (!newdata) {
|
| 165 |
+
error("ERROR: %s: out of memory\n", __func__);
|
| 166 |
+
return -1;
|
| 167 |
+
}
|
| 168 |
+
uint32_t hdrsize = 0;
|
| 169 |
+
uint32_t firstpartlen = 0;
|
| 170 |
+
for (i = 0; i < fls->num_elements; i++) {
|
| 171 |
+
switch (fls->elements[i]->type) {
|
| 172 |
+
case 0x0c:
|
| 173 |
+
hdrsize = offsetof(fls_0c_element, data);
|
| 174 |
+
// update offset
|
| 175 |
+
((fls_0c_element*)fls->elements[i])->offset = offset+hdrsize;
|
| 176 |
+
// copy first part of data
|
| 177 |
+
firstpartlen = fls->elements[i]->size - hdrsize - oldsiglen;
|
| 178 |
+
memcpy(newdata+offset+hdrsize, ((fls_0c_element*)fls->elements[i])->data, firstpartlen);
|
| 179 |
+
// copy new signature data
|
| 180 |
+
memcpy(newdata+offset+hdrsize+firstpartlen, sigdata, siglen);
|
| 181 |
+
((fls_0c_element*)fls->elements[i])->data = newdata+offset+hdrsize;
|
| 182 |
+
fls->elements[i]->size -= oldsiglen;
|
| 183 |
+
fls->elements[i]->size += siglen;
|
| 184 |
+
((fls_0c_element*)fls->elements[i])->data_size -= oldsiglen;
|
| 185 |
+
((fls_0c_element*)fls->elements[i])->data_size += siglen;
|
| 186 |
+
memcpy(newdata+offset+hdrsize+0x10, &(((fls_0c_element*)fls->elements[i])->data_size), 4);
|
| 187 |
+
// copy header
|
| 188 |
+
memcpy(newdata+offset, fls->elements[i], hdrsize);
|
| 189 |
+
break;
|
| 190 |
+
case 0x10:
|
| 191 |
+
hdrsize = offsetof(fls_10_element, data);
|
| 192 |
+
// update offset
|
| 193 |
+
((fls_10_element*)fls->elements[i])->offset = offset+hdrsize;
|
| 194 |
+
// copy header
|
| 195 |
+
memcpy(newdata+offset, fls->elements[i], hdrsize);
|
| 196 |
+
// copy data
|
| 197 |
+
if (fls->elements[i]->size > hdrsize) {
|
| 198 |
+
memcpy(newdata+offset+hdrsize, ((fls_10_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize);
|
| 199 |
+
((fls_10_element*)fls->elements[i])->data = newdata+offset+hdrsize;
|
| 200 |
+
} else {
|
| 201 |
+
((fls_10_element*)fls->elements[i])->data = NULL;
|
| 202 |
+
}
|
| 203 |
+
break;
|
| 204 |
+
case 0x14:
|
| 205 |
+
hdrsize = offsetof(fls_14_element, data);
|
| 206 |
+
// update offset
|
| 207 |
+
((fls_14_element*)fls->elements[i])->offset = offset+hdrsize;
|
| 208 |
+
// copy header
|
| 209 |
+
memcpy(newdata+offset, fls->elements[i], hdrsize);
|
| 210 |
+
// copy data
|
| 211 |
+
if (fls->elements[i]->size > hdrsize) {
|
| 212 |
+
memcpy(newdata+offset+hdrsize, ((fls_14_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize);
|
| 213 |
+
((fls_14_element*)fls->elements[i])->data = newdata+offset+hdrsize;
|
| 214 |
+
} else {
|
| 215 |
+
((fls_14_element*)fls->elements[i])->data = NULL;
|
| 216 |
+
}
|
| 217 |
+
break;
|
| 218 |
+
default:
|
| 219 |
+
hdrsize = offsetof(fls_element, data);
|
| 220 |
+
// copy header
|
| 221 |
+
memcpy(newdata+offset, fls->elements[i], hdrsize);
|
| 222 |
+
// copy data
|
| 223 |
+
if (fls->elements[i]->size > hdrsize) {
|
| 224 |
+
memcpy(newdata+offset+hdrsize, fls->elements[i]->data, fls->elements[i]->size - hdrsize);
|
| 225 |
+
fls->elements[i]->data = newdata+offset+hdrsize;
|
| 226 |
+
} else {
|
| 227 |
+
fls->elements[i]->data = NULL;
|
| 228 |
+
}
|
| 229 |
+
break;
|
| 230 |
+
}
|
| 231 |
+
offset += fls->elements[i]->size;
|
| 232 |
+
}
|
| 233 |
+
if (fls->data) {
|
| 234 |
+
free(fls->data);
|
| 235 |
+
}
|
| 236 |
+
fls->data = newdata;
|
| 237 |
+
fls->size = newsize;
|
| 238 |
+
|
| 239 |
+
return 0;
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size)
|
| 243 |
+
{
|
| 244 |
+
/* FIXME: the code in this function is not big endian safe */
|
| 245 |
+
if (!fls || !fls->num_elements) {
|
| 246 |
+
error("ERROR: %s: no data\n", __func__);
|
| 247 |
+
return -1;
|
| 248 |
+
}
|
| 249 |
+
if (!fls->c_element) {
|
| 250 |
+
error("ERROR: %s: no fls_0c_element in fls data\n", __func__);
|
| 251 |
+
return -1;
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
uint32_t padding = 0;
|
| 255 |
+
if (size%4 != 0) {
|
| 256 |
+
padding = 4-(size%4);
|
| 257 |
+
}
|
| 258 |
+
uint32_t newsize = fls->size + size + padding;
|
| 259 |
+
unsigned int i;
|
| 260 |
+
uint32_t offset = 0;
|
| 261 |
+
void* newdata = malloc(newsize);
|
| 262 |
+
if (!newdata) {
|
| 263 |
+
error("ERROR: %s: out of memory\n", __func__);
|
| 264 |
+
return -1;
|
| 265 |
+
}
|
| 266 |
+
uint32_t hdrsize = 0;
|
| 267 |
+
for (i = 0; i < fls->num_elements; i++) {
|
| 268 |
+
switch (fls->elements[i]->type) {
|
| 269 |
+
case 0x0c:
|
| 270 |
+
hdrsize = offsetof(fls_0c_element, data);
|
| 271 |
+
// update offset
|
| 272 |
+
((fls_0c_element*)fls->elements[i])->offset = offset+hdrsize;
|
| 273 |
+
// copy ticket data
|
| 274 |
+
memcpy(newdata+offset+hdrsize, data, size);
|
| 275 |
+
if (padding > 0) {
|
| 276 |
+
// padding
|
| 277 |
+
memset(newdata+offset+hdrsize+size, '\xFF', padding);
|
| 278 |
+
}
|
| 279 |
+
// copy remaining data
|
| 280 |
+
memcpy(newdata+offset+hdrsize+size+padding, ((fls_0c_element*)fls->elements[i])->data, fls->elements[i]->size);
|
| 281 |
+
((fls_0c_element*)fls->elements[i])->data = newdata+offset+hdrsize;
|
| 282 |
+
fls->elements[i]->size += (size + padding);
|
| 283 |
+
((fls_0c_element*)fls->elements[i])->data_size += (size + padding);
|
| 284 |
+
// copy header
|
| 285 |
+
memcpy(newdata+offset, fls->elements[i], hdrsize);
|
| 286 |
+
break;
|
| 287 |
+
case 0x10:
|
| 288 |
+
hdrsize = offsetof(fls_10_element, data);
|
| 289 |
+
// update offset
|
| 290 |
+
((fls_10_element*)fls->elements[i])->offset = offset+hdrsize;
|
| 291 |
+
// copy header
|
| 292 |
+
memcpy(newdata+offset, fls->elements[i], hdrsize);
|
| 293 |
+
// copy data
|
| 294 |
+
if (fls->elements[i]->size > hdrsize) {
|
| 295 |
+
memcpy(newdata+offset+hdrsize, ((fls_10_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize);
|
| 296 |
+
((fls_10_element*)fls->elements[i])->data = newdata+offset+hdrsize;
|
| 297 |
+
} else {
|
| 298 |
+
((fls_10_element*)fls->elements[i])->data = NULL;
|
| 299 |
+
}
|
| 300 |
+
break;
|
| 301 |
+
case 0x14:
|
| 302 |
+
hdrsize = offsetof(fls_14_element, data);
|
| 303 |
+
// update offset
|
| 304 |
+
((fls_14_element*)fls->elements[i])->offset = offset+hdrsize;
|
| 305 |
+
// copy header
|
| 306 |
+
memcpy(newdata+offset, fls->elements[i], hdrsize);
|
| 307 |
+
// copy data
|
| 308 |
+
if (fls->elements[i]->size > hdrsize) {
|
| 309 |
+
memcpy(newdata+offset+hdrsize, ((fls_14_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize);
|
| 310 |
+
((fls_14_element*)fls->elements[i])->data = newdata+offset+hdrsize;
|
| 311 |
+
} else {
|
| 312 |
+
((fls_14_element*)fls->elements[i])->data = NULL;
|
| 313 |
+
}
|
| 314 |
+
break;
|
| 315 |
+
default:
|
| 316 |
+
hdrsize = offsetof(fls_element, data);
|
| 317 |
+
// copy header
|
| 318 |
+
memcpy(newdata+offset, fls->elements[i], hdrsize);
|
| 319 |
+
// copy data
|
| 320 |
+
if (fls->elements[i]->size > hdrsize) {
|
| 321 |
+
memcpy(newdata+offset+hdrsize, fls->elements[i]->data, fls->elements[i]->size - hdrsize);
|
| 322 |
+
fls->elements[i]->data = newdata+offset+hdrsize;
|
| 323 |
+
} else {
|
| 324 |
+
fls->elements[i]->data = NULL;
|
| 325 |
+
}
|
| 326 |
+
break;
|
| 327 |
+
}
|
| 328 |
+
offset += fls->elements[i]->size;
|
| 329 |
+
}
|
| 330 |
+
if (fls->data) {
|
| 331 |
+
free(fls->data);
|
| 332 |
+
}
|
| 333 |
+
fls->data = newdata;
|
| 334 |
+
fls->size = newsize;
|
| 335 |
+
|
| 336 |
+
return 0;
|
| 337 |
+
}
|
| 338 |
+
|
fls.h
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* fls.h
|
| 3 |
+
* support for .fls file format (found in .bbfw files)
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2012 Nikias Bassen. All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
#ifndef FLS_H
|
| 22 |
+
#define FLS_H
|
| 23 |
+
|
| 24 |
+
#include <stdint.h>
|
| 25 |
+
|
| 26 |
+
struct _fls_element {
|
| 27 |
+
uint32_t type;
|
| 28 |
+
uint32_t size;
|
| 29 |
+
uint32_t empty;
|
| 30 |
+
const unsigned char* data;
|
| 31 |
+
} __attribute__((packed));
|
| 32 |
+
typedef struct _fls_element fls_element;
|
| 33 |
+
|
| 34 |
+
struct _fls_0c_element {
|
| 35 |
+
uint32_t type;
|
| 36 |
+
uint32_t size;
|
| 37 |
+
uint32_t empty;
|
| 38 |
+
uint32_t off_0x0c;
|
| 39 |
+
uint32_t off_0x10;
|
| 40 |
+
uint32_t off_0x14;
|
| 41 |
+
uint32_t off_0x18;
|
| 42 |
+
uint32_t data_size; // size without header
|
| 43 |
+
uint32_t off_0x20;
|
| 44 |
+
uint32_t offset; // absolute offset of data in file
|
| 45 |
+
const unsigned char* data; // data+0x14 contains offset to sig blob
|
| 46 |
+
} __attribute__((packed));
|
| 47 |
+
typedef struct _fls_0c_element fls_0c_element;
|
| 48 |
+
|
| 49 |
+
struct _fls_10_element {
|
| 50 |
+
uint32_t type;
|
| 51 |
+
uint32_t size;
|
| 52 |
+
uint32_t empty;
|
| 53 |
+
uint32_t data_size; // size without header
|
| 54 |
+
uint32_t off_0x10;
|
| 55 |
+
uint32_t offset;
|
| 56 |
+
const unsigned char* data;
|
| 57 |
+
} __attribute__((packed));
|
| 58 |
+
typedef struct _fls_10_element fls_10_element;
|
| 59 |
+
|
| 60 |
+
struct _fls_14_element {
|
| 61 |
+
uint32_t type;
|
| 62 |
+
uint32_t size;
|
| 63 |
+
uint32_t empty;
|
| 64 |
+
uint32_t data_size; // size without header
|
| 65 |
+
uint32_t off_0x10;
|
| 66 |
+
uint32_t offset;
|
| 67 |
+
const unsigned char* data;
|
| 68 |
+
} __attribute__((packed));
|
| 69 |
+
typedef struct _fls_14_element fls_14_element;
|
| 70 |
+
|
| 71 |
+
typedef struct {
|
| 72 |
+
unsigned int num_elements;
|
| 73 |
+
unsigned int max_elements;
|
| 74 |
+
fls_element** elements;
|
| 75 |
+
const fls_0c_element* c_element;
|
| 76 |
+
void* data;
|
| 77 |
+
uint32_t size;
|
| 78 |
+
} fls_file;
|
| 79 |
+
|
| 80 |
+
fls_file* fls_parse(unsigned char* data, unsigned int size);
|
| 81 |
+
void fls_free(fls_file* fls);
|
| 82 |
+
int fls_update_sig_blob(fls_file* fls, const unsigned char* data, unsigned int size);
|
| 83 |
+
int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size);
|
| 84 |
+
|
| 85 |
+
#endif
|
ftab.c
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* ftab.c
|
| 3 |
+
* Functions for handling the ftab format
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) 2019 Nikias Bassen. All Rights Reserved.
|
| 6 |
+
*
|
| 7 |
+
* This library is free software; you can redistribute it and/or
|
| 8 |
+
* modify it under the terms of the GNU Lesser General Public
|
| 9 |
+
* License as published by the Free Software Foundation; either
|
| 10 |
+
* version 2.1 of the License, or (at your option) any later version.
|
| 11 |
+
*
|
| 12 |
+
* This library is distributed in the hope that it will be useful,
|
| 13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 15 |
+
* Lesser General Public License for more details.
|
| 16 |
+
*
|
| 17 |
+
* You should have received a copy of the GNU Lesser General Public
|
| 18 |
+
* License along with this library; if not, write to the Free Software
|
| 19 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| 20 |
+
*/
|
| 21 |
+
|
| 22 |
+
#include <stdio.h>
|
| 23 |
+
#include <stdlib.h>
|
| 24 |
+
#include <string.h>
|
| 25 |
+
#include <stdint.h>
|
| 26 |
+
|
| 27 |
+
#include "ftab.h"
|
| 28 |
+
#include "common.h"
|
| 29 |
+
#include "endianness.h"
|
| 30 |
+
|
| 31 |
+
int ftab_parse(unsigned char *data, unsigned int data_size, ftab_t *ftab, uint32_t *tag)
|
| 32 |
+
{
|
| 33 |
+
if (!data || !data_size || !ftab) {
|
| 34 |
+
return -1;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
if (data_size < sizeof(struct ftab_header)) {
|
| 38 |
+
error("ERROR: %s: Buffer too small for ftab data\n", __func__);
|
| 39 |
+
return -1;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
struct ftab_header *hdr_ptr = (struct ftab_header*)data;
|
| 43 |
+
if (be32toh(hdr_ptr->magic) != 'ftab') {
|
| 44 |
+
error("ERROR: %s: Unexpected magic value 0x%08x\n", __func__, le32toh(hdr_ptr->magic));
|
| 45 |
+
return -1;
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
/* copy header */
|
| 49 |
+
ftab_t ftab_new = (ftab_t)calloc(1, sizeof(struct ftab_fmt));
|
| 50 |
+
memcpy(&ftab_new->header, data, sizeof(struct ftab_header));
|
| 51 |
+
|
| 52 |
+
ftab_new->header.always_01 = le32toh(ftab_new->header.always_01);
|
| 53 |
+
ftab_new->header.always_ff = le32toh(ftab_new->header.always_ff);
|
| 54 |
+
ftab_new->header.tag = be32toh(ftab_new->header.tag);
|
| 55 |
+
if (tag) {
|
| 56 |
+
*tag = ftab_new->header.tag;
|
| 57 |
+
}
|
| 58 |
+
ftab_new->header.magic = be32toh(ftab_new->header.magic);
|
| 59 |
+
ftab_new->header.num_entries = le32toh(ftab_new->header.num_entries);
|
| 60 |
+
|
| 61 |
+
/* copy entries */
|
| 62 |
+
ftab_new->entries = (struct ftab_entry*)malloc(sizeof(struct ftab_entry) * ftab_new->header.num_entries);
|
| 63 |
+
memcpy(ftab_new->entries, data + sizeof(struct ftab_header), sizeof(struct ftab_entry) * ftab_new->header.num_entries);
|
| 64 |
+
|
| 65 |
+
/* create data storage */
|
| 66 |
+
ftab_new->storage = (unsigned char**)calloc(ftab_new->header.num_entries, sizeof(unsigned char*));
|
| 67 |
+
|
| 68 |
+
/* fill data storage */
|
| 69 |
+
uint32_t i = 0;
|
| 70 |
+
for (i = 0; i < ftab_new->header.num_entries; i++) {
|
| 71 |
+
ftab_new->entries[i].tag = be32toh(ftab_new->entries[i].tag);
|
| 72 |
+
ftab_new->entries[i].offset = le32toh(ftab_new->entries[i].offset);
|
| 73 |
+
ftab_new->entries[i].size = le32toh(ftab_new->entries[i].size);
|
| 74 |
+
|
| 75 |
+
ftab_new->storage[i] = malloc(ftab_new->entries[i].size);
|
| 76 |
+
memcpy(ftab_new->storage[i], data + ftab_new->entries[i].offset, ftab_new->entries[i].size);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
*ftab = ftab_new;
|
| 80 |
+
|
| 81 |
+
return 0;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, unsigned char **data, unsigned int *data_size)
|
| 85 |
+
{
|
| 86 |
+
if (!ftab || !tag || !data || !data_size) {
|
| 87 |
+
return -1;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
uint32_t i;
|
| 91 |
+
int res = -1;
|
| 92 |
+
for (i = 0; i < ftab->header.num_entries; i++) {
|
| 93 |
+
if (ftab->entries[i].tag == tag) {
|
| 94 |
+
*data = ftab->storage[i];
|
| 95 |
+
*data_size = ftab->entries[i].size;
|
| 96 |
+
res = 0;
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
return res;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int data_size)
|
| 103 |
+
{
|
| 104 |
+
if (!ftab || !tag || !data || !data_size) {
|
| 105 |
+
return -1;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
uint32_t new_index = ftab->header.num_entries;
|
| 109 |
+
struct ftab_entry *new_entries = realloc(ftab->entries, sizeof(struct ftab_entry) * (ftab->header.num_entries + 1));
|
| 110 |
+
if (!new_entries) {
|
| 111 |
+
error("ERROR: %s: realloc failed!\n", __func__);
|
| 112 |
+
return -1;
|
| 113 |
+
}
|
| 114 |
+
ftab->entries = new_entries;
|
| 115 |
+
unsigned char **new_storage = realloc(ftab->storage, sizeof(unsigned char*) * (ftab->header.num_entries + 1));
|
| 116 |
+
if (!new_storage) {
|
| 117 |
+
error("ERROR: %s: realloc failed!\n", __func__);
|
| 118 |
+
return -1;
|
| 119 |
+
}
|
| 120 |
+
ftab->storage = new_storage;
|
| 121 |
+
|
| 122 |
+
unsigned char *data_copy = (unsigned char*)malloc(data_size);
|
| 123 |
+
if (!data_copy) {
|
| 124 |
+
return -1;
|
| 125 |
+
}
|
| 126 |
+
memcpy(data_copy, data, data_size);
|
| 127 |
+
|
| 128 |
+
ftab->storage[new_index] = data_copy;
|
| 129 |
+
ftab->entries[new_index].tag = tag;
|
| 130 |
+
ftab->entries[new_index].size = data_size;
|
| 131 |
+
ftab->header.num_entries++;
|
| 132 |
+
|
| 133 |
+
uint32_t off = sizeof(struct ftab_header) + sizeof(struct ftab_entry) * ftab->header.num_entries;
|
| 134 |
+
uint32_t i;
|
| 135 |
+
for (i = 0; i < ftab->header.num_entries; i++) {
|
| 136 |
+
ftab->entries[i].offset = off;
|
| 137 |
+
off += ftab->entries[i].size;
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
return 0;
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
int ftab_write(ftab_t ftab, unsigned char **data, unsigned int *data_size)
|
| 144 |
+
{
|
| 145 |
+
uint32_t i;
|
| 146 |
+
unsigned int total_size = sizeof(struct ftab_header);
|
| 147 |
+
total_size += ftab->header.num_entries * sizeof(struct ftab_entry);
|
| 148 |
+
for (i = 0; i < ftab->header.num_entries; i++) {
|
| 149 |
+
total_size += ftab->entries[i].size;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
unsigned char *data_out = (unsigned char*)malloc(total_size);
|
| 153 |
+
if (!data_out) {
|
| 154 |
+
error("ERROR: %s: Out of memory?!\n", __func__);
|
| 155 |
+
return -1;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
struct ftab_header *ftab_header = (struct ftab_header*)data_out;
|
| 159 |
+
memset(ftab_header, '\0', sizeof(struct ftab_header));
|
| 160 |
+
ftab_header->always_01 = htole32(ftab->header.always_01);
|
| 161 |
+
ftab_header->always_ff = htole32(ftab->header.always_ff);
|
| 162 |
+
ftab_header->tag = htobe32(ftab->header.tag);
|
| 163 |
+
ftab_header->magic = htobe32(ftab->header.magic);
|
| 164 |
+
ftab_header->num_entries = htole32(ftab->header.num_entries);
|
| 165 |
+
|
| 166 |
+
for (i = 0; i < ftab->header.num_entries; i++) {
|
| 167 |
+
struct ftab_entry* entry = (struct ftab_entry*)(data_out + sizeof(struct ftab_header) + (sizeof(struct ftab_entry) * i));
|
| 168 |
+
entry->tag = htobe32(ftab->entries[i].tag);
|
| 169 |
+
entry->offset = htole32(ftab->entries[i].offset);
|
| 170 |
+
entry->size = htole32(ftab->entries[i].size);
|
| 171 |
+
entry->pad_0x0C = 0;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
unsigned char *p = data_out + sizeof(struct ftab_header) + (sizeof(struct ftab_entry) * ftab->header.num_entries);
|
| 175 |
+
for (i = 0; i < ftab->header.num_entries; i++) {
|
| 176 |
+
memcpy(p, ftab->storage[i], ftab->entries[i].size);
|
| 177 |
+
p += ftab->entries[i].size;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
*data = data_out;
|
| 181 |
+
*data_size = total_size;
|
| 182 |
+
|
| 183 |
+
return 0;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
int ftab_free(ftab_t ftab)
|
| 187 |
+
{
|
| 188 |
+
if (!ftab) return -1;
|
| 189 |
+
uint32_t i = 0;
|
| 190 |
+
for (i = 0; i < ftab->header.num_entries; i++) {
|
| 191 |
+
free(ftab->storage[i]);
|
| 192 |
+
}
|
| 193 |
+
free(ftab->storage);
|
| 194 |
+
free(ftab->entries);
|
| 195 |
+
free(ftab);
|
| 196 |
+
return 0;
|
| 197 |
+
}
|