pax_global_header00006660000000000000000000000064137417632210014520gustar00rootroot0000000000000052 comment=52c38a4a756b30efecc6470b5e4d4f22f9187a45 umtp-responder-1.3.10/000077500000000000000000000000001374176322100145665ustar00rootroot00000000000000umtp-responder-1.3.10/.github/000077500000000000000000000000001374176322100161265ustar00rootroot00000000000000umtp-responder-1.3.10/.github/workflows/000077500000000000000000000000001374176322100201635ustar00rootroot00000000000000umtp-responder-1.3.10/.github/workflows/ccpp.yml000066400000000000000000000002301374176322100216260ustar00rootroot00000000000000name: C/C++ CI on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: make run: make umtp-responder-1.3.10/.gitignore000066400000000000000000000000141374176322100165510ustar00rootroot00000000000000obj/ umtprd umtp-responder-1.3.10/LICENSE000066400000000000000000001045131374176322100155770ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . umtp-responder-1.3.10/Makefile000066400000000000000000000011011374176322100162170ustar00rootroot00000000000000 override CFLAGS += -I./inc -lpthread -Wall -O3 sources := $(wildcard src/*.c) objects := $(sources:src/%.c=obj/%.o) ops_sources := $(wildcard src/mtp_operations/*.c) ops_objects := $(ops_sources:src/mtp_operations/%.c=obj/%.o) all: output_dir umtprd umtprd: $(objects) $(ops_objects) ${CC} -o $@ $^ $(LDFLAGS) -lpthread $(objects): obj/%.o: src/%.c ${CC} -o $@ $^ -c $(CFLAGS) $(ops_objects): obj/%.o: src/mtp_operations/%.c ${CC} -o $@ $^ -c $(CFLAGS) output_dir: @mkdir -p obj clean: rm -Rf *.o .*.o .*.o.* *.ko .*.ko *.mod.* .*.mod.* .*.cmd umtprd obj umtp-responder-1.3.10/README.md000066400000000000000000000066371374176322100160610ustar00rootroot00000000000000![uMTP-responder logo](https://raw.githubusercontent.com/viveris/uMTP-Responder/master/img/umtp-128h.png ) # uMTP-Responder ## Lightweight USB Media Transfer Protocol (MTP) responder daemon for GNU/Linux The uMTP-Responder allows files to be transferred to and from devices through the devices USB port. ### Main characteristics and features - Implemented in C. - Lightweight implementation. - User space implementation. - As few dependencies as possible. - Hook to the FunctionFS/libcomposite or the GadgetFS Linux layer. - Dynamic handles allocation (No file-system pre-scan). - Unicode support. - (Optional) Syslog support. ## Current status ### What is working - Folder listing. - Folder creation. - Files & Folders upload. - Files & Folders download. - Files & Folders deletion. - Files & Folders renaming. - Files / folders changes async events. - Up to 16 storage instances supported. - Storages mount / unmount. - GadgetFS and FunctionFS/libcomposite modes supported. ## Which platforms are supported ? Any board with a USB device port should be compatible. The only requirement is to have the USB FunctionFS (CONFIG_USB_FUNCTIONFS) or GadgetFS (CONFIG_USB_GADGETFS) support enabled in your Linux kernel. You also need to enable the board-specific USB device port driver (eg. dwc2 for the RaspberryPi Zero). uMTP-Responder is currently tested with various 4.x.x Linux kernel versions. This may work with earlier kernels (v3.x.x and some v2.6.x versions) but without any guarantee. ### Successfully tested boards - Atmel Sama5D2 Xplained. - Raspberry PI Zero (W). - BeagleBone Black. - Allwinner SoC based board. - Freescale i.MX6 SabreSD. (Kernel v4.14) - Samsung Artik710. (FunctionFS mode) ### Successfully tested client operating systems - Windows 7, Windows 10, Linux, Android. ## How to build it ? A simple "make" should be enough if you build uMTPrd directly on the target. If you are using a cross-compile environment, set the "CC" variable to your GCC cross compiler. You can also enable the syslog support with the C flag "USE_SYSLOG" and the verbose/debug output with the "DEBUG" C flag. examples: On a cross-compile environment : ```c make CC=armv6j-hardfloat-linux-gnueabi-gcc ``` On a cross-compile environment with both syslog support and debug output options enabled : ```c make CC=armv6j-hardfloat-linux-gnueabi-gcc CFLAGS="-DUSE_SYSLOG -DDEBUG" ``` Note: syslog support and debug output options can be enabled separately. (replace "armv6j-hardfloat-linux-gnueabi-gcc" with your target gcc cross-compiler) If you want to use it on a Kernel version < 3.15 you need to compile uMTPrd with old-style FunctionFS descriptors support: ```c make CC=armv6j-hardfloat-linux-gnueabi-gcc CFLAGS="-DOLD_FUNCTIONFS_DESCRIPTORS" ``` ## How to set it up ? A config file should copied into the folder /etc/umtprd/umtprd.conf This file defines the storage entries (host path and name), the MTP device name, the USB vendor & product IDs and the USB device configuration. Check the file [umtprd.conf](conf/umtprd.conf) file for details on available options. ## How to launch it ? Once you have configured the correct settings in umtprd.conf, you can use umtprd_ffs.sh or umtprd_gfs.sh to launch it in FunctionFS/GadgetFS mode or use udev to launch the deamon when the usb device port is connected. ## License This project is licensed under the GNU General Public License version 3 - see the [LICENSE](LICENSE) file for details umtp-responder-1.3.10/Release-notes.txt000066400000000000000000000066071374176322100200460ustar00rootroot00000000000000================================================= * uMTP Responder * Lightweight USB Media Transfer Protocol (MTP) * responder * * Copyright (c) 2018 - 2020 Viveris Technologies * * https://github.com/viveris/uMTP-Responder * * Release notes ================================================= Noteworthy changes in release v1.3.6 (2020-Apr-3) ================================================= * MTP Storage mount / unmount support (-cmd:mount:[store name] / -cmd:unmount:[store name] / ). * Config file : * "storage" operation : new "notmounted" option. * New usb_max_rd_buffer_size option (iMX6 issue workaround). * New usb_max_wr_buffer_size option (iMX6 issue workaround). * New read_buffer_cache_size option (iMX6 issue workaround). * Config file path can be changed in the command line (-conf:[Config file path]). * Async/inotify event : Send file size changes. * Fix : gadgetfs -> Handle unexpected disconnection while transferring a file. * Fix : Shared multi-drives inotify events. * Code fixes / improvements : * MTP operations : Better errors handling. * Code refactoring (MTP operations code separated). Noteworthy changes in release v1.0.0 (2019-10-7) ================================================= * Major update ! : Now support all file operations ! * Config file : storage "rw"/"ro" parameter added to write protect a drive. * Performance : Read and write throughput increased (~ 4x speedup). * Fix >2GB files listing. * Fix >2GB files access support on 32 bits systems. * File read/write transfer cancel operation supported. * Drives and objects properties support. * New supported commands : * MTP_OPERATION_GET_PARTIAL_OBJECT_64 * MTP_OPERATION_SEND_PARTIAL_OBJECT * MTP_OPERATION_BEGIN_EDIT_OBJECT * MTP_OPERATION_END_EDIT_OBJECT * MTP_OPERATION_TRUNCATE_OBJECT * MTP_REQ_CANCEL * MTP_REQ_RESET * MTP_REQ_GET_DEVICE_STATUS * MTP_OPERATION_GET_DEVICE_PROP_DESC * MTP_OPERATION_GET_DEVICE_PROP_VALUE * MTP_OPERATION_GET_OBJECT_REFERENCES * MTP_OPERATION_GET_OBJECT_PROP_LIST * MTP_OPERATION_GET_OBJECT_PROP_VALUE * MTP_OPERATION_SET_OBJECT_PROP_VALUE * Many others fixes and improvements ! Noteworthy changes in release v0.10.1 (2019-7-17) ================================================= * True Unicode support. * Files/Folders renaming support. * Fixes and improvements. Noteworthy changes in release v0.9.7 (2019-1-10) ================================================= * MTP event support added : * The MTP initiator is now notified when files/folders are removed or added from the responder. * Various debug messages fixes and improvements. Noteworthy changes in release v0.9.2 (2018-12-5) ================================================= * Generic FunctionFS/libcomposite support added ! * New configuration option : show/hide hidden files option. * It now follows the symbolic links. Noteworthy changes in release v0.8.6 (2018-6-30) ================================================= * Daemon mode : * New "loop_on_disconnect" config file option. * Bug fixes / Improvements : * Windows host : Non-empty folder deletion issue fixed. * Severals memory leaks in daemon mode fixed. * GadgetFS init/deinit reworked. Noteworthy changes in release v0.8.1 (2018-5-9) ================================================= * Initial release. Tested on Raspberry Pi Zero and Atmel Sama5D2 Xplained boards. umtp-responder-1.3.10/conf/000077500000000000000000000000001374176322100155135ustar00rootroot00000000000000umtp-responder-1.3.10/conf/S98uMTPrd000066400000000000000000000015351374176322100171210ustar00rootroot00000000000000#!/bin/sh GADGETFS_PATH=/dev/gadget UMTPRD_DAEMON_NAME=uMTPrd UMTPRD_DAEMON_PATH=/usr/bin/umtprd.sh UMTPRD_DAEMON_OPTS= UMTPRD_DAEMON_USER=root case "$1" in start) echo -n "Start uMTPrd deamon :" if [ ! -f "$GADGETFS_PATH" ]; then mkdir $GADGETFS_PATH fi mount -t gadgetfs gadgetfs $GADGETFS_PATH start-stop-daemon -S --background --name $UMTPRD_DAEMON_NAME \ --chuid $UMTPRD_DAEMON_USER \ --exec $UMTPRD_DAEMON_PATH \ -- $UMTPRD_DAEMON_OPTS echo "DONE" ;; stop) printf -n "Stop uMTPrd deamon :" start-stop-daemon --name $UMTPRD_DAEMON_NAME --K -s 9 echo " DONE" ;; restart|reload) "$0" stop "$0" start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac exit $? umtp-responder-1.3.10/conf/umtprd-ffs.sh000066400000000000000000000020251374176322100201350ustar00rootroot00000000000000#/bin/sh # FunctionFS uMTPrd startup example/test script # Must be launched from a writable/temporary folder. modprobe libcomposite mkdir cfg mount none cfg -t configfs mkdir cfg/usb_gadget/g1 cd cfg/usb_gadget/g1 mkdir configs/c.1 mkdir functions/ffs.mtp # Uncomment / Change the follow line to enable another usb gadget function #mkdir functions/acm.usb0 mkdir strings/0x409 mkdir configs/c.1/strings/0x409 echo 0x0100 > idProduct echo 0x1D6B > idVendor echo "01234567" > strings/0x409/serialnumber echo "Viveris Technologies" > strings/0x409/manufacturer echo "The Viveris Product !" > strings/0x409/product echo "Conf 1" > configs/c.1/strings/0x409/configuration echo 120 > configs/c.1/MaxPower ln -s functions/ffs.mtp configs/c.1 # Uncomment / Change the follow line to enable another usb gadget function #ln -s functions/acm.usb0 configs/c.1 mkdir /dev/ffs-mtp mount -t functionfs mtp /dev/ffs-mtp # Start the umtprd service umtprd & cd ../../.. sleep 1 # enable the usb functions ls /sys/class/udc/ > cfg/usb_gadget/g1/UDC umtp-responder-1.3.10/conf/umtprd.conf000066400000000000000000000060721374176322100177020ustar00rootroot00000000000000# # uMTP Responder config file # Must be copied to /etc/umtprd/umtprd.conf # # Loop / daemon mode # Set to 1 to don't shutdown uMTPrd when the link is disconnected. loop_on_disconnect 0 # storage command : Create add a storage entry point. Up to 16 entry points supported # Syntax : storage "PATH" "NAME" storage "/" "root folder" "rw" storage "/home" "home folder" "ro" storage "/www" "www folder" "ro,notmounted" # # Uncomment the following line if you want to # override the system default umask value for # the uploaded files. # #umask 022 # Set the USB manufacturer string manufacturer "Viveris Technologies" # Set the USB Product string product "Viveris Technologies" # Set the USB Serial number string serial "01234567" # Set the MTP firmware version firmware_version "Rev A" # Set the USB interface string. Should be always "MTP" interface "MTP" # Set the USB Vendor ID, Product ID and class usb_vendor_id 0x1D6B # Linux Foundation usb_product_id 0x0100 # PTP Gadget usb_class 0x6 # Image usb_subclass 0x1 # Still Imaging device usb_protocol 0x1 # # Device version usb_dev_version 0x3008 # inotify support # If you want disable the events support (beta), uncomment the following line : # no_inotify 0x1 # # Internal buffers size # # Internal default usb_max_rd_buffer_size and usb_max_wr_buffer_size value set to 0x10000. # Internal default read_buffer_cache_size value set to 0x100000. # Uncomment the following lines to reduce the buffers sizes to fix USB issues on iMX6 based systems. # usb_max_rd_buffer_size 0x200 # MAX usb read size. Must be a multiple of 512 and be less than read_buffer_cache_size # usb_max_wr_buffer_size 0x200 # MAX usb write size. Must be a multiple of 512. # read_buffer_cache_size 0x4000 # Read file cache buffer. Must be a 2^x value. # # USB gadget device driver path # ######################################################################## # # -- Generic FunctionFS Mode -- # ######################################################################## usb_functionfs_mode 0x1 usb_dev_path "/dev/ffs-mtp/ep0" usb_epin_path "/dev/ffs-mtp/ep1" usb_epout_path "/dev/ffs-mtp/ep2" usb_epint_path "/dev/ffs-mtp/ep3" usb_max_packet_size 0x200 ######################################################################## # # -- GadgetFS Mode : Atmel Sama5D2Xplained board -- # ######################################################################## #usb_functionfs_mode 0x0 #usb_dev_path "/dev/gadget/atmel_usba_udc" #usb_epin_path "/dev/gadget/ep1" #usb_epout_path "/dev/gadget/ep2" #usb_epint_path "/dev/gadget/ep3" # Max USB packet size #usb_max_packet_size 0x200 ######################################################################## # # -- GadgetFS Mode : Raspberry PI Zero / Raspberry PI Zero W Boards -- # ######################################################################## #usb_functionfs_mode 0x0 #usb_dev_path "/dev/gadget/20980000.usb" #usb_epin_path "/dev/gadget/ep1in" #usb_epout_path "/dev/gadget/ep2out" #usb_epint_path "/dev/gadget/ep3in" # Max USB packet size #usb_max_packet_size 0x200 umtp-responder-1.3.10/conf/umtprd.init000066400000000000000000000017111374176322100177130ustar00rootroot00000000000000#!/bin/sh GADGETFS_PATH=/dev/gadget UMTPRD_DAEMON_NAME=uMTPrd UMTPRD_DAEMON_PATH=/usr/bin/umtprd UMTPRD_DAEMON_OPTS= UMTPRD_DAEMON_USER=root case "$1" in start) echo -n "Start uMTPrd daemon :" if [ ! -d "$GADGETFS_PATH" ]; then mkdir $GADGETFS_PATH fi mountpoint -q $GADGETFS_PATH MOUNTED=$? if [ "$MOUNTED" != "0" ] ; then mount -t gadgetfs gadgetfs $GADGETFS_PATH fi start-stop-daemon -S --background --name $UMTPRD_DAEMON_NAME \ --chuid $UMTPRD_DAEMON_USER \ --exec $UMTPRD_DAEMON_PATH \ -- $UMTPRD_DAEMON_OPTS echo "DONE" ;; stop) echo -n "Stop uMTPrd daemon :" start-stop-daemon --stop --signal 3 --quiet --exec $UMTPRD_DAEMON_PATH echo " DONE" ;; restart|reload) "$0" stop "$0" start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac exit $? umtp-responder-1.3.10/conf/umtprd_gfs.sh000066400000000000000000000004071374176322100202220ustar00rootroot00000000000000#/bin/sh # GadgetFS uMTPrd startup example/test script # Raspberry Pi : start dwc2 & gadgetfs modprobe dwc2 modprobe gadgetfs # Mount gadgetfs mkdir /dev/gadget mount -t gadgetfs gadgetfs /dev/gadget # Start umtprd while [ test ]; do /usr/bin/umtprd done umtp-responder-1.3.10/img/000077500000000000000000000000001374176322100153425ustar00rootroot00000000000000umtp-responder-1.3.10/img/uMTP-logo.svg000066400000000000000000000537641374176322100176650ustar00rootroot00000000000000 image/svg+xml uMTP umtp-responder-1.3.10/img/umtp-128h.png000066400000000000000000000160011374176322100175130ustar00rootroot00000000000000PNG  IHDR;tsBIT|d pHYsfGmtEXtSoftwarewww.inkscape.org<~IDATxwt\՝}oFnU˪e۱ݐ&@!4/@ȦI9!o&Kr`7u aw6=%ZMyzeiFyUw|=eKd7Xʀ)`u!1`l,Ko'V۰aĢUdج)!*8g{gpJWO( RCB #lx׾-;T/YpRK:#E~Ϳ8;rZA$"U#pbq₃ַ9,J/!rQdqK/bN%"B.C[|Oƾ(t!$N[ ^!)[Br([kI-L;%%` Dp0֐CfHWd,>Xsy7t BblO6X喱1q,R̬Cb)d*yO05@qS&O@䝑 ! G` jT}L 2⤳@+BHYM^)ʝ0ɭf˖-̙3@LvԄ={^yKJU4]ʑ'| ?U)HLt}45wH 5I@Տ4`srssC!++'a2f8ؼy36nΕ?V nh50gڍ?}NU4\7.b|nc=ߜc ӧO*++5%aRjE՜+݄蟮h5Kp MC47Ow#--Ī5kf)2 TK2s=Yg|țJ@Aͱydl6̘1CqA;B5"f"6[-&sۢ ( :Tf&2({ 6m()ƲGVcSpݟAA^:nx~iV,?p`tjNJHeGt]blBA^:\n c(@tM"rs֍Lۡm`FZBP#R`2k ={QVu^pQQՌq9,e23 /mҫ= 1t ~m?vF&2P#}/],hnBsk83d֍g`pv|Yq,[iehЃ$leFhԵ@_>o=s…^M {8?[V_m+ExucK9*셎^C^~cߘObr!A!1!$&P##QcRZ͒$gLn|>Ad轂7 Qg/=}|P#Q㏿^dqӅw&l9Y)xIKwn %9BzPױ&6q8[݌Gki!.WKBRM7V&g<*kZg>VA^z;g&̜>_c^˷;Ӿ:;BB STRgc"T6)^O+ }B1pű3Ɉuk~r.GKB*ɜC` ?>T ;_]vι#*k Ν-*rv*)R0,_{GѼDl;zf9Q`HLaZq6״nn.Ʈ'K,`GewX-H oݰr"x9̞F]7?.QA'~?oA60X~>z/{rsRߪi~FX=(F)3*/;Ʀj;L]CN` %ʖ:x 1y`G".fE4űfT^ϛ#zt2$_Z {909fTfw|xD3 v$Js,Uc( ʤIŭ7]y҅uSր۬IUg,ؕk'ԣž?ݠ9l7T ן{>$w={4v|/,׾z[ǿmzS.E3P뮃t)˭y#Ih[a=!Qˎ(%*]w@PJK- ?A@ݱ>rzZ Kz^9^Fvf2_T5oش"e`rܨ=ry*_qck`G4Ap2\,ϟx{9`G (fQ,7?NOs}Tw楣swrϱ!5&4tܫ9W Gg{upo =~=HGяU5, rp[KR` ^:C1 wKU88[1Oe͚`zsk7zC.ÕGkS$ZS@[1%RPUuރ(SF;y|lнWfЂp&xd+w3)#cι"_2l<߁AA%/wR$IFQW+V]oʩ&s1`.* x}"rd^4UAU*kƾgiNV qcF't vZ_xDV^3Kq_:qu^?$Aվo"Ϊz#R<ުM-R캥N2,u;: e PX_YbhyԺJ(}_'+=8Vu Q'V=ފv'Q#PcX8f7.%WOOMznrwAOrVT#Jui1(xG.[Mj}zwj18Xu1ٗDneFt`jw}qmK=3&%'}*QwHMcFd̞eWdE#[xԓh)o6(Wa4|! vX9ofi8b{_ŏyq.|[zSI2`$8{L@ej#XX`83#?]AKo f`??rcRmzWU n5g5k ʉ1E-;QQՌ+֬ ..CQa& I2.t W`108Og6ظSpt I+oW;p:_N׭Zaʼn3F3Yx4T&Qc 88&p%^^#px]{{ۑ @.`GAH>;BHL`G !1!$&온9t핌AϑXh,gͱ:\MA}}ӹLh 8[{->|2ғ4` Ii$kڵ+!QSSZ1z-©$w߶ &صS2O` )Iß{`K7@ ͆tL3,~YHW5 :?n]G"k``O=f)$zꎛkO>s^\lq=g_!V^!f{W a:Ac!B2aKdy455ofr7/N³>&T.؅_{ Nk/g*Iز,7!bK-'+3GONEvV DQ@fF2JCe6!їp)/99o[(JD˅(w9̪{®='Vʙya)sv9:("9I,Q5IDIp0cH,E#BEEEX*DKbp }/9j[|Qܒ>O_^$IBRR #$999,;)d8X*[<K4]JopЉӕZfcSn ohu .M͝ز(޺a^8NH+۶yߩ-fϞrq 鐙 V?Na2\b.huV~cn 90wV!f*J,N}5giB,X ,eyӮ]MY2!D`pZzLY\b6ԋ&ivKغ. )vLNNȲyv1̝;pm㥸?0'Μlj3Տ-?CLP. VtlKїsÇرc3'n1k,\uU}G{O[*73 9-G"dBca޼y7o^v Ą1Y+{N #, q)Ē;Yn @=g$ɺ!%1>8 Lfb 3oYnK̅Kȥ?1xa8؉ VwFTaH,#DȻ>M.Jr PE'G(}.MIȈމ=fW@kjyH744u&<,2SDR*V*{!޿aXf ͛>p9Gmm-oߎ={htË,R=L3ƿ$k@CS'L̄:QY}!ȍxR'?AII ,n1b!l`;WMt5B+N?w/A?_2k.!!wu[hn&s~Nwt5V~;w%4Kʕ+REHhnF-hKxNOe;PbB@f $t6 %%%8yKsK2@5n|N hw9GeM+^{0*+`ǽ;jEﻯ!#HIGNV2l=·4v+i&zvBNN uuu"Dg kE}v>@ǎ3T>TVVꞣ\|cVܹ3jR:NJ^{͓Z[Mbԭ@Ȉ6dA<4T){۷or]܇p$nӃݻwCev̎cs>}? m" fT+,3T8b@w؈qņa8L{a0.UM$pv8o2(O@"x?wL@B!@h \~Ӕpㆾ3h63=QB"ޅraÆ 8{$ҵ!9֯G^l*"0{w߻?4k-!*Dukޞ)FP#L|g,޸_{(+Z`˸WB=Qp-ܷe"ѣE]+Ǽrbpؾ~&! Kf,0@6을2>^\wc_/{]`IENDB`umtp-responder-1.3.10/inc/000077500000000000000000000000001374176322100153375ustar00rootroot00000000000000umtp-responder-1.3.10/inc/buildconf.h000066400000000000000000000006331374176322100174570ustar00rootroot00000000000000#define _LARGEFILE64_SOURCE #define _FILE_OFFSET_BITS 64 //#define CONFIG_USB_NON_BLOCKING_WRITE 1 #define CONFIG_READ_FILE_BUFFER_SIZE (1024*1024) // Must be a 2^x value. #define CONFIG_MAX_TX_USB_BUFFER_SIZE (16*512) // Must be a multiple of 512 and be less than CONFIG_READ_FILE_BUFFER_SIZE #define CONFIG_MAX_RX_USB_BUFFER_SIZE (16*512) // Must be a multiple of 512 #include "custom_buildconf.h" umtp-responder-1.3.10/inc/custom_buildconf.h000066400000000000000000000000001374176322100210350ustar00rootroot00000000000000umtp-responder-1.3.10/inc/default_cfg.h000066400000000000000000000032671374176322100177630ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file default_cfg.h * @brief default settings. * @author Jean-François DEL NERO */ #ifndef _INC_DEFAULT_CFG_H_ #define _INC_DEFAULT_CFG_H_ #ifndef UMTPR_CONF_FILE #define UMTPR_CONF_FILE "/etc/umtprd/umtprd.conf" #endif #define MAX_PACKET_SIZE 512 #define USB_DEV_VENDOR_ID 0x1D6B // Linux Foundation #define USB_DEV_PRODUCT_ID 0x0100 // PTP Gadget #define USB_DEV_CLASS 0x6 // Still Imaging device #define USB_DEV_SUBCLASS 0x1 // #define USB_DEV_PROTOCOL 0x1 // #define USB_DEV_VERSION 0x3008 #define USB_FFS_MODE 1 #define USB_DEV "/dev/ffs-umtp/ep0" #define USB_EPIN "/dev/ffs-umtp/ep1" #define USB_EPOUT "/dev/ffs-umtp/ep2" #define USB_EPINTIN "/dev/ffs-umtp/ep3" #define MANUFACTURER "Viveris Technologies" #define PRODUCT "The Viveris Product !" #define SERIALNUMBER "01234567" #endif umtp-responder-1.3.10/inc/fs_handles_db.h000066400000000000000000000061001374176322100202600ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file fs_handles_db.h * @brief Local file system helpers and handles database management. * @author Jean-François DEL NERO */ #ifndef _INC_FS_HANDLES_DB_H_ #define _INC_FS_HANDLES_DB_H_ typedef struct fs_entry fs_entry; typedef int64_t mtp_size; typedef int64_t mtp_offset; #define FS_HANDLE_MAX_FILENAME_SIZE 256 struct fs_entry { uint32_t handle; uint32_t parent; uint32_t storage_id; char * name; uint32_t flags; mtp_size size; uint32_t date; int watch_descriptor; fs_entry * next; }; #define ENTRY_IS_DIR 0x00000001 #define ENTRY_IS_DELETED 0x00000002 #define _DEF_FS_HANDLES_ 1 typedef struct fs_handles_db_ { fs_entry * entry_list; uint32_t next_handle; fs_entry * search_entry; uint32_t handle_search; uint32_t storage_search; void * mtp_ctx; }fs_handles_db; typedef struct filefoundinfo_ { int isdirectory; char filename[FS_HANDLE_MAX_FILENAME_SIZE + 1]; mtp_size size; }filefoundinfo; fs_handles_db * init_fs_db(void * mtp_ctx); void deinit_fs_db(fs_handles_db * fsh); int scan_and_add_folder(fs_handles_db * db, char * base, uint32_t parent, uint32_t storage_id); fs_entry * init_search_handle(fs_handles_db * db, uint32_t parent, uint32_t storage_id); fs_entry * get_next_child_handle(fs_handles_db * db); fs_entry * get_entry_by_handle(fs_handles_db * db, uint32_t handle); fs_entry * get_entry_by_handle_and_storageid(fs_handles_db * db, uint32_t handle, uint32_t storage_id); fs_entry * get_entry_by_wd(fs_handles_db * db, int watch_descriptor, fs_entry * entry_list); fs_entry * get_entry_by_storageid( fs_handles_db * db, uint32_t storage_id, fs_entry * entry_list ); fs_entry * add_entry(fs_handles_db * db, filefoundinfo *fileinfo, uint32_t parent, uint32_t storage_id); fs_entry * search_entry(fs_handles_db * db, filefoundinfo *fileinfo, uint32_t parent, uint32_t storage_id); fs_entry * alloc_root_entry(fs_handles_db * db, uint32_t storage_id); int entry_open(fs_handles_db * db, fs_entry * entry); int entry_read(fs_handles_db * db, int file, unsigned char * buffer_out, mtp_offset offset, mtp_size size); void entry_close(int file); char * build_full_path(fs_handles_db * db,char * root_path,fs_entry * entry); int fs_remove_tree( char *folder ); int fs_entry_stat(char *path, filefoundinfo* fileinfo); #endif umtp-responder-1.3.10/inc/inotify.h000066400000000000000000000003131374176322100171660ustar00rootroot00000000000000int inotify_handler_init( mtp_ctx * ctx ); int inotify_handler_deinit( mtp_ctx * ctx ); int inotify_handler_addwatch( mtp_ctx * ctx, char * path ); int inotify_handler_rmwatch( mtp_ctx * ctx, int wd ); umtp-responder-1.3.10/inc/logs_out.h000066400000000000000000000103431374176322100173440ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file logs_out.h * @brief Log output functions * @author Jean-François DEL NERO */ #ifndef _INC_DEBUG_OUT_H_ #define _INC_DEBUG_OUT_H_ void timestamp(char * timestr, int maxsize); #define SIZEHEX PRIx64 #ifdef USE_SYSLOG #include #else #ifdef DEBUG #include #endif #endif #ifdef USE_SYSLOG // Syslog usage #define PRINT_MSG(fmt, args...) syslog(LOG_NOTICE, "[uMTPrd - Info] " fmt "\n", \ ## args) #define PRINT_ERROR(fmt, args...) syslog(LOG_ERR, "[uMTPrd - Error] " fmt "\n", \ ## args) #define PRINT_WARN(fmt, args...) syslog(LOG_WARNING, "[uMTPrd - Warning] " fmt "\n", \ ## args) #ifdef DEBUG #define PRINT_DEBUG(fmt, args...) syslog(LOG_DEBUG, "[uMTPrd - Debug] " fmt "\n", \ ## args) #else #define PRINT_DEBUG(fmt, args...) #endif #else // Stdout usage #define PRINT_MSG(fmt, args...) { \ char timestr[32]; \ timestamp((char*)×tr, sizeof(timestr)); \ fprintf(stdout, \ "[uMTPrd - %s - Info] " fmt "\n",(char*)×tr, \ ## args); \ fflush(stdout); \ } #define PRINT_ERROR(fmt, args...) { \ char timestr[32]; \ timestamp((char*)×tr, sizeof(timestr)); \ fprintf(stderr, \ "[uMTPrd - %s - Error] " fmt "\n",(char*)×tr, \ ## args); \ fflush(stderr); \ } #define PRINT_WARN(fmt, args...) { \ char timestr[32]; \ timestamp((char*)×tr, sizeof(timestr)); \ fprintf(stdout, \ "[uMTPrd - %s - Warning] " fmt "\n",(char*)×tr, \ ## args); \ fflush(stdout); \ } #ifdef DEBUG #define PRINT_DEBUG(fmt, args...) { \ char timestr[32]; \ timestamp((char*)×tr, sizeof(timestr)); \ fprintf(stdout, \ "[uMTPrd - %s - Debug] " fmt "\n",(char*)×tr, \ ## args); \ fflush(stdout); \ } #else #define PRINT_DEBUG(fmt, args...) #endif #endif #ifdef DEBUG #define PRINT_DEBUG_BUF(x, y) printbuf( x, y ); void printbuf(void * buf,int size); #else #define PRINT_DEBUG_BUF(x, y) #endif #endif umtp-responder-1.3.10/inc/msgqueue.h000066400000000000000000000002051374176322100173400ustar00rootroot00000000000000int msgqueue_handler_init( mtp_ctx * ctx ); int msgqueue_handler_deinit( mtp_ctx * ctx ); int send_message_queue( char * message ); umtp-responder-1.3.10/inc/mtp.h000066400000000000000000000104001374176322100163030ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp.h * @brief Main MTP protocol functions. * @author Jean-François DEL NERO */ #ifndef _INC_MTP_H_ #define _INC_MTP_H_ #define MAX_STORAGE_NB 16 #define MAX_CFG_STRING_SIZE 512 #pragma pack(1) typedef struct _MTP_PACKET_HEADER { uint32_t length; uint16_t operation; uint16_t code; uint32_t tx_id; }MTP_PACKET_HEADER; #pragma pack() #include "fs_handles_db.h" typedef struct mtp_usb_cfg_ { uint16_t usb_vendor_id; uint16_t usb_product_id; uint8_t usb_class; uint8_t usb_subclass; uint8_t usb_protocol; uint16_t usb_dev_version; uint16_t usb_max_packet_size; uint8_t usb_functionfs_mode; char usb_device_path[MAX_CFG_STRING_SIZE + 1]; char usb_endpoint_in[MAX_CFG_STRING_SIZE + 1]; char usb_endpoint_out[MAX_CFG_STRING_SIZE + 1]; char usb_endpoint_intin[MAX_CFG_STRING_SIZE + 1]; char usb_string_manufacturer[MAX_CFG_STRING_SIZE + 1]; char usb_string_product[MAX_CFG_STRING_SIZE + 1]; char usb_string_serial[MAX_CFG_STRING_SIZE + 1]; char usb_string_version[MAX_CFG_STRING_SIZE + 1]; char usb_string_interface[MAX_CFG_STRING_SIZE + 1]; int wait_connection; int loop_on_disconnect; int show_hidden_files; int val_umask; }mtp_usb_cfg; typedef struct mtp_storage_ { char * root_path; char * description; uint32_t storage_id; uint32_t flags; }mtp_storage; #define UMTP_STORAGE_NOTMOUNTED 0x00000002 #define UMTP_STORAGE_READONLY 0x00000001 #define UMTP_STORAGE_READWRITE 0x00000000 typedef struct mtp_ctx_ { uint32_t session_id; mtp_usb_cfg usb_cfg; void * usb_ctx; unsigned char * wrbuffer; int usb_wr_buffer_max_size; unsigned char * rdbuffer; unsigned char * rdbuffer2; int usb_rd_buffer_max_size; unsigned char * read_file_buffer; int read_file_buffer_size; uint32_t *temp_array; fs_handles_db * fs_db; uint32_t SendObjInfoHandle; mtp_size SendObjInfoSize; mtp_offset SendObjInfoOffset; uint32_t SetObjectPropValue_Handle; uint32_t SetObjectPropValue_PropCode; uint32_t max_packet_size; mtp_storage storages[MAX_STORAGE_NB]; int inotify_fd; pthread_t inotify_thread; pthread_mutex_t inotify_mutex; int msgqueue_id; pthread_t msgqueue_thread; int no_inotify; volatile int cancel_req; volatile int transferring_file_data; }mtp_ctx; mtp_ctx * mtp_init_responder(); int mtp_incoming_packet(mtp_ctx * ctx); void mtp_set_usb_handle(mtp_ctx * ctx, void * handle, uint32_t max_packet_size); int mtp_load_config_file(mtp_ctx * context, const char * conffile); uint32_t mtp_add_storage(mtp_ctx * ctx, char * path, char * description, uint32_t flags); int mtp_get_storage_index_by_name(mtp_ctx * ctx, char * name); uint32_t mtp_get_storage_id_by_name(mtp_ctx * ctx, char * name); char * mtp_get_storage_description(mtp_ctx * ctx, uint32_t storage_id); char * mtp_get_storage_root(mtp_ctx * ctx, uint32_t storage_id); uint32_t mtp_get_storage_flags(mtp_ctx * ctx, uint32_t storage_id); int check_handle_access( mtp_ctx * ctx, fs_entry * entry, uint32_t handle, int wraccess, uint32_t * response); int mtp_push_event(mtp_ctx * ctx, uint32_t event, int nbparams, uint32_t * parameters ); void mtp_deinit_responder(mtp_ctx * ctx); int build_response(mtp_ctx * ctx, uint32_t tx_id, uint16_t type, uint16_t status, void * buffer, int maxsize, void * datain,int size); int check_and_send_USB_ZLP(mtp_ctx * ctx , int size); int parse_incomming_dataset(mtp_ctx * ctx,void * datain,int size,uint32_t * newhandle, uint32_t parent_handle, uint32_t storage_id); #define APP_VERSION "v1.3.10" #endif umtp-responder-1.3.10/inc/mtp_cfg.h000066400000000000000000000020251374176322100171260ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_cfg.c * @brief Configuration file parsing. * @author Jean-François DEL NERO */ #ifndef _INC_MTP_CFG_H_ #include "mtp.h" int mtp_create_storage(mtp_ctx * context); #endif umtp-responder-1.3.10/inc/mtp_constant.h000066400000000000000000000761031374176322100202300ustar00rootroot00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _INC_MTP_CONSTANT_H_ #define _INC_MTP_CONSTANT_H_ #include #include #define MTP_STANDARD_VERSION 100 // Container Types #define MTP_CONTAINER_TYPE_UNDEFINED 0 #define MTP_CONTAINER_TYPE_COMMAND 1 #define MTP_CONTAINER_TYPE_DATA 2 #define MTP_CONTAINER_TYPE_RESPONSE 3 #define MTP_CONTAINER_TYPE_EVENT 4 // Container Offsets #define MTP_CONTAINER_LENGTH_OFFSET 0 #define MTP_CONTAINER_TYPE_OFFSET 4 #define MTP_CONTAINER_CODE_OFFSET 6 #define MTP_CONTAINER_TRANSACTION_ID_OFFSET 8 #define MTP_CONTAINER_PARAMETER_OFFSET 12 #define MTP_CONTAINER_HEADER_SIZE 12 // Maximum buffer size for a MTP packet. #define MTP_BUFFER_SIZE 16384 // MTP Data Types #define MTP_TYPE_UNDEFINED 0x0000 // Undefined #define MTP_TYPE_INT8 0x0001 // Signed 8-bit integer #define MTP_TYPE_UINT8 0x0002 // Unsigned 8-bit integer #define MTP_TYPE_INT16 0x0003 // Signed 16-bit integer #define MTP_TYPE_UINT16 0x0004 // Unsigned 16-bit integer #define MTP_TYPE_INT32 0x0005 // Signed 32-bit integer #define MTP_TYPE_UINT32 0x0006 // Unsigned 32-bit integer #define MTP_TYPE_INT64 0x0007 // Signed 64-bit integer #define MTP_TYPE_UINT64 0x0008 // Unsigned 64-bit integer #define MTP_TYPE_INT128 0x0009 // Signed 128-bit integer #define MTP_TYPE_UINT128 0x000A // Unsigned 128-bit integer #define MTP_TYPE_AINT8 0x4001 // Array of signed 8-bit integers #define MTP_TYPE_AUINT8 0x4002 // Array of unsigned 8-bit integers #define MTP_TYPE_AINT16 0x4003 // Array of signed 16-bit integers #define MTP_TYPE_AUINT16 0x4004 // Array of unsigned 16-bit integers #define MTP_TYPE_AINT32 0x4005 // Array of signed 32-bit integers #define MTP_TYPE_AUINT32 0x4006 // Array of unsigned 32-bit integers #define MTP_TYPE_AINT64 0x4007 // Array of signed 64-bit integers #define MTP_TYPE_AUINT64 0x4008 // Array of unsigned 64-bit integers #define MTP_TYPE_AINT128 0x4009 // Array of signed 128-bit integers #define MTP_TYPE_AUINT128 0x400A // Array of unsigned 128-bit integers #define MTP_TYPE_STR 0xFFFF // Variable-length Unicode string // MTP Format Codes #define MTP_FORMAT_UNDEFINED 0x3000 // Undefined object #define MTP_FORMAT_ASSOCIATION 0x3001 // Association (for example, a folder) #define MTP_FORMAT_SCRIPT 0x3002 // Device model-specific script #define MTP_FORMAT_EXECUTABLE 0x3003 // Device model-specific binary executable #define MTP_FORMAT_TEXT 0x3004 // Text file #define MTP_FORMAT_HTML 0x3005 // Hypertext Markup Language file (text) #define MTP_FORMAT_DPOF 0x3006 // Digital Print Order Format file (text) #define MTP_FORMAT_AIFF 0x3007 // Audio clip #define MTP_FORMAT_WAV 0x3008 // Audio clip #define MTP_FORMAT_MP3 0x3009 // Audio clip #define MTP_FORMAT_AVI 0x300A // Video clip #define MTP_FORMAT_MPEG 0x300B // Video clip #define MTP_FORMAT_ASF 0x300C // Microsoft Advanced Streaming Format (video) #define MTP_FORMAT_DEFINED 0x3800 // Unknown image object #define MTP_FORMAT_EXIF_JPEG 0x3801 // Exchangeable File Format, JEIDA standard #define MTP_FORMAT_TIFF_EP 0x3802 // Tag Image File Format for Electronic Photography #define MTP_FORMAT_FLASHPIX 0x3803 // Structured Storage Image Format #define MTP_FORMAT_BMP 0x3804 // Microsoft Windows Bitmap file #define MTP_FORMAT_CIFF 0x3805 // Canon Camera Image File Format #define MTP_FORMAT_GIF 0x3807 // Graphics Interchange Format #define MTP_FORMAT_JFIF 0x3808 // JPEG File Interchange Format #define MTP_FORMAT_CD 0x3809 // PhotoCD Image Pac #define MTP_FORMAT_PICT 0x380A // Quickdraw Image Format #define MTP_FORMAT_PNG 0x380B // Portable Network Graphics #define MTP_FORMAT_TIFF 0x380D // Tag Image File Format #define MTP_FORMAT_TIFF_IT 0x380E // Tag Image File Format for Information Technology (graphic arts) #define MTP_FORMAT_JP2 0x380F // JPEG2000 Baseline File Format #define MTP_FORMAT_JPX 0x3810 // JPEG2000 Extended File Format #define MTP_FORMAT_DNG 0x3811 // Digital Negative #define MTP_FORMAT_HEIF 0x3812 // HEIF images #define MTP_FORMAT_UNDEFINED_FIRMWARE 0xB802 #define MTP_FORMAT_WINDOWS_IMAGE_FORMAT 0xB881 #define MTP_FORMAT_UNDEFINED_AUDIO 0xB900 #define MTP_FORMAT_WMA 0xB901 #define MTP_FORMAT_OGG 0xB902 #define MTP_FORMAT_AAC 0xB903 #define MTP_FORMAT_AUDIBLE 0xB904 #define MTP_FORMAT_FLAC 0xB906 #define MTP_FORMAT_UNDEFINED_VIDEO 0xB980 #define MTP_FORMAT_WMV 0xB981 #define MTP_FORMAT_MP4_CONTAINER 0xB982 // ISO 14496-1 #define MTP_FORMAT_MP2 0xB983 #define MTP_FORMAT_3GP_CONTAINER 0xB984 // 3GPP file format. Details: http://www.3gpp.org/ftp/Specs/html-info/26244.htm (page title - \u201cTransparent end-to-end packet switched streaming service, 3GPP file format\u201d). #define MTP_FORMAT_UNDEFINED_COLLECTION 0xBA00 #define MTP_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM 0xBA01 #define MTP_FORMAT_ABSTRACT_IMAGE_ALBUM 0xBA02 #define MTP_FORMAT_ABSTRACT_AUDIO_ALBUM 0xBA03 #define MTP_FORMAT_ABSTRACT_VIDEO_ALBUM 0xBA04 #define MTP_FORMAT_ABSTRACT_AV_PLAYLIST 0xBA05 #define MTP_FORMAT_ABSTRACT_CONTACT_GROUP 0xBA06 #define MTP_FORMAT_ABSTRACT_MESSAGE_FOLDER 0xBA07 #define MTP_FORMAT_ABSTRACT_CHAPTERED_PRODUCTION 0xBA08 #define MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST 0xBA09 #define MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST 0xBA0A #define MTP_FORMAT_ABSTRACT_MEDIACAST 0xBA0B // For use with mediacasts; references multimedia enclosures of RSS feeds or episodic content #define MTP_FORMAT_WPL_PLAYLIST 0xBA10 #define MTP_FORMAT_M3U_PLAYLIST 0xBA11 #define MTP_FORMAT_MPL_PLAYLIST 0xBA12 #define MTP_FORMAT_ASX_PLAYLIST 0xBA13 #define MTP_FORMAT_PLS_PLAYLIST 0xBA14 #define MTP_FORMAT_UNDEFINED_DOCUMENT 0xBA80 #define MTP_FORMAT_ABSTRACT_DOCUMENT 0xBA81 #define MTP_FORMAT_XML_DOCUMENT 0xBA82 #define MTP_FORMAT_MS_WORD_DOCUMENT 0xBA83 #define MTP_FORMAT_MHT_COMPILED_HTML_DOCUMENT 0xBA84 #define MTP_FORMAT_MS_EXCEL_SPREADSHEET 0xBA85 #define MTP_FORMAT_MS_POWERPOINT_PRESENTATION 0xBA86 #define MTP_FORMAT_UNDEFINED_MESSAGE 0xBB00 #define MTP_FORMAT_ABSTRACT_MESSSAGE 0xBB01 #define MTP_FORMAT_UNDEFINED_CONTACT 0xBB80 #define MTP_FORMAT_ABSTRACT_CONTACT 0xBB81 #define MTP_FORMAT_VCARD_2 0xBB82 // MTP Object Property Codes #define MTP_PROPERTY_STORAGE_ID 0xDC01 #define MTP_PROPERTY_OBJECT_FORMAT 0xDC02 #define MTP_PROPERTY_PROTECTION_STATUS 0xDC03 #define MTP_PROPERTY_OBJECT_SIZE 0xDC04 #define MTP_PROPERTY_ASSOCIATION_TYPE 0xDC05 #define MTP_PROPERTY_ASSOCIATION_DESC 0xDC06 #define MTP_PROPERTY_OBJECT_FILE_NAME 0xDC07 #define MTP_PROPERTY_DATE_CREATED 0xDC08 #define MTP_PROPERTY_DATE_MODIFIED 0xDC09 #define MTP_PROPERTY_KEYWORDS 0xDC0A #define MTP_PROPERTY_PARENT_OBJECT 0xDC0B #define MTP_PROPERTY_ALLOWED_FOLDER_CONTENTS 0xDC0C #define MTP_PROPERTY_HIDDEN 0xDC0D #define MTP_PROPERTY_SYSTEM_OBJECT 0xDC0E #define MTP_PROPERTY_PERSISTENT_UID 0xDC41 #define MTP_PROPERTY_SYNC_ID 0xDC42 #define MTP_PROPERTY_PROPERTY_BAG 0xDC43 #define MTP_PROPERTY_NAME 0xDC44 #define MTP_PROPERTY_CREATED_BY 0xDC45 #define MTP_PROPERTY_ARTIST 0xDC46 #define MTP_PROPERTY_DATE_AUTHORED 0xDC47 #define MTP_PROPERTY_DESCRIPTION 0xDC48 #define MTP_PROPERTY_URL_REFERENCE 0xDC49 #define MTP_PROPERTY_LANGUAGE_LOCALE 0xDC4A #define MTP_PROPERTY_COPYRIGHT_INFORMATION 0xDC4B #define MTP_PROPERTY_SOURCE 0xDC4C #define MTP_PROPERTY_ORIGIN_LOCATION 0xDC4D #define MTP_PROPERTY_DATE_ADDED 0xDC4E #define MTP_PROPERTY_NON_CONSUMABLE 0xDC4F #define MTP_PROPERTY_CORRUPT_UNPLAYABLE 0xDC50 #define MTP_PROPERTY_PRODUCER_SERIAL_NUMBER 0xDC51 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_FORMAT 0xDC81 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_SIZE 0xDC82 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_HEIGHT 0xDC83 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_WIDTH 0xDC84 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DURATION 0xDC85 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DATA 0xDC86 #define MTP_PROPERTY_WIDTH 0xDC87 #define MTP_PROPERTY_HEIGHT 0xDC88 #define MTP_PROPERTY_DURATION 0xDC89 #define MTP_PROPERTY_RATING 0xDC8A #define MTP_PROPERTY_TRACK 0xDC8B #define MTP_PROPERTY_GENRE 0xDC8C #define MTP_PROPERTY_CREDITS 0xDC8D #define MTP_PROPERTY_LYRICS 0xDC8E #define MTP_PROPERTY_SUBSCRIPTION_CONTENT_ID 0xDC8F #define MTP_PROPERTY_PRODUCED_BY 0xDC90 #define MTP_PROPERTY_USE_COUNT 0xDC91 #define MTP_PROPERTY_SKIP_COUNT 0xDC92 #define MTP_PROPERTY_LAST_ACCESSED 0xDC93 #define MTP_PROPERTY_PARENTAL_RATING 0xDC94 #define MTP_PROPERTY_META_GENRE 0xDC95 #define MTP_PROPERTY_COMPOSER 0xDC96 #define MTP_PROPERTY_EFFECTIVE_RATING 0xDC97 #define MTP_PROPERTY_SUBTITLE 0xDC98 #define MTP_PROPERTY_ORIGINAL_RELEASE_DATE 0xDC99 #define MTP_PROPERTY_ALBUM_NAME 0xDC9A #define MTP_PROPERTY_ALBUM_ARTIST 0xDC9B #define MTP_PROPERTY_MOOD 0xDC9C #define MTP_PROPERTY_DRM_STATUS 0xDC9D #define MTP_PROPERTY_SUB_DESCRIPTION 0xDC9E #define MTP_PROPERTY_IS_CROPPED 0xDCD1 #define MTP_PROPERTY_IS_COLOUR_CORRECTED 0xDCD2 #define MTP_PROPERTY_IMAGE_BIT_DEPTH 0xDCD3 #define MTP_PROPERTY_F_NUMBER 0xDCD4 #define MTP_PROPERTY_EXPOSURE_TIME 0xDCD5 #define MTP_PROPERTY_EXPOSURE_INDEX 0xDCD6 #define MTP_PROPERTY_TOTAL_BITRATE 0xDE91 #define MTP_PROPERTY_BITRATE_TYPE 0xDE92 #define MTP_PROPERTY_SAMPLE_RATE 0xDE93 #define MTP_PROPERTY_NUMBER_OF_CHANNELS 0xDE94 #define MTP_PROPERTY_AUDIO_BIT_DEPTH 0xDE95 #define MTP_PROPERTY_SCAN_TYPE 0xDE97 #define MTP_PROPERTY_AUDIO_WAVE_CODEC 0xDE99 #define MTP_PROPERTY_AUDIO_BITRATE 0xDE9A #define MTP_PROPERTY_VIDEO_FOURCC_CODEC 0xDE9B #define MTP_PROPERTY_VIDEO_BITRATE 0xDE9C #define MTP_PROPERTY_FRAMES_PER_THOUSAND_SECONDS 0xDE9D #define MTP_PROPERTY_KEYFRAME_DISTANCE 0xDE9E #define MTP_PROPERTY_BUFFER_SIZE 0xDE9F #define MTP_PROPERTY_ENCODING_QUALITY 0xDEA0 #define MTP_PROPERTY_ENCODING_PROFILE 0xDEA1 #define MTP_PROPERTY_DISPLAY_NAME 0xDCE0 #define MTP_PROPERTY_BODY_TEXT 0xDCE1 #define MTP_PROPERTY_SUBJECT 0xDCE2 #define MTP_PROPERTY_PRIORITY 0xDCE3 #define MTP_PROPERTY_GIVEN_NAME 0xDD00 #define MTP_PROPERTY_MIDDLE_NAMES 0xDD01 #define MTP_PROPERTY_FAMILY_NAME 0xDD02 #define MTP_PROPERTY_PREFIX 0xDD03 #define MTP_PROPERTY_SUFFIX 0xDD04 #define MTP_PROPERTY_PHONETIC_GIVEN_NAME 0xDD05 #define MTP_PROPERTY_PHONETIC_FAMILY_NAME 0xDD06 #define MTP_PROPERTY_EMAIL_PRIMARY 0xDD07 #define MTP_PROPERTY_EMAIL_PERSONAL_1 0xDD08 #define MTP_PROPERTY_EMAIL_PERSONAL_2 0xDD09 #define MTP_PROPERTY_EMAIL_BUSINESS_1 0xDD0A #define MTP_PROPERTY_EMAIL_BUSINESS_2 0xDD0B #define MTP_PROPERTY_EMAIL_OTHERS 0xDD0C #define MTP_PROPERTY_PHONE_NUMBER_PRIMARY 0xDD0D #define MTP_PROPERTY_PHONE_NUMBER_PERSONAL 0xDD0E #define MTP_PROPERTY_PHONE_NUMBER_PERSONAL_2 0xDD0F #define MTP_PROPERTY_PHONE_NUMBER_BUSINESS 0xDD10 #define MTP_PROPERTY_PHONE_NUMBER_BUSINESS_2 0xDD11 #define MTP_PROPERTY_PHONE_NUMBER_MOBILE 0xDD12 #define MTP_PROPERTY_PHONE_NUMBER_MOBILE_2 0xDD13 #define MTP_PROPERTY_FAX_NUMBER_PRIMARY 0xDD14 #define MTP_PROPERTY_FAX_NUMBER_PERSONAL 0xDD15 #define MTP_PROPERTY_FAX_NUMBER_BUSINESS 0xDD16 #define MTP_PROPERTY_PAGER_NUMBER 0xDD17 #define MTP_PROPERTY_PHONE_NUMBER_OTHERS 0xDD18 #define MTP_PROPERTY_PRIMARY_WEB_ADDRESS 0xDD19 #define MTP_PROPERTY_PERSONAL_WEB_ADDRESS 0xDD1A #define MTP_PROPERTY_BUSINESS_WEB_ADDRESS 0xDD1B #define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS 0xDD1C #define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_2 0xDD1D #define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_3 0xDD1E #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_FULL 0xDD1F #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_1 0xDD20 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_2 0xDD21 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_CITY 0xDD22 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_REGION 0xDD23 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_POSTAL_CODE 0xDD24 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_COUNTRY 0xDD25 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_FULL 0xDD26 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_1 0xDD27 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_2 0xDD28 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_CITY 0xDD29 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_REGION 0xDD2A #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_POSTAL_CODE 0xDD2B #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_COUNTRY 0xDD2C #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_FULL 0xDD2D #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_1 0xDD2E #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_2 0xDD2F #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_CITY 0xDD30 #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_REGION 0xDD31 #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_POSTAL_CODE 0xDD32 #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_COUNTRY 0xDD33 #define MTP_PROPERTY_ORGANIZATION_NAME 0xDD34 #define MTP_PROPERTY_PHONETIC_ORGANIZATION_NAME 0xDD35 #define MTP_PROPERTY_ROLE 0xDD36 #define MTP_PROPERTY_BIRTHDATE 0xDD37 #define MTP_PROPERTY_MESSAGE_TO 0xDD40 #define MTP_PROPERTY_MESSAGE_CC 0xDD41 #define MTP_PROPERTY_MESSAGE_BCC 0xDD42 #define MTP_PROPERTY_MESSAGE_READ 0xDD43 #define MTP_PROPERTY_MESSAGE_RECEIVED_TIME 0xDD44 #define MTP_PROPERTY_MESSAGE_SENDER 0xDD45 #define MTP_PROPERTY_ACTIVITY_BEGIN_TIME 0xDD50 #define MTP_PROPERTY_ACTIVITY_END_TIME 0xDD51 #define MTP_PROPERTY_ACTIVITY_LOCATION 0xDD52 #define MTP_PROPERTY_ACTIVITY_REQUIRED_ATTENDEES 0xDD54 #define MTP_PROPERTY_ACTIVITY_OPTIONAL_ATTENDEES 0xDD55 #define MTP_PROPERTY_ACTIVITY_RESOURCES 0xDD56 #define MTP_PROPERTY_ACTIVITY_ACCEPTED 0xDD57 #define MTP_PROPERTY_ACTIVITY_TENTATIVE 0xDD58 #define MTP_PROPERTY_ACTIVITY_DECLINED 0xDD59 #define MTP_PROPERTY_ACTIVITY_REMAINDER_TIME 0xDD5A #define MTP_PROPERTY_ACTIVITY_OWNER 0xDD5B #define MTP_PROPERTY_ACTIVITY_STATUS 0xDD5C #define MTP_PROPERTY_OWNER 0xDD5D #define MTP_PROPERTY_EDITOR 0xDD5E #define MTP_PROPERTY_WEBMASTER 0xDD5F #define MTP_PROPERTY_URL_SOURCE 0xDD60 #define MTP_PROPERTY_URL_DESTINATION 0xDD61 #define MTP_PROPERTY_TIME_BOOKMARK 0xDD62 #define MTP_PROPERTY_OBJECT_BOOKMARK 0xDD63 #define MTP_PROPERTY_BYTE_BOOKMARK 0xDD64 #define MTP_PROPERTY_LAST_BUILD_DATE 0xDD70 #define MTP_PROPERTY_TIME_TO_LIVE 0xDD71 #define MTP_PROPERTY_MEDIA_GUID 0xDD72 // MTP Device Property Codes #define MTP_DEVICE_PROPERTY_UNDEFINED 0x5000 #define MTP_DEVICE_PROPERTY_BATTERY_LEVEL 0x5001 #define MTP_DEVICE_PROPERTY_FUNCTIONAL_MODE 0x5002 #define MTP_DEVICE_PROPERTY_IMAGE_SIZE 0x5003 #define MTP_DEVICE_PROPERTY_COMPRESSION_SETTING 0x5004 #define MTP_DEVICE_PROPERTY_WHITE_BALANCE 0x5005 #define MTP_DEVICE_PROPERTY_RGB_GAIN 0x5006 #define MTP_DEVICE_PROPERTY_F_NUMBER 0x5007 #define MTP_DEVICE_PROPERTY_FOCAL_LENGTH 0x5008 #define MTP_DEVICE_PROPERTY_FOCUS_DISTANCE 0x5009 #define MTP_DEVICE_PROPERTY_FOCUS_MODE 0x500A #define MTP_DEVICE_PROPERTY_EXPOSURE_METERING_MODE 0x500B #define MTP_DEVICE_PROPERTY_FLASH_MODE 0x500C #define MTP_DEVICE_PROPERTY_EXPOSURE_TIME 0x500D #define MTP_DEVICE_PROPERTY_EXPOSURE_PROGRAM_MODE 0x500E #define MTP_DEVICE_PROPERTY_EXPOSURE_INDEX 0x500F #define MTP_DEVICE_PROPERTY_EXPOSURE_BIAS_COMPENSATION 0x5010 #define MTP_DEVICE_PROPERTY_DATETIME 0x5011 #define MTP_DEVICE_PROPERTY_CAPTURE_DELAY 0x5012 #define MTP_DEVICE_PROPERTY_STILL_CAPTURE_MODE 0x5013 #define MTP_DEVICE_PROPERTY_CONTRAST 0x5014 #define MTP_DEVICE_PROPERTY_SHARPNESS 0x5015 #define MTP_DEVICE_PROPERTY_DIGITAL_ZOOM 0x5016 #define MTP_DEVICE_PROPERTY_EFFECT_MODE 0x5017 #define MTP_DEVICE_PROPERTY_BURST_NUMBER 0x5018 #define MTP_DEVICE_PROPERTY_BURST_INTERVAL 0x5019 #define MTP_DEVICE_PROPERTY_TIMELAPSE_NUMBER 0x501A #define MTP_DEVICE_PROPERTY_TIMELAPSE_INTERVAL 0x501B #define MTP_DEVICE_PROPERTY_FOCUS_METERING_MODE 0x501C #define MTP_DEVICE_PROPERTY_UPLOAD_URL 0x501D #define MTP_DEVICE_PROPERTY_ARTIST 0x501E #define MTP_DEVICE_PROPERTY_COPYRIGHT_INFO 0x501F #define MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER 0xD401 #define MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME 0xD402 #define MTP_DEVICE_PROPERTY_VOLUME 0xD403 #define MTP_DEVICE_PROPERTY_SUPPORTED_FORMATS_ORDERED 0xD404 #define MTP_DEVICE_PROPERTY_DEVICE_ICON 0xD405 #define MTP_DEVICE_PROPERTY_PLAYBACK_RATE 0xD410 #define MTP_DEVICE_PROPERTY_PLAYBACK_OBJECT 0xD411 #define MTP_DEVICE_PROPERTY_PLAYBACK_CONTAINER_INDEX 0xD412 #define MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO 0xD406 #define MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE 0xD407 // MTP Operation Codes #define MTP_OPERATION_GET_DEVICE_INFO 0x1001 #define MTP_OPERATION_OPEN_SESSION 0x1002 #define MTP_OPERATION_CLOSE_SESSION 0x1003 #define MTP_OPERATION_GET_STORAGE_IDS 0x1004 #define MTP_OPERATION_GET_STORAGE_INFO 0x1005 #define MTP_OPERATION_GET_NUM_OBJECTS 0x1006 #define MTP_OPERATION_GET_OBJECT_HANDLES 0x1007 #define MTP_OPERATION_GET_OBJECT_INFO 0x1008 #define MTP_OPERATION_GET_OBJECT 0x1009 #define MTP_OPERATION_GET_THUMB 0x100A #define MTP_OPERATION_DELETE_OBJECT 0x100B #define MTP_OPERATION_SEND_OBJECT_INFO 0x100C #define MTP_OPERATION_SEND_OBJECT 0x100D #define MTP_OPERATION_INITIATE_CAPTURE 0x100E #define MTP_OPERATION_FORMAT_STORE 0x100F #define MTP_OPERATION_RESET_DEVICE 0x1010 #define MTP_OPERATION_SELF_TEST 0x1011 #define MTP_OPERATION_SET_OBJECT_PROTECTION 0x1012 #define MTP_OPERATION_POWER_DOWN 0x1013 #define MTP_OPERATION_GET_DEVICE_PROP_DESC 0x1014 #define MTP_OPERATION_GET_DEVICE_PROP_VALUE 0x1015 #define MTP_OPERATION_SET_DEVICE_PROP_VALUE 0x1016 #define MTP_OPERATION_RESET_DEVICE_PROP_VALUE 0x1017 #define MTP_OPERATION_TERMINATE_OPEN_CAPTURE 0x1018 #define MTP_OPERATION_MOVE_OBJECT 0x1019 #define MTP_OPERATION_COPY_OBJECT 0x101A #define MTP_OPERATION_GET_PARTIAL_OBJECT 0x101B #define MTP_OPERATION_INITIATE_OPEN_CAPTURE 0x101C #define MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED 0x9801 #define MTP_OPERATION_GET_OBJECT_PROP_DESC 0x9802 #define MTP_OPERATION_GET_OBJECT_PROP_VALUE 0x9803 #define MTP_OPERATION_SET_OBJECT_PROP_VALUE 0x9804 #define MTP_OPERATION_GET_OBJECT_PROP_LIST 0x9805 #define MTP_OPERATION_SET_OBJECT_PROP_LIST 0x9806 #define MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC 0x9807 #define MTP_OPERATION_SEND_OBJECT_PROP_LIST 0x9808 #define MTP_OPERATION_GET_OBJECT_REFERENCES 0x9810 #define MTP_OPERATION_SET_OBJECT_REFERENCES 0x9811 #define MTP_OPERATION_SKIP 0x9820 // Android extensions for direct file IO // Same as GetPartialObject, but with 64 bit offset #define MTP_OPERATION_GET_PARTIAL_OBJECT_64 0x95C1 // Same as GetPartialObject64, but copying host to device #define MTP_OPERATION_SEND_PARTIAL_OBJECT 0x95C2 // Truncates file to 64 bit length #define MTP_OPERATION_TRUNCATE_OBJECT 0x95C3 // Must be called before using SendPartialObject and TruncateObject #define MTP_OPERATION_BEGIN_EDIT_OBJECT 0x95C4 // Called to commit changes made by SendPartialObject and TruncateObject #define MTP_OPERATION_END_EDIT_OBJECT 0x95C5 // MTP Response Codes #define MTP_RESPONSE_UNDEFINED 0x2000 #define MTP_RESPONSE_OK 0x2001 #define MTP_RESPONSE_GENERAL_ERROR 0x2002 #define MTP_RESPONSE_SESSION_NOT_OPEN 0x2003 #define MTP_RESPONSE_INVALID_TRANSACTION_ID 0x2004 #define MTP_RESPONSE_OPERATION_NOT_SUPPORTED 0x2005 #define MTP_RESPONSE_PARAMETER_NOT_SUPPORTED 0x2006 #define MTP_RESPONSE_INCOMPLETE_TRANSFER 0x2007 #define MTP_RESPONSE_INVALID_STORAGE_ID 0x2008 #define MTP_RESPONSE_INVALID_OBJECT_HANDLE 0x2009 #define MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED 0x200A #define MTP_RESPONSE_INVALID_OBJECT_FORMAT_CODE 0x200B #define MTP_RESPONSE_STORAGE_FULL 0x200C #define MTP_RESPONSE_OBJECT_WRITE_PROTECTED 0x200D #define MTP_RESPONSE_STORE_READ_ONLY 0x200E #define MTP_RESPONSE_ACCESS_DENIED 0x200F #define MTP_RESPONSE_NO_THUMBNAIL_PRESENT 0x2010 #define MTP_RESPONSE_SELF_TEST_FAILED 0x2011 #define MTP_RESPONSE_PARTIAL_DELETION 0x2012 #define MTP_RESPONSE_STORE_NOT_AVAILABLE 0x2013 #define MTP_RESPONSE_SPECIFICATION_BY_FORMAT_UNSUPPORTED 0x2014 #define MTP_RESPONSE_NO_VALID_OBJECT_INFO 0x2015 #define MTP_RESPONSE_INVALID_CODE_FORMAT 0x2016 #define MTP_RESPONSE_UNKNOWN_VENDOR_CODE 0x2017 #define MTP_RESPONSE_CAPTURE_ALREADY_TERMINATED 0x2018 #define MTP_RESPONSE_DEVICE_BUSY 0x2019 #define MTP_RESPONSE_INVALID_PARENT_OBJECT 0x201A #define MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT 0x201B #define MTP_RESPONSE_INVALID_DEVICE_PROP_VALUE 0x201C #define MTP_RESPONSE_INVALID_PARAMETER 0x201D #define MTP_RESPONSE_SESSION_ALREADY_OPEN 0x201E #define MTP_RESPONSE_TRANSACTION_CANCELLED 0x201F #define MTP_RESPONSE_SPECIFICATION_OF_DESTINATION_UNSUPPORTED 0x2020 #define MTP_RESPONSE_INVALID_OBJECT_PROP_CODE 0xA801 #define MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT 0xA802 #define MTP_RESPONSE_INVALID_OBJECT_PROP_VALUE 0xA803 #define MTP_RESPONSE_INVALID_OBJECT_REFERENCE 0xA804 #define MTP_RESPONSE_GROUP_NOT_SUPPORTED 0xA805 #define MTP_RESPONSE_INVALID_DATASET 0xA806 #define MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED 0xA807 #define MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED 0xA808 #define MTP_RESPONSE_OBJECT_TOO_LARGE 0xA809 #define MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED 0xA80A #define MTP_RESPONSE_NO_RESPONSE 0xFFFF // MTP Event Codes #define MTP_EVENT_UNDEFINED 0x4000 #define MTP_EVENT_CANCEL_TRANSACTION 0x4001 #define MTP_EVENT_OBJECT_ADDED 0x4002 #define MTP_EVENT_OBJECT_REMOVED 0x4003 #define MTP_EVENT_STORE_ADDED 0x4004 #define MTP_EVENT_STORE_REMOVED 0x4005 #define MTP_EVENT_DEVICE_PROP_CHANGED 0x4006 #define MTP_EVENT_OBJECT_INFO_CHANGED 0x4007 #define MTP_EVENT_DEVICE_INFO_CHANGED 0x4008 #define MTP_EVENT_REQUEST_OBJECT_TRANSFER 0x4009 #define MTP_EVENT_STORE_FULL 0x400A #define MTP_EVENT_DEVICE_RESET 0x400B #define MTP_EVENT_STORAGE_INFO_CHANGED 0x400C #define MTP_EVENT_CAPTURE_COMPLETE 0x400D #define MTP_EVENT_UNREPORTED_STATUS 0x400E #define MTP_EVENT_OBJECT_PROP_CHANGED 0xC801 #define MTP_EVENT_OBJECT_PROP_DESC_CHANGED 0xC802 #define MTP_EVENT_OBJECT_REFERENCES_CHANGED 0xC803 // Storage Type #define MTP_STORAGE_FIXED_ROM 0x0001 #define MTP_STORAGE_REMOVABLE_ROM 0x0002 #define MTP_STORAGE_FIXED_RAM 0x0003 #define MTP_STORAGE_REMOVABLE_RAM 0x0004 // Storage File System #define MTP_STORAGE_FILESYSTEM_FLAT 0x0001 #define MTP_STORAGE_FILESYSTEM_HIERARCHICAL 0x0002 #define MTP_STORAGE_FILESYSTEM_DCF 0x0003 // Storage Access Capability #define MTP_STORAGE_READ_WRITE 0x0000 #define MTP_STORAGE_READ_ONLY_WITHOUT_DELETE 0x0001 #define MTP_STORAGE_READ_ONLY_WITH_DELETE 0x0002 // Association Type #define MTP_ASSOCIATION_TYPE_UNDEFINED 0x0000 #define MTP_ASSOCIATION_TYPE_GENERIC_FOLDER 0x0001 // MTP class reqeusts #define MTP_REQ_CANCEL 0x64 #define MTP_REQ_GET_EXT_EVENT_DATA 0x65 #define MTP_REQ_RESET 0x66 #define MTP_REQ_GET_DEVICE_STATUS 0x67 #endif // _MTP_H umtp-responder-1.3.10/inc/mtp_constant_strings.h000066400000000000000000000024121374176322100217710ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_constant_strings.h * @brief MTP Codes to string decoder (Debug purpose) * @author Jean-François DEL NERO */ #ifndef _INC_MTP_CONSTANT_STRINGS_H_ extern const char DevInfos_MTP_Extensions[]; const char * mtp_get_operation_string(uint16_t operation); const char * mtp_get_property_string(uint16_t property); const char * mtp_get_format_string(uint16_t format); const char * mtp_get_type_string(uint16_t type); #endif umtp-responder-1.3.10/inc/mtp_datasets.h000066400000000000000000000026541374176322100202070ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_datasets.h * @brief MTP datasets builders * @author Jean-François DEL NERO */ #ifndef _INC_MTP_DATASETS_H_ #define _INC_MTP_DATASETS_H_ #include "mtp.h" int build_deviceinfo_dataset(mtp_ctx * ctx,void * buffer, int maxsize); int build_storageinfo_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t storageid); int build_objectinfo_dataset(mtp_ctx * ctx, void * buffer, int maxsize,fs_entry * entry); int build_event_dataset(mtp_ctx * ctx, void * buffer, int maxsize, uint32_t event, uint32_t session, uint32_t transaction, int nbparams, uint32_t * parameters); #endif umtp-responder-1.3.10/inc/mtp_helpers.h000066400000000000000000000030451374176322100200340ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_helpers.h * @brief MTP messages creation helpers. * @author Jean-François DEL NERO */ #ifndef _INC_MTP_HELPERS_H_ #define _INC_MTP_HELPERS_H_ int poke32(void * buffer, int index, int maxsize, uint32_t data); int poke16(void * buffer, int index, int maxsize, uint16_t data); int poke08(void * buffer, int index, int maxsize, uint8_t data); uint32_t peek(void * buffer, int index, int typesize); uint64_t peek64(void * buffer, int index, int typesize); int poke_string(void * buffer, int index, int maxsize, const char *str); int poke_array(void * buffer, int index, int maxsize, int size, int elementsize, const unsigned char *bufferin,int prefixed); uint16_t posix_to_mtp_errcode(int err); #endif umtp-responder-1.3.10/inc/mtp_operations.h000066400000000000000000000101121374176322100205460ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_operations.h * @brief MTP operations * @author Jean-Franois DEL NERO */ uint32_t mtp_op_OpenSession(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_CloseSession(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetDeviceInfos(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetDevicePropDesc(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetDevicePropValue(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetStorageIDs(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetStorageInfo(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetObjectHandles(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetObjectInfo(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_SendObjectInfo(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetObjectReferences(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetObjectPropsSupported(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetObjectPropDesc(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetObjectPropList(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_SetObjectPropValue(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetObjectPropValue(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_GetPartialObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_BeginEditObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_EndEditObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_TruncateObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_DeleteObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); uint32_t mtp_op_SendObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size); umtp-responder-1.3.10/inc/mtp_ops_helpers.h000066400000000000000000000021131374176322100207100ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_ops_helpers.h * @brief mtp operations helpers * @author Jean-Franois DEL NERO */ mtp_size send_file_data( mtp_ctx * ctx, fs_entry * entry,mtp_offset offset, mtp_size maxsize ); int delete_tree(mtp_ctx * ctx,uint32_t handle); umtp-responder-1.3.10/inc/mtp_properties.h000066400000000000000000000044021374176322100205640ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_properties.h * @brief MTP properties datasets helpers * @author Jean-François DEL NERO */ #ifndef _INC_MTP_PROPERTIES_H_ #define _INC_MTP_PROPERTIES_H_ #include "mtp.h" typedef struct profile_property_ { uint16_t prop_code; uint16_t data_type; uint8_t getset; uint64_t default_value; uint32_t group_code; uint8_t form_flag; uint16_t format_id; }profile_property; typedef struct format_property_ { uint16_t format_code; uint16_t * properties; }formats_property; extern profile_property dev_properties[]; extern profile_property properties[]; extern formats_property fmt_properties[]; int build_properties_supported_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t format_id); int build_properties_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t property_id,uint32_t format_id); int build_ObjectPropValue_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t handle,uint32_t prop_code); int setObjectPropValue(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, uint32_t handle,uint32_t prop_code); int build_device_properties_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t property_id); int build_DevicePropValue_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t prop_code); int build_objectproplist_dataset(mtp_ctx * ctx, void * buffer, int maxsize,fs_entry * entry, uint32_t handle,uint32_t format_id, uint32_t prop_code, uint32_t prop_group_code, uint32_t depth); #endif umtp-responder-1.3.10/inc/mtp_support_def.h000066400000000000000000000023071374176322100207240ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_support_def.h * @brief MTP support definitions. * @author Jean-François DEL NERO */ #ifndef _INC_MTS_SUPPORT_DEF_H_ #define _INC_MTS_SUPPORT_DEF_H_ #define MTP_VERSION 100 extern const unsigned short supported_op[]; extern const int supported_op_size; extern const unsigned short supported_event[]; extern const int supported_event_size; #endif umtp-responder-1.3.10/inc/usb_gadget.h000066400000000000000000000057561374176322100176310ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file usb_gadget.c * @brief USB gadget layer * @author Jean-François DEL NERO */ #ifndef _INC_USB_GADGET_H_ #define _INC_USB_GADGET_H_ #include #include #include #include "usbstring.h" enum { EP_DESCRIPTOR_IN = 0, EP_DESCRIPTOR_OUT, EP_DESCRIPTOR_INT_IN, EP_NB_OF_DESCRIPTORS }; #define EP_INT_MODE 0x00000000 #define EP_BULK_MODE 0x00000001 #define EP_IN_DIR 0x00000000 #define EP_OUT_DIR 0x00000002 #define EP_HS_MODE 0x00000004 // Direct GadgetFS mode typedef struct _usb_cfg { uint32_t head; struct usb_config_descriptor cfg; struct usb_interface_descriptor if_desc; struct usb_endpoint_descriptor_no_audio ep_desc[3]; struct usb_config_descriptor cfg_hs; struct usb_interface_descriptor if_desc_hs; struct usb_endpoint_descriptor_no_audio ep_desc_hs[3]; struct usb_device_descriptor dev_desc; } __attribute__ ((packed)) usb_cfg; // FunctionFS mode typedef struct _usb_ffs_cfg { uint32_t magic; uint32_t length; #ifndef OLD_FUNCTIONFS_DESCRIPTORS // Kernel > v3.14 uint32_t flags; #endif uint32_t fs_count; uint32_t hs_count; struct usb_interface_descriptor if_desc; struct usb_endpoint_descriptor_no_audio ep_desc[3]; struct usb_interface_descriptor if_desc_hs; struct usb_endpoint_descriptor_no_audio ep_desc_hs[3]; } __attribute__ ((packed)) usb_ffs_cfg; typedef struct _ffs_strings { struct usb_functionfs_strings_head header; uint16_t code; char string_data[128]; // string data. } __attribute__((packed)) ffs_strings; typedef struct _ep_cfg { uint32_t head; struct usb_endpoint_descriptor_no_audio ep_desc[2]; } __attribute__ ((packed)) ep_cfg; enum { STRINGID_MANUFACTURER = 1, STRINGID_PRODUCT, STRINGID_SERIAL, STRINGID_CONFIG_HS, STRINGID_CONFIG_LS, STRINGID_INTERFACE, STRINGID_MAX }; #define MAX_USB_STRING 16 typedef struct _usb_gadget { int usb_device; usb_cfg * usb_config; usb_ffs_cfg * usb_ffs_config; ep_cfg * ep_config[3]; int ep_handles[EP_NB_OF_DESCRIPTORS]; char * ep_path[3]; int stop; struct usb_string stringtab[MAX_USB_STRING]; int wait_connection; pthread_t thread; int thread_not_started; }usb_gadget; #endif umtp-responder-1.3.10/inc/usb_gadget_fct.h000066400000000000000000000026451374176322100204570ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file usb_gadget_fct.h * @brief USB gadget / FunctionFS layer - Public functions declarations. * @author Jean-François DEL NERO */ #ifndef _INC_USB_GADGET_FCT_H_ #define _INC_USB_GADGET_FCT_H_ #include "usb_gadget.h" usb_gadget * init_usb_mtp_gadget(mtp_ctx * ctx); int read_usb(usb_gadget * ctx, unsigned char * buffer, int maxsize); int write_usb(usb_gadget * ctx, int channel, unsigned char * buffer, int size); int handle_ep0(usb_gadget * ctx); int handle_ffs_ep0(usb_gadget * ctx); int is_usb_up(usb_gadget * ctx); void deinit_usb_mtp_gadget(usb_gadget * usbctx); #endif umtp-responder-1.3.10/inc/usbstring.h000066400000000000000000000026641374176322100175400ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file usbstring.h * @brief USB strings - Function & structures declarations. * @author Jean-François DEL NERO */ #ifndef _INC_USBSTRING_H_ #define _INC_USBSTRING_H_ struct usb_string { uint8_t id; char *str; }; struct usb_gadget_strings { uint16_t language; /* 0x0409 for en-us */ struct usb_string *strings; }; int usb_gadget_get_string (struct usb_gadget_strings *table, int id, uint8_t *buf); int unicode2charstring(char * str, uint16_t * unicodestr, int maxstrsize); int char2unicodestring(char * unicodestr, int index, int maxsize, char * str, int unicodestrsize); #endif umtp-responder-1.3.10/src/000077500000000000000000000000001374176322100153555ustar00rootroot00000000000000umtp-responder-1.3.10/src/fs_handles_db.c000066400000000000000000000307211374176322100202770ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file fs_handles_db.c * @brief Local file system helpers and handles database management. * @author Jean-François DEL NERO */ #include "buildconf.h" #include #include #include #include #include #include #include #include #include #include "mtp.h" #include "fs_handles_db.h" #include "inotify.h" #include "logs_out.h" int fs_remove_tree( char *folder ) { struct dirent *d; DIR * dir; struct stat64 fileStat; char * tmpstr; int del_fail; del_fail = 0; dir = opendir (folder); if( dir ) { do { d = readdir (dir); if( d ) { tmpstr = malloc (strlen(folder) + strlen(d->d_name) + 4 ); if( tmpstr ) { strcpy(tmpstr,folder); strcat(tmpstr,"/"); strcat(tmpstr,d->d_name); memset(&fileStat,0,sizeof(struct stat64)); if( !lstat64 (tmpstr, &fileStat) ) { if ( S_ISDIR ( fileStat.st_mode ) ) { if( strcmp(d->d_name,"..") && strcmp(d->d_name,".") ) { if( fs_remove_tree(tmpstr) ) del_fail = 1; } } else { if( remove(tmpstr) ) del_fail = 1; } } free(tmpstr); } else { del_fail = 1; } } }while(d); closedir(dir); if( remove(folder) ) del_fail = 1; } else { del_fail = 1; } return del_fail; } int fs_entry_stat(char *path, filefoundinfo* fileinfo) { struct stat64 fileStat; int i; memset(&fileStat,0,sizeof(struct stat64)); if( !stat64 (path, &fileStat) ) { if ( S_ISDIR ( fileStat.st_mode ) ) fileinfo->isdirectory = 1; else fileinfo->isdirectory = 0; fileinfo->size = fileStat.st_size; i = strlen(path); while( i ) { if( path[i] == '/' ) { i++; break; } i--; } fileinfo->filename[FS_HANDLE_MAX_FILENAME_SIZE] = '\0'; strncpy(fileinfo->filename,&path[i],FS_HANDLE_MAX_FILENAME_SIZE); return 1; } return 0; } DIR * fs_find_first_file(char *folder, filefoundinfo* fileinfo) { struct dirent *d; DIR * dir; char * tmpstr; dir = opendir (folder); if( dir ) { d = readdir (dir); if( d ) { tmpstr = malloc (strlen(folder) + strlen(d->d_name) + 4 ); if( tmpstr ) { strcpy(tmpstr,folder); strcat(tmpstr,"/"); strcat(tmpstr,d->d_name); if( fs_entry_stat(tmpstr, fileinfo) ) { free(tmpstr); return (void*)dir; } free(tmpstr); } closedir(dir); dir = NULL; } closedir(dir); dir = NULL; } else { dir = NULL; } return dir; } int fs_find_next_file(DIR* dir, char *folder, filefoundinfo* fileinfo) { int ret; struct dirent *d; char * tmpstr; d = readdir (dir); ret = 0; if( d ) { tmpstr = malloc (strlen(folder) + strlen(d->d_name) + 4 ); if( tmpstr ) { strcpy(tmpstr,folder); strcat(tmpstr,"/"); strcat(tmpstr,d->d_name); if( fs_entry_stat( tmpstr, fileinfo ) ) { ret = 1; free(tmpstr); return ret; } free(tmpstr); } } return ret; } int fs_find_close(DIR* dir) { if( dir ) closedir( dir ); return 0; } fs_handles_db * init_fs_db(void * mtp_ctx) { fs_handles_db * db; PRINT_DEBUG("init_fs_db called"); db = (fs_handles_db *)malloc(sizeof(fs_handles_db)); if( db ) { memset(db,0,sizeof(fs_handles_db)); db->next_handle = 0x00000001; db->mtp_ctx = mtp_ctx; } return db; } void deinit_fs_db(fs_handles_db * fsh) { fs_entry * next_entry; PRINT_DEBUG("deinit_fs_db called"); if( fsh ) { while( fsh->entry_list ) { next_entry = fsh->entry_list->next; if( fsh->entry_list->watch_descriptor != -1 ) { // Disable the inotify watch point inotify_handler_rmwatch( fsh->mtp_ctx, fsh->entry_list->watch_descriptor ); fsh->entry_list->watch_descriptor = -1; } if( fsh->entry_list->name ) free( fsh->entry_list->name ); free( fsh->entry_list ); fsh->entry_list = next_entry; } free(fsh); } return; } fs_entry * search_entry(fs_handles_db * db, filefoundinfo *fileinfo, uint32_t parent, uint32_t storage_id) { fs_entry * entry_list; entry_list = db->entry_list; while( entry_list ) { if( !( entry_list->flags & ENTRY_IS_DELETED ) && ( entry_list->parent == parent ) && ( entry_list->storage_id == storage_id ) ) { if( !strcmp(entry_list->name,fileinfo->filename) ) { return entry_list; } } entry_list = entry_list->next; } return NULL; } fs_entry * alloc_entry(fs_handles_db * db, filefoundinfo *fileinfo, uint32_t parent, uint32_t storage_id) { fs_entry * entry; entry = malloc(sizeof(fs_entry)); if( entry ) { memset(entry,0,sizeof(fs_entry)); entry->handle = db->next_handle; db->next_handle++; entry->parent = parent; entry->storage_id = storage_id; entry->name = malloc(strlen(fileinfo->filename)+1); if( entry->name ) { strcpy(entry->name,fileinfo->filename); } entry->size = fileinfo->size; entry->watch_descriptor = -1; if( fileinfo->isdirectory ) entry->flags = ENTRY_IS_DIR; else entry->flags = 0x00000000; entry->next = db->entry_list; db->entry_list = entry; } return entry; } fs_entry * alloc_root_entry(fs_handles_db * db, uint32_t storage_id) { fs_entry * entry; entry = malloc(sizeof(fs_entry)); if( entry ) { memset(entry,0,sizeof(fs_entry)); entry->handle = 0x00000000; entry->parent = 0x00000000; entry->storage_id = storage_id; entry->name = malloc(strlen("/")+1); if( entry->name ) { strcpy(entry->name,"/"); } entry->size = 1; entry->watch_descriptor = -1; entry->flags = ENTRY_IS_DIR; entry->next = db->entry_list; db->entry_list = entry; } return entry; } fs_entry * add_entry(fs_handles_db * db, filefoundinfo *fileinfo, uint32_t parent, uint32_t storage_id) { fs_entry * entry; entry = search_entry(db, fileinfo, parent, storage_id); if( entry ) { // entry already there... PRINT_DEBUG("add_entry : File already present (%s)",fileinfo->filename); } else { // add the entry PRINT_DEBUG("add_entry : File not present - add entry (%s)",fileinfo->filename); entry = alloc_entry( db, fileinfo, parent, storage_id); } return entry; } int scan_and_add_folder(fs_handles_db * db, char * base, uint32_t parent, uint32_t storage_id) { fs_entry * entry; char * path; DIR* dir; int ret; filefoundinfo fileinfo; struct stat64 entrystat; PRINT_DEBUG("scan_and_add_folder : %s, Parent : 0x%.8X, Storage ID : 0x%.8X",base,parent,storage_id); dir = fs_find_first_file(base, &fileinfo); if( dir ) { do { PRINT_DEBUG("---------------------"); PRINT_DEBUG("File : %s",fileinfo.filename); PRINT_DEBUG("Size : 0x%"SIZEHEX,fileinfo.size); PRINT_DEBUG("IsDir: %d",fileinfo.isdirectory); PRINT_DEBUG("---------------------"); if( strcmp(fileinfo.filename,"..") && strcmp(fileinfo.filename,".") && \ (((mtp_ctx *)db->mtp_ctx)->usb_cfg.show_hidden_files || fileinfo.filename[0] != '.') ) { add_entry(db, &fileinfo, parent, storage_id); } }while(fs_find_next_file(dir, base, &fileinfo)); fs_find_close(dir); } // Scan the DB to find and remove deleted files... init_search_handle(db, parent, storage_id); do { entry = get_next_child_handle(db); if(entry) { path = build_full_path(db, mtp_get_storage_root(db->mtp_ctx, entry->storage_id), entry); if(path) { ret = stat64(path, &entrystat); if(ret) { PRINT_DEBUG("scan_and_add_folder : discard entry %s - stat error", path); entry->flags |= ENTRY_IS_DELETED; if( entry->watch_descriptor != -1 ) { inotify_handler_rmwatch( db->mtp_ctx, entry->watch_descriptor ); entry->watch_descriptor = -1; } } else { entry->size = entrystat.st_size; } free(path); } } }while(entry); return 0; } fs_entry * init_search_handle(fs_handles_db * db, uint32_t parent, uint32_t storage_id) { db->search_entry = db->entry_list; db->handle_search = parent; db->storage_search = storage_id; return db->search_entry; } fs_entry * get_next_child_handle(fs_handles_db * db) { fs_entry * entry_list; entry_list = db->search_entry; while( entry_list ) { if( !( entry_list->flags & ENTRY_IS_DELETED ) && ( entry_list->parent == db->handle_search ) && ( entry_list->storage_id == db->storage_search ) && ( entry_list->handle != entry_list->parent ) ) { db->search_entry = entry_list->next; return entry_list; } entry_list = entry_list->next; } db->search_entry = 0x00000000; return NULL; } fs_entry * get_entry_by_handle(fs_handles_db * db, uint32_t handle) { fs_entry * entry_list; entry_list = db->entry_list; while( entry_list ) { if( !( entry_list->flags & ENTRY_IS_DELETED ) && ( entry_list->handle == handle ) ) { return entry_list; } entry_list = entry_list->next; } return 0; } fs_entry * get_entry_by_handle_and_storageid(fs_handles_db * db, uint32_t handle, uint32_t storage_id) { fs_entry * entry_list; entry_list = db->entry_list; while( entry_list ) { if( !( entry_list->flags & ENTRY_IS_DELETED ) && ( entry_list->handle == handle ) && ( entry_list->storage_id == storage_id ) ) { return entry_list; } entry_list = entry_list->next; } return NULL; } char * build_full_path(fs_handles_db * db,char * root_path,fs_entry * entry) { int totallen,namelen; fs_entry * curentry; char * full_path; int full_path_offset; full_path = NULL; curentry = entry; totallen = 0; do { totallen += strlen(curentry->name); totallen++; // '/' if( curentry->parent && ( curentry->parent != 0xFFFFFFFF ) ) { curentry = get_entry_by_handle(db, curentry->parent); } else { curentry = NULL; } }while( curentry ); if(root_path) { totallen += strlen(root_path); } full_path = malloc(totallen+1); if( full_path ) { memset(full_path,0,totallen+1); full_path_offset = totallen; curentry = entry; do { namelen = strlen(curentry->name); full_path_offset -= namelen; memcpy(&full_path[full_path_offset],curentry->name,namelen); full_path_offset--; full_path[full_path_offset] = '/'; if(curentry->parent && curentry->parent!=0xFFFFFFFF) { curentry = get_entry_by_handle(db, curentry->parent); } else { curentry = NULL; } }while(curentry); if(root_path) { memcpy(&full_path[0],root_path,strlen(root_path)); } PRINT_DEBUG("build_full_path : %s -> %s",entry->name, full_path); } return full_path; } int entry_open(fs_handles_db * db, fs_entry * entry) { int file; char * full_path; file = -1; full_path = build_full_path(db,mtp_get_storage_root(db->mtp_ctx, entry->storage_id), entry); if( full_path ) { file = open(full_path,O_RDONLY | O_LARGEFILE); if( file == -1 ) PRINT_DEBUG("entry_open : Can't open %s !",full_path); free(full_path); } return file; } int entry_read(fs_handles_db * db, int file, unsigned char * buffer_out, mtp_offset offset, mtp_size size) { int totalread; if( file != -1 ) { lseek64(file, offset, SEEK_SET); totalread = read( file, buffer_out, size ); return totalread; } return 0; } void entry_close(int file) { if( file != -1 ) close(file); } fs_entry * get_entry_by_wd( fs_handles_db * db, int watch_descriptor, fs_entry * entry_list ) { if(!entry_list) entry_list = db->entry_list; while( entry_list ) { if( !( entry_list->flags & ENTRY_IS_DELETED ) && ( entry_list->watch_descriptor == watch_descriptor ) ) { return entry_list; } entry_list = entry_list->next; } return NULL; } fs_entry * get_entry_by_storageid( fs_handles_db * db, uint32_t storage_id, fs_entry * entry_list ) { if(!entry_list) entry_list = db->entry_list; while( entry_list ) { if( !( entry_list->flags & ENTRY_IS_DELETED ) && ( entry_list->storage_id == storage_id ) ) { return entry_list; } entry_list = entry_list->next; } return NULL; } umtp-responder-1.3.10/src/inotify.c000066400000000000000000000203741374176322100172100ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file inotify.c * @brief inotify file system events handler. * @author Jean-François DEL NERO */ #include "buildconf.h" #include #include #include #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_datasets.h" #include "usb_gadget_fct.h" #include "fs_handles_db.h" #include "inotify.h" #include "logs_out.h" #define INOTIFY_RD_BUF_SIZE ( 32*1024 ) static int get_file_info(mtp_ctx * ctx, const struct inotify_event *event, fs_entry * entry, filefoundinfo * fileinfo, int deleted) { char * path; char * tmp_path; if( entry && fileinfo ) { PRINT_DEBUG( "Entry %x - %s", entry->handle, entry->name ); path = build_full_path( ctx->fs_db, mtp_get_storage_root( ctx, entry->storage_id), entry); if( path ) { tmp_path = malloc( strlen(path) + event->len + 3 ); if( tmp_path ) { strcpy( tmp_path, path ); strcat( tmp_path, "/" ); strncat( tmp_path, event->name, event->len ); if( !deleted ) { fs_entry_stat( tmp_path, fileinfo ); } else { fileinfo->isdirectory = 0; fileinfo->size = 0; fileinfo->filename[FS_HANDLE_MAX_FILENAME_SIZE] = '\0'; strncpy( fileinfo->filename, event->name, FS_HANDLE_MAX_FILENAME_SIZE ); } free( tmp_path ); return 1; } free( path ); } } return 0; } void *inotify_gotsig(int sig, siginfo_t *info, void *ucontext) { return NULL; } void* inotify_thread(void* arg) { mtp_ctx * ctx; int i,length; fs_entry * entry; fs_entry * deleted_entry; fs_entry * modified_entry; fs_entry * new_entry; fs_entry * old_entry; filefoundinfo fileinfo; uint32_t handle[3]; char inotify_buffer[INOTIFY_RD_BUF_SIZE] __attribute__ ((aligned(__alignof__(struct inotify_event)))); const struct inotify_event *event; struct sigaction sa; ctx = (mtp_ctx *)arg; sa.sa_handler = NULL; sa.sa_sigaction = (void *)inotify_gotsig; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); if (sigaction(SIGUSR1, &sa, NULL) < 0) { return (void *)-1; } for (;;) { memset(inotify_buffer,0,sizeof(inotify_buffer)); length = read(ctx->inotify_fd, inotify_buffer, sizeof(inotify_buffer)); if ( length >= 0 ) { if(!length) PRINT_DEBUG( "inotify_thread : Null sized packet ?"); i = 0; while ( i < length && i < INOTIFY_RD_BUF_SIZE ) { event = ( struct inotify_event * ) &inotify_buffer[ i ]; // Sanity check to prevent possible buffer overrun/overflow. if ( event->len && (i + (( sizeof (struct inotify_event) ) + event->len) < sizeof(inotify_buffer)) ) { if ( event->mask & IN_CREATE ) { entry = NULL; do { pthread_mutex_lock( &ctx->inotify_mutex ); entry = get_entry_by_wd( ctx->fs_db, event->wd, entry ); if ( get_file_info( ctx, event, entry, &fileinfo, 0 ) ) { old_entry = search_entry(ctx->fs_db, &fileinfo, entry->handle, entry->storage_id); if( !old_entry ) { // If the entry is not in the db, add it and trigger an MTP_EVENT_OBJECT_ADDED event new_entry = add_entry( ctx->fs_db, &fileinfo, entry->handle, entry->storage_id ); // Send an "ObjectAdded" (0x4002) MTP event message with the entry handle. handle[0] = new_entry->handle; mtp_push_event( ctx, MTP_EVENT_OBJECT_ADDED, 1, (uint32_t *)&handle ); PRINT_DEBUG( "inotify_thread (IN_CREATE): Entry %s created (Handle 0x%.8X)", event->name, new_entry->handle ); } else { PRINT_DEBUG( "inotify_thread (IN_CREATE): Entry %s already in the db ! (Handle 0x%.8X)", event->name, old_entry->handle ); } } else { PRINT_DEBUG( "inotify_thread (IN_CREATE): Watch point descriptor not found in the db ! (Descriptor 0x%.8X)", event->wd ); } if(entry) { entry = entry->next; } pthread_mutex_unlock( &ctx->inotify_mutex ); }while(entry); } if ( event->mask & IN_MODIFY ) { entry = NULL; do { pthread_mutex_lock( &ctx->inotify_mutex ); entry = get_entry_by_wd( ctx->fs_db, event->wd, entry ); if ( get_file_info( ctx, event, entry, &fileinfo, 1 ) ) { modified_entry = search_entry(ctx->fs_db, &fileinfo, entry->handle, entry->storage_id); if( modified_entry ) { // Send an "ObjectInfoChanged" (0x4007) MTP event message with the entry handle. handle[0] = modified_entry->handle; mtp_push_event( ctx, MTP_EVENT_OBJECT_INFO_CHANGED, 1, (uint32_t *)&handle ); PRINT_DEBUG( "inotify_thread (IN_MODIFY): Entry %s modified (Handle 0x%.8X)", event->name, modified_entry->handle); } } else { PRINT_DEBUG( "inotify_thread (IN_MODIFY): Watch point descriptor not found in the db ! (Descriptor 0x%.8X)", event->wd ); } if(entry) { entry = entry->next; } pthread_mutex_unlock( &ctx->inotify_mutex ); }while(entry); } if ( event->mask & IN_DELETE ) { entry = NULL; do { pthread_mutex_lock( &ctx->inotify_mutex ); entry = get_entry_by_wd( ctx->fs_db, event->wd, entry ); if ( get_file_info( ctx, event, entry, &fileinfo, 1 ) ) { deleted_entry = search_entry(ctx->fs_db, &fileinfo, entry->handle, entry->storage_id); if( deleted_entry ) { deleted_entry->flags |= ENTRY_IS_DELETED; if( deleted_entry->watch_descriptor != -1 ) { inotify_handler_rmwatch( ctx, deleted_entry->watch_descriptor ); deleted_entry->watch_descriptor = -1; } // Send an "ObjectRemoved" (0x4003) MTP event message with the entry handle. handle[0] = deleted_entry->handle; mtp_push_event( ctx, MTP_EVENT_OBJECT_REMOVED, 1, (uint32_t *)&handle ); PRINT_DEBUG( "inotify_thread (IN_DELETE): Entry %s deleted (Handle 0x%.8X)", event->name, deleted_entry->handle); } } else { PRINT_DEBUG( "inotify_thread (IN_DELETE): Watch point descriptor not found in the db ! (Descriptor 0x%.8X)", event->wd ); } if(entry) { entry = entry->next; } pthread_mutex_unlock( &ctx->inotify_mutex ); }while(entry); } } i += (( sizeof (struct inotify_event) ) + event->len); } } else { PRINT_DEBUG( "inotify_thread : read error %d",length ); return NULL; } } return NULL; } int inotify_handler_init( mtp_ctx * ctx ) { if( ctx ) { ctx->inotify_fd = inotify_init1(0x00); PRINT_DEBUG("init_inotify_handler : inotify_fd = %d", ctx->inotify_fd); pthread_create(&ctx->inotify_thread, NULL, inotify_thread, ctx); return 1; } return 0; } int inotify_handler_deinit( mtp_ctx * ctx ) { void * ret; if( ctx ) { if( ctx->inotify_fd != -1 ) { pthread_kill( ctx->inotify_thread, SIGUSR1); pthread_join( ctx->inotify_thread, &ret); close( ctx->inotify_fd ); ctx->inotify_fd = -1; } return 1; } return 0; } int inotify_handler_addwatch( mtp_ctx * ctx, char * path ) { if( ctx->inotify_fd != -1 ) { if( !ctx->no_inotify ) { return inotify_add_watch( ctx->inotify_fd, path, IN_CREATE | IN_DELETE | IN_MODIFY ); } } return -1; } int inotify_handler_rmwatch( mtp_ctx * ctx, int wd ) { if( ctx->inotify_fd != -1 && wd != -1 ) { return inotify_rm_watch( ctx->inotify_fd, wd ); } return -1; } umtp-responder-1.3.10/src/logs_out.c000066400000000000000000000045631374176322100173640ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file logs_out.c * @brief log output functions * @author Jean-François DEL NERO */ #include "buildconf.h" #include #include #include #include "logs_out.h" void timestamp(char * timestr, int maxsize) { time_t ltime; struct tm * local_time; ltime = time(NULL); timestr[0] = 0; local_time = localtime(<ime); snprintf(timestr, maxsize, "%.2d:%.2d:%.2d",local_time->tm_hour, local_time->tm_min, local_time->tm_sec ); } #ifdef DEBUG int is_printable_char(unsigned char c) { int i; unsigned char specialchar[]={"&#{}()|_@=$!?;+*-"}; if( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ) { return 1; } i = 0; while(specialchar[i]) { if(specialchar[i] == c) { return 1; } i++; } return 0; } void printbuf(void * buf,int size) { #define PRINTBUF_HEXPERLINE 16 #define PRINTBUF_MAXLINE_SIZE ((3*PRINTBUF_HEXPERLINE)+1+PRINTBUF_HEXPERLINE+2) int i,j; unsigned char *ptr = buf; char tmp[8]; char str[PRINTBUF_MAXLINE_SIZE]; memset(str, ' ', PRINTBUF_MAXLINE_SIZE); str[PRINTBUF_MAXLINE_SIZE-1] = 0; j = 0; for(i=0;i */ #include "buildconf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_datasets.h" #include "usb_gadget_fct.h" #include "fs_handles_db.h" #include "inotify.h" #include "logs_out.h" typedef struct mesg_buffer_ { long mesg_type; char mesg_text[100]; } queue_msg_buf; void *msgqueue_gotsig(int sig, siginfo_t *info, void *ucontext) { return NULL; } void* msgqueue_thread( void* arg ) { mtp_ctx * ctx; queue_msg_buf msg_buf; uint32_t handle[3]; fs_entry * entry; int store_index; struct sigaction sa; ctx = (mtp_ctx *)arg; sa.sa_handler = NULL; sa.sa_sigaction = (void *)msgqueue_gotsig; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); if (sigaction(SIGUSR1, &sa, NULL) < 0) { return (void *)-1; } PRINT_DEBUG("msgqueue_thread : Thread started"); do { if( msgrcv(ctx->msgqueue_id, &msg_buf, sizeof(msg_buf), 1, 0) > 0 ) { PRINT_DEBUG("msgqueue_thread : New message received : %s",msg_buf.mesg_text); if(!strncmp((char*)&msg_buf.mesg_text,"mount:",6)) { store_index = mtp_get_storage_index_by_name(ctx, (char*)&msg_buf.mesg_text + 6); if(store_index >= 0) { pthread_mutex_lock( &ctx->inotify_mutex ); if( ctx->storages[store_index].flags & UMTP_STORAGE_NOTMOUNTED ) { alloc_root_entry(ctx->fs_db, ctx->storages[store_index].storage_id); } ctx->storages[store_index].flags &= ~UMTP_STORAGE_NOTMOUNTED; handle[0] = ctx->storages[store_index].storage_id; mtp_push_event( ctx, MTP_EVENT_STORE_ADDED, 1, (uint32_t *)&handle ); pthread_mutex_unlock( &ctx->inotify_mutex ); } else { PRINT_ERROR("msgqueue_thread : Store not found : %s",(char*)&msg_buf.mesg_text + 6); } } if(!strncmp((char*)&msg_buf.mesg_text,"unmount:",8)) { store_index = mtp_get_storage_index_by_name(ctx, (char*)&msg_buf.mesg_text + 8); if(store_index >= 0) { pthread_mutex_lock( &ctx->inotify_mutex ); entry = NULL; do { entry = get_entry_by_storageid( ctx->fs_db, ctx->storages[store_index].storage_id, entry ); if(entry) { entry->flags |= ENTRY_IS_DELETED; if( entry->watch_descriptor != -1 ) { inotify_handler_rmwatch( ctx, entry->watch_descriptor ); entry->watch_descriptor = -1; } entry = entry->next; } }while(entry); ctx->storages[store_index].flags |= UMTP_STORAGE_NOTMOUNTED; handle[0] = ctx->storages[store_index].storage_id; mtp_push_event( ctx, MTP_EVENT_STORE_REMOVED, 1, (uint32_t *)&handle ); pthread_mutex_unlock( &ctx->inotify_mutex ); } else { PRINT_ERROR("msgqueue_thread : Store not found : %s",(char*)&msg_buf.mesg_text + 8); } } } else { break; } }while(1); msgctl(ctx->msgqueue_id, IPC_RMID, NULL); PRINT_DEBUG("msgqueue_thread : Leaving msgqueue_thread..."); return NULL; } int get_current_exec_path( char * exec_path, int maxsize ) { pid_t pid; char path[PATH_MAX]; char tmp_exec_path[PATH_MAX + 1]; memset(tmp_exec_path,0,sizeof(tmp_exec_path)); pid = getpid(); sprintf(path, "/proc/%d/exe", pid); if (readlink(path, tmp_exec_path, PATH_MAX) == -1) { return -1; } tmp_exec_path[PATH_MAX] = 0; if(strlen(tmp_exec_path) < maxsize) { strcpy(exec_path,tmp_exec_path); return 0; } else return -2; } int send_message_queue( char * message ) { key_t key; int msgqueue_id; char exec_path[PATH_MAX + 1]; queue_msg_buf msg_buf; if(get_current_exec_path(exec_path, sizeof(exec_path)) >= 0) { PRINT_DEBUG("send_message_queue : current exec path : %s", exec_path); key = ftok(exec_path, 44); msgqueue_id = msgget(key, 0666 | IPC_CREAT); PRINT_DEBUG("send_message_queue : msgqueue_id = %d", msgqueue_id); msg_buf.mesg_type = 1; msg_buf.mesg_text[sizeof(msg_buf.mesg_text) - 1] = '\0'; // to be sure to terminate the string - see the strncpy's behavior. strncpy(msg_buf.mesg_text,message,sizeof(msg_buf.mesg_text) - 1); if( msgsnd(msgqueue_id, &msg_buf, sizeof(msg_buf), 0) == 0 ) { return 0; } } PRINT_ERROR("send_message_queue : Couldn't send %s !", message); return -1; } int msgqueue_handler_init( mtp_ctx * ctx ) { key_t key; char exec_path[PATH_MAX + 1]; int ret; if( ctx ) { if(get_current_exec_path(exec_path, sizeof(exec_path)) >= 0) { PRINT_DEBUG("msgqueue_handler_init : current exec path : %s", exec_path); key = ftok(exec_path, 44); ctx->msgqueue_id = msgget(key, 0666 | IPC_CREAT); if(ctx->msgqueue_id != -1) { PRINT_DEBUG("msgqueue_handler_init : msgqueue_id = %d", ctx->msgqueue_id); ret = pthread_create(&ctx->msgqueue_thread, NULL, msgqueue_thread, ctx); if(ret != 0) { PRINT_ERROR("msgqueue_handler_init : msgqueue_thread thread creation failed ! (error %d)", ret); return -1; } else { return 1; } } else { PRINT_ERROR("msgqueue_handler_init : msgget error %d", errno); } } } return 0; } int msgqueue_handler_deinit( mtp_ctx * ctx ) { void * ret; if( ctx ) { if( ctx->msgqueue_id != -1 ) { pthread_kill( ctx->msgqueue_thread, SIGUSR1); pthread_join( ctx->msgqueue_thread, &ret); ctx->msgqueue_id = -1; } return 1; } return 0; } umtp-responder-1.3.10/src/mtp.c000066400000000000000000000514101374176322100163220ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp.c * @brief Main MTP protocol functions. * @author Jean-François DEL NERO */ #include "buildconf.h" #include #include #include #include #include #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_constant_strings.h" #include "mtp_datasets.h" #include "mtp_properties.h" #include "mtp_operations.h" #include "usb_gadget_fct.h" #include "mtp_support_def.h" #include "fs_handles_db.h" #include "inotify.h" #include "msgqueue.h" #include "logs_out.h" mtp_ctx * mtp_init_responder() { mtp_ctx * ctx; PRINT_DEBUG("init_mtp_responder"); ctx = malloc(sizeof(mtp_ctx)); if(ctx) { memset(ctx,0,sizeof(mtp_ctx)); ctx->usb_wr_buffer_max_size = CONFIG_MAX_TX_USB_BUFFER_SIZE; ctx->wrbuffer = NULL; ctx->usb_rd_buffer_max_size = CONFIG_MAX_RX_USB_BUFFER_SIZE; ctx->rdbuffer = NULL; ctx->rdbuffer2 = NULL; ctx->read_file_buffer_size = CONFIG_READ_FILE_BUFFER_SIZE; ctx->read_file_buffer = NULL; ctx->temp_array = malloc( MAX_STORAGE_NB * sizeof(uint32_t) ); if(!ctx->temp_array) goto init_error; ctx->SetObjectPropValue_Handle = 0xFFFFFFFF; pthread_mutex_init ( &ctx->inotify_mutex, NULL); inotify_handler_init( ctx ); msgqueue_handler_init( ctx ); PRINT_DEBUG("init_mtp_responder : Ok !"); return ctx; } init_error: if(ctx) { if(ctx->wrbuffer) free(ctx->wrbuffer); if(ctx->rdbuffer) free(ctx->rdbuffer); if(ctx->rdbuffer2) free(ctx->rdbuffer2); if(ctx->temp_array) free(ctx->temp_array); free(ctx); } PRINT_ERROR("init_mtp_responder : Failed !"); return 0; } void mtp_deinit_responder(mtp_ctx * ctx) { if( ctx ) { msgqueue_handler_deinit( ctx ); inotify_handler_deinit( ctx ); if(ctx->wrbuffer) free(ctx->wrbuffer); if(ctx->rdbuffer) free(ctx->rdbuffer); if(ctx->rdbuffer2) free(ctx->rdbuffer2); if(ctx->temp_array) free(ctx->temp_array); if(ctx->read_file_buffer) free(ctx->read_file_buffer); free(ctx); } } int build_response(mtp_ctx * ctx, uint32_t tx_id, uint16_t type, uint16_t status, void * buffer, int maxsize, void * datain,int size) { MTP_PACKET_HEADER tmp_hdr; int ofs; ofs = 0; tmp_hdr.length = sizeof(tmp_hdr) + size; tmp_hdr.operation = type; tmp_hdr.code = status; tmp_hdr.tx_id = tx_id; ofs = poke_array(buffer, ofs, maxsize, sizeof(MTP_PACKET_HEADER), 1, (unsigned char*)&tmp_hdr,0); if(size) ofs = poke_array(buffer, ofs, maxsize, size, 1, (unsigned char*)datain,0); return ofs; } int parse_incomming_dataset(mtp_ctx * ctx,void * datain,int size,uint32_t * newhandle, uint32_t parent_handle, uint32_t storage_id) { MTP_PACKET_HEADER * tmp_hdr; unsigned char *dataset_ptr; uint32_t objectformat,objectsize; #ifdef DEBUG uint32_t type; #endif unsigned char string_len; char tmp_str[256+1]; uint16_t unicode_str[256+1]; char * parent_folder; char * tmp_path; uint32_t storage_flags; int i,ret_code; fs_entry * entry; int file; filefoundinfo tmp_file_entry; ret_code = MTP_RESPONSE_GENERAL_ERROR; tmp_hdr = (MTP_PACKET_HEADER *)datain; if(parent_handle == 0xFFFFFFFF) parent_handle = 0x00000000; PRINT_DEBUG("Incoming dataset : %d bytes (raw) %d bytes, operation 0x%x, code 0x%x, tx_id: %x",size,tmp_hdr->length,tmp_hdr->operation,tmp_hdr->code ,tmp_hdr->tx_id ); storage_flags = mtp_get_storage_flags(ctx, storage_id); if( storage_flags == 0xFFFFFFFF ) { PRINT_DEBUG("parse_incomming_dataset : Storage 0x%.8x is Invalid !",storage_id); return MTP_RESPONSE_INVALID_STORAGE_ID; } if( (storage_flags & UMTP_STORAGE_READONLY) ) { PRINT_DEBUG("parse_incomming_dataset : Storage 0x%.8x is Read only !", storage_id); return MTP_RESPONSE_STORE_READ_ONLY; } dataset_ptr = (datain + sizeof(MTP_PACKET_HEADER)); switch( tmp_hdr->code ) { case MTP_OPERATION_SEND_OBJECT_INFO: objectformat = peek(dataset_ptr, 0x04, 2); // ObjectFormat Code if(objectformat==MTP_FORMAT_ASSOCIATION) { objectsize = peek(dataset_ptr, 0x08, 4); // Object Compressed Size //parent = peek(dataset_ptr,0x26, 4); // Parent Object (NR) #ifdef DEBUG type = peek(dataset_ptr,0x2A, 2); // Association Type #else peek(dataset_ptr,0x2A, 2); // Association Type #endif string_len = peek(dataset_ptr,0x34, 1); // File name if(string_len > 255) string_len = 255; memset(unicode_str,0,sizeof(unicode_str)); for(i=0;ifs_db, parent_handle,storage_id); if(entry) { if(entry->flags & ENTRY_IS_DIR) { tmp_path = NULL; parent_folder = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); if(parent_folder) { PRINT_DEBUG("MTP_OPERATION_SEND_OBJECT_INFO : Parent folder %s",parent_folder); tmp_path = malloc(strlen(parent_folder) + 1 + strlen(tmp_str) + 1); } if(tmp_path) { sprintf(tmp_path,"%s/%s",parent_folder,tmp_str); PRINT_DEBUG("MTP_OPERATION_SEND_OBJECT_INFO : Creating %s ...",tmp_path); if( mkdir(tmp_path, 0700) ) { PRINT_WARN("MTP_OPERATION_SEND_OBJECT_INFO : Can't create %s ...",tmp_path); if(parent_folder) free(parent_folder); free(tmp_path); ret_code = MTP_RESPONSE_ACCESS_DENIED; return ret_code; } tmp_file_entry.isdirectory = 1; strcpy(tmp_file_entry.filename,tmp_str); tmp_file_entry.size = 0; entry = add_entry(ctx->fs_db, &tmp_file_entry, parent_handle, storage_id); if(entry) { *newhandle = entry->handle; } free(tmp_path); ret_code = MTP_RESPONSE_OK; } if(parent_folder) free(parent_folder); } } } else { objectsize = peek(dataset_ptr, 0x08, 4); // Object Compressed Size //parent = peek(dataset_ptr,0x26, 4); // Parent Object (NR) #ifdef DEBUG type = peek(dataset_ptr,0x2A, 2); // Association Type #else peek(dataset_ptr,0x2A, 2); // Association Type #endif string_len = peek(dataset_ptr,0x34, 1); // File name memset(unicode_str,0,sizeof(unicode_str)); for(i=0;ifs_db, parent_handle,storage_id); if(entry) { if(entry->flags & ENTRY_IS_DIR) { parent_folder = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); tmp_path = NULL; entry = NULL; if(parent_folder) { PRINT_DEBUG("MTP_OPERATION_SEND_OBJECT_INFO : Parent folder %s",parent_folder); tmp_path = malloc(strlen(parent_folder) + 1 + strlen(tmp_str) + 1); } if( tmp_path ) { sprintf(tmp_path,"%s/%s",parent_folder,tmp_str); PRINT_DEBUG("MTP_OPERATION_SEND_OBJECT_INFO : Creating %s ...",tmp_path); tmp_file_entry.isdirectory = 0; strcpy(tmp_file_entry.filename,tmp_str); tmp_file_entry.size = objectsize; file = open(tmp_path,O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRUSR|S_IWUSR); if( file == -1) { PRINT_WARN("MTP_OPERATION_SEND_OBJECT_INFO : Can't create %s ...",tmp_path); if(parent_folder) free(parent_folder); free(tmp_path); ret_code = MTP_RESPONSE_ACCESS_DENIED; return ret_code; } close( file ); entry = add_entry(ctx->fs_db, &tmp_file_entry, parent_handle, storage_id); free(tmp_path); } if(entry) { ctx->SendObjInfoHandle = entry->handle; ctx->SendObjInfoSize = objectsize; ctx->SendObjInfoOffset = 0; *newhandle = entry->handle; } else { ctx->SendObjInfoHandle = 0xFFFFFFFF; ctx->SendObjInfoSize = 0; ctx->SendObjInfoOffset = 0; } if( parent_folder ) free(parent_folder); ret_code = MTP_RESPONSE_OK; } } } break; default : break; } return MTP_RESPONSE_OK; } int check_and_send_USB_ZLP(mtp_ctx * ctx , int size) { // USB ZLP needed ? if( (size >= ctx->max_packet_size) && !(size % ctx->max_packet_size) ) { PRINT_DEBUG("%d bytes transfert ended - ZLP packet needed", size); // Yes - Send zero lenght packet. write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,0); return 1; } return 0; } int check_handle_access( mtp_ctx * ctx, fs_entry * entry, uint32_t handle, int wraccess, uint32_t * response) { uint32_t storage_flags; if( !entry ) { entry = get_entry_by_handle(ctx->fs_db, handle); } if(entry) { storage_flags = mtp_get_storage_flags(ctx, entry->storage_id); if( storage_flags == 0xFFFFFFFF ) { PRINT_DEBUG("check_handle_access : Storage 0x%.8x is Invalid !",entry->storage_id); if( response ) *response = MTP_RESPONSE_INVALID_STORAGE_ID; return 1; } if( (storage_flags & UMTP_STORAGE_READONLY) && wraccess ) { PRINT_DEBUG("check_handle_access : Storage 0x%.8x is Read only !",entry->storage_id); if( response ) *response = MTP_RESPONSE_STORE_READ_ONLY; return 1; } } else { PRINT_DEBUG("check_handle_access : Handle 0x%.8x is invalid !",handle); if( response ) *response = MTP_RESPONSE_INVALID_OBJECT_HANDLE; return 1; } return 0; } int process_in_packet(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int rawsize) { uint32_t params[5]; int params_size; uint32_t response_code; int size; params[0] = 0x000000; params[1] = 0x000000; params[2] = 0x000000; params[3] = 0x000000; params[4] = 0x000000; params_size = 0; // No response parameter by default size = rawsize; switch( mtp_packet_hdr->code ) { case MTP_OPERATION_OPEN_SESSION: response_code = mtp_op_OpenSession(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_CLOSE_SESSION: response_code = mtp_op_CloseSession(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_DEVICE_INFO: response_code = mtp_op_GetDeviceInfos(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_STORAGE_IDS: response_code = mtp_op_GetStorageIDs(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_STORAGE_INFO: response_code = mtp_op_GetStorageInfo(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_DEVICE_PROP_DESC: response_code = mtp_op_GetDevicePropDesc(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_DEVICE_PROP_VALUE: response_code = mtp_op_GetDevicePropValue(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_OBJECT_HANDLES: response_code = mtp_op_GetObjectHandles(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_OBJECT_INFO: response_code = mtp_op_GetObjectInfo(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_PARTIAL_OBJECT_64: case MTP_OPERATION_GET_PARTIAL_OBJECT: response_code = mtp_op_GetPartialObject(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_OBJECT: response_code = mtp_op_GetObject(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_SEND_OBJECT_INFO: response_code = mtp_op_SendObjectInfo(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_SEND_PARTIAL_OBJECT: case MTP_OPERATION_SEND_OBJECT: response_code = mtp_op_SendObject(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_DELETE_OBJECT: response_code = mtp_op_DeleteObject(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED: response_code = mtp_op_GetObjectPropsSupported(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_OBJECT_PROP_DESC: response_code = mtp_op_GetObjectPropDesc(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_OBJECT_PROP_VALUE: response_code = mtp_op_GetObjectPropValue(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_SET_OBJECT_PROP_VALUE: response_code = mtp_op_SetObjectPropValue(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_OBJECT_PROP_LIST: response_code = mtp_op_GetObjectPropList(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_GET_OBJECT_REFERENCES: response_code = mtp_op_GetObjectReferences(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_BEGIN_EDIT_OBJECT: response_code = mtp_op_BeginEditObject(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_END_EDIT_OBJECT: response_code = mtp_op_EndEditObject(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; case MTP_OPERATION_TRUNCATE_OBJECT : response_code = mtp_op_TruncateObject(ctx,mtp_packet_hdr,&size,(uint32_t*)¶ms,¶ms_size); break; default: PRINT_WARN("MTP code unsupported ! : 0x%.4X (%s)", mtp_packet_hdr->code,mtp_get_operation_string(mtp_packet_hdr->code)); response_code = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; break; } // Send the status response if(response_code != MTP_RESPONSE_NO_RESPONSE) { size = build_response(ctx, mtp_packet_hdr->tx_id,MTP_CONTAINER_TYPE_RESPONSE, response_code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size , ¶ms,params_size); if(size >= 0) { PRINT_DEBUG("Status response (%d Bytes):",size); PRINT_DEBUG_BUF(ctx->wrbuffer, size); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,size); } } else { PRINT_DEBUG("No Status response sent"); } return 0; // TODO Return usb error code. } int mtp_incoming_packet(mtp_ctx * ctx) { int size; MTP_PACKET_HEADER * mtp_packet_hdr; if(!ctx) return 0; size = read_usb(ctx->usb_ctx, ctx->rdbuffer, ctx->usb_rd_buffer_max_size); if(size>=0) { PRINT_DEBUG("--------------------------------------------------"); PRINT_DEBUG("Incoming_packet : %p - rawsize : %d",ctx->rdbuffer,size); if(!size) return 0; // ZLP mtp_packet_hdr = (MTP_PACKET_HEADER *)ctx->rdbuffer; PRINT_DEBUG("MTP Packet size : %d bytes", mtp_packet_hdr->length); PRINT_DEBUG("MTP Operation : 0x%.4X (%s)", mtp_packet_hdr->operation, mtp_get_type_string(mtp_packet_hdr->operation) ); PRINT_DEBUG("MTP code : 0x%.4X (%s)", mtp_packet_hdr->code,mtp_get_operation_string(mtp_packet_hdr->code)); PRINT_DEBUG("MTP Tx ID : 0x%.8X", mtp_packet_hdr->tx_id); if( mtp_packet_hdr->length != size ) { PRINT_DEBUG("Header Packet size and rawsize are not equal !: %d != %d",mtp_packet_hdr->length,size); } PRINT_DEBUG("Header : "); PRINT_DEBUG_BUF(ctx->rdbuffer, sizeof(MTP_PACKET_HEADER)); PRINT_DEBUG("Payload : "); PRINT_DEBUG_BUF(ctx->rdbuffer + sizeof(MTP_PACKET_HEADER),size - sizeof(MTP_PACKET_HEADER)); process_in_packet(ctx,mtp_packet_hdr,size); return 0; } else { PRINT_ERROR("incoming_packet : Read Error (%d)!",size); } return -1; } void mtp_set_usb_handle(mtp_ctx * ctx, void * handle, uint32_t max_packet_size) { ctx->usb_ctx = handle; ctx->max_packet_size = max_packet_size; } uint32_t mtp_add_storage(mtp_ctx * ctx, char * path, char * description, uint32_t flags) { int i; PRINT_DEBUG("mtp_add_storage : %s", path ); i = 0; while(i < MAX_STORAGE_NB) { if( !ctx->storages[i].root_path ) { ctx->storages[i].root_path = malloc(strlen(path) + 1); ctx->storages[i].description = malloc(strlen(description) + 1); if(ctx->storages[i].root_path && ctx->storages[i].description) { strcpy(ctx->storages[i].root_path,path); strcpy(ctx->storages[i].description,description); ctx->storages[i].flags = flags; ctx->storages[i].storage_id = 0xFFFF0000 + (i + 1); PRINT_DEBUG("mtp_add_storage : Storage %.8X mapped to %s (%s) (Flags: 0x%.8X)", ctx->storages[i].storage_id, ctx->storages[i].root_path, ctx->storages[i].description, ctx->storages[i].flags); return ctx->storages[i].storage_id; } else { if(ctx->storages[i].root_path) free(ctx->storages[i].root_path); if(ctx->storages[i].description) free(ctx->storages[i].description); ctx->storages[i].root_path = NULL; ctx->storages[i].description = NULL; ctx->storages[i].flags = 0x00000000; ctx->storages[i].storage_id = 0x00000000; return ctx->storages[i].storage_id; } } i++; } return 0x00000000; } uint32_t mtp_get_storage_id_by_name(mtp_ctx * ctx, char * name) { int i; PRINT_DEBUG("mtp_get_storage_id_by_name : %s", name ); i = 0; while(i < MAX_STORAGE_NB) { if( ctx->storages[i].root_path ) { if( !strcmp(ctx->storages[i].description, name ) ) { PRINT_DEBUG("mtp_get_storage_id_by_name : %s -> %.8X", ctx->storages[i].root_path, ctx->storages[i].storage_id); return ctx->storages[i].storage_id; } } i++; } return 0xFFFFFFFF; } int mtp_get_storage_index_by_name(mtp_ctx * ctx, char * name) { int i; PRINT_DEBUG("mtp_get_storage_index_by_name : %s", name ); i = 0; while(i < MAX_STORAGE_NB) { if( ctx->storages[i].root_path ) { if( !strcmp(ctx->storages[i].description, name ) ) { PRINT_DEBUG("mtp_get_storage_index_by_name : %s -> %.8X", ctx->storages[i].root_path, i); return i; } } i++; } return -1; } char * mtp_get_storage_root(mtp_ctx * ctx, uint32_t storage_id) { int i; PRINT_DEBUG("mtp_get_storage_root : %.8X", storage_id ); i = 0; while(i < MAX_STORAGE_NB) { if( ctx->storages[i].root_path ) { if( ctx->storages[i].storage_id == storage_id ) { PRINT_DEBUG("mtp_get_storage_root : %.8X -> %s", storage_id, ctx->storages[i].root_path ); return ctx->storages[i].root_path; } } i++; } return NULL; } char * mtp_get_storage_description(mtp_ctx * ctx, uint32_t storage_id) { int i; PRINT_DEBUG("mtp_get_storage_description : %.8X", storage_id ); i = 0; while(i < MAX_STORAGE_NB) { if( ctx->storages[i].root_path ) { if( ctx->storages[i].storage_id == storage_id ) { PRINT_DEBUG("mtp_get_storage_description : %.8X -> %s", storage_id, ctx->storages[i].description ); return ctx->storages[i].description; } } i++; } return NULL; } uint32_t mtp_get_storage_flags(mtp_ctx * ctx, uint32_t storage_id) { int i; PRINT_DEBUG("mtp_get_storage_flags : %.8X", storage_id ); i = 0; while(i < MAX_STORAGE_NB) { if( ctx->storages[i].root_path ) { if( ctx->storages[i].storage_id == storage_id ) { PRINT_DEBUG("mtp_get_storage_flags : %.8X -> 0x%.8X", storage_id, ctx->storages[i].flags ); return ctx->storages[i].flags; } } i++; } return 0xFFFFFFFF; } int mtp_push_event(mtp_ctx * ctx, uint32_t event, int nbparams, uint32_t * parameters ) { unsigned char event_buffer[64]; int size; int ret; size = build_event_dataset( ctx, event_buffer, sizeof(event_buffer), event , ctx->session_id, 0x00000000, nbparams, parameters); if(size < 0) return -1; PRINT_DEBUG("mtp_push_event : Event packet buffer - %d Bytes :",size); PRINT_DEBUG_BUF(event_buffer, size); ret = write_usb(ctx->usb_ctx,EP_DESCRIPTOR_INT_IN,event_buffer,size); PRINT_DEBUG("write_usb return: %d", ret ); return ret; } umtp-responder-1.3.10/src/mtp_cfg.c000066400000000000000000000341541374176322100171470ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_cfg.c * @brief Configuration file parser. * @author Jean-François DEL NERO */ #include "buildconf.h" #include #include #include #include #include #include "mtp.h" #include "mtp_cfg.h" #include "fs_handles_db.h" #include "usbstring.h" #include "default_cfg.h" #include "logs_out.h" typedef int (* KW_FUNC)(mtp_ctx * context, char * line, int cmd); enum { STORAGE_CMD = 0, USBVENDORID_CMD, USBPRODUCTID_CMD, USBCLASS_CMD, USBSUBCLASS_CMD, USBPROTOCOL_CMD, USBDEVVERSION_CMD, USBMAXPACKETSIZE_CMD, USBFUNCTIONFSMODE_CMD, USBMAXRDBUFFERSIZE_CMD, USBMAXWRBUFFERSIZE_CMD, READBUFFERSIZE_CMD, USB_DEV_PATH_CMD, USB_EPIN_PATH_CMD, USB_EPOUT_PATH_CMD, USB_EPINT_PATH_CMD, MANUFACTURER_STRING_CMD, PRODUCT_STRING_CMD, SERIAL_STRING_CMD, VERSION_STRING_CMD, INTERFACE_STRING_CMD, WAIT_CONNECTION, LOOP_ON_DISCONNECT, SHOW_HIDDEN_FILES, UMASK, NO_INOTIFY }; typedef struct kw_list_ { char * keyword; KW_FUNC func; int cmd; }kw_list; static int is_end_line(char c) { if( c == 0 || c == '#' || c == '\r' || c == '\n' ) { return 1; } else { return 0; } } static int is_space(char c) { if( c == ' ' || c == '\t' ) { return 1; } else { return 0; } } static int get_next_word(char * line, int offset) { while( !is_end_line(line[offset]) && ( line[offset] == ' ' ) ) { offset++; } return offset; } static int copy_param(char * dest, char * line, int offs) { int i,insidequote; i = 0; insidequote = 0; while( !is_end_line(line[offs]) && ( insidequote || !is_space(line[offs]) ) && (i < (MAX_CFG_STRING_SIZE - 1)) ) { if(line[offs] != '"') { if(dest) dest[i] = line[offs]; i++; } else { if(insidequote) insidequote = 0; else insidequote = 1; } offs++; } if(dest) dest[i] = 0; return offs; } static int get_param_offset(char * line, int param) { int param_cnt, offs; offs = 0; offs = get_next_word(line, offs); param_cnt = 0; do { offs = copy_param(NULL, line, offs); offs = get_next_word( line, offs ); if(line[offs] == 0 || line[offs] == '#') return -1; param_cnt++; }while( param_cnt < param ); return offs; } static int get_param(char * line, int param_offset,char * param) { int offs; offs = get_param_offset(line, param_offset); if(offs>=0) { offs = copy_param(param, line, offs); return 1; } return -1; } static int extract_cmd(char * line, char * command) { int offs,i; i = 0; offs = 0; offs = get_next_word(line, offs); if( !is_end_line(line[offs]) ) { while( !is_end_line(line[offs]) && !is_space(line[offs]) && i < (MAX_CFG_STRING_SIZE - 1) ) { command[i] = line[offs]; offs++; i++; } command[i] = 0; return i; } return 0; } int test_flag(char * str, char * flag) { int i,flaglen; char previous_char; flaglen = strlen(flag); i = 0; previous_char = 0; while( str[i] ) { if(!strncmp(&str[i],flag,strlen(flag))) { if( (previous_char == 0 || previous_char == ',') && \ (str[i + flaglen] == 0 || str[i + flaglen] == ',') ) { return 1; } } previous_char = str[i]; i++; } return 0; } static int get_storage_params(mtp_ctx * context, char * line,int cmd) { int i, j, k; char storagename[MAX_CFG_STRING_SIZE]; char storagepath[MAX_CFG_STRING_SIZE]; char options[MAX_CFG_STRING_SIZE]; uint32_t flags; i = get_param(line, 2,storagename); j = get_param(line, 1,storagepath); flags = UMTP_STORAGE_READWRITE; if( i >= 0 && j >= 0 ) { k = get_param(line, 3,options); if( k >= 0 ) { if(test_flag(options, "ro")) { flags |= UMTP_STORAGE_READONLY; } if(test_flag(options, "rw")) { flags |= UMTP_STORAGE_READWRITE; } if(test_flag(options, "notmounted")) { flags |= UMTP_STORAGE_NOTMOUNTED; } } PRINT_MSG("Add storage %s - Root Path: %s - Flags: 0x%.8X", storagename, storagepath,flags); mtp_add_storage(context, storagepath, storagename, flags); } return 0; } static int get_hex_param(mtp_ctx * context, char * line,int cmd) { int i; char tmp_txt[MAX_CFG_STRING_SIZE]; unsigned long param_value; i = get_param(line, 1,tmp_txt); if( i >= 0 ) { param_value = strtol(tmp_txt,0,16); switch(cmd) { case USBVENDORID_CMD: context->usb_cfg.usb_vendor_id = param_value; break; case USBPRODUCTID_CMD: context->usb_cfg.usb_product_id = param_value; break; case USBCLASS_CMD: context->usb_cfg.usb_class = param_value; break; case USBSUBCLASS_CMD: context->usb_cfg.usb_subclass = param_value; break; case USBPROTOCOL_CMD: context->usb_cfg.usb_protocol = param_value; break; case USBDEVVERSION_CMD: context->usb_cfg.usb_dev_version = param_value; break; case USBMAXPACKETSIZE_CMD: context->usb_cfg.usb_max_packet_size = param_value; break; case USBMAXRDBUFFERSIZE_CMD: context->usb_rd_buffer_max_size = param_value & (~(512-1)); break; case USBMAXWRBUFFERSIZE_CMD: context->usb_wr_buffer_max_size = param_value & (~(512-1)); break; case READBUFFERSIZE_CMD: context->read_file_buffer_size = param_value; break; case USBFUNCTIONFSMODE_CMD: context->usb_cfg.usb_functionfs_mode = param_value; break; case WAIT_CONNECTION: context->usb_cfg.wait_connection = param_value; break; case LOOP_ON_DISCONNECT: context->usb_cfg.loop_on_disconnect = param_value; break; case SHOW_HIDDEN_FILES: context->usb_cfg.show_hidden_files = param_value; break; case NO_INOTIFY: context->no_inotify = param_value; break; } } return 0; } static int get_str_param(mtp_ctx * context, char * line,int cmd) { int i; char tmp_txt[MAX_CFG_STRING_SIZE]; i = get_param(line, 1,tmp_txt); if( i >= 0 ) { switch(cmd) { case USB_DEV_PATH_CMD: strncpy(context->usb_cfg.usb_device_path,tmp_txt,MAX_CFG_STRING_SIZE); break; case USB_EPIN_PATH_CMD: strncpy(context->usb_cfg.usb_endpoint_in,tmp_txt,MAX_CFG_STRING_SIZE); break; case USB_EPOUT_PATH_CMD: strncpy(context->usb_cfg.usb_endpoint_out,tmp_txt,MAX_CFG_STRING_SIZE); break; case USB_EPINT_PATH_CMD: strncpy(context->usb_cfg.usb_endpoint_intin,tmp_txt,MAX_CFG_STRING_SIZE); break; case MANUFACTURER_STRING_CMD: strncpy(context->usb_cfg.usb_string_manufacturer,tmp_txt,MAX_CFG_STRING_SIZE); break; case PRODUCT_STRING_CMD: strncpy(context->usb_cfg.usb_string_product,tmp_txt,MAX_CFG_STRING_SIZE); break; case SERIAL_STRING_CMD: strncpy(context->usb_cfg.usb_string_serial,tmp_txt,MAX_CFG_STRING_SIZE); break; case VERSION_STRING_CMD: strncpy(context->usb_cfg.usb_string_version,tmp_txt,MAX_CFG_STRING_SIZE); break; case INTERFACE_STRING_CMD: strncpy(context->usb_cfg.usb_string_interface,tmp_txt,MAX_CFG_STRING_SIZE); break; } } return 0; } static int get_oct_param(mtp_ctx * context, char * line,int cmd) { int i; char tmp_txt[MAX_CFG_STRING_SIZE]; unsigned long param_value; i = get_param(line, 1, tmp_txt); if (i >= 0) { param_value = strtol(tmp_txt, 0, 8); switch (cmd) { case UMASK: context->usb_cfg.val_umask = param_value; break; } } return 0; } kw_list kwlist[] = { {"storage", get_storage_params, STORAGE_CMD}, {"usb_vendor_id", get_hex_param, USBVENDORID_CMD}, {"usb_product_id", get_hex_param, USBPRODUCTID_CMD}, {"usb_class", get_hex_param, USBCLASS_CMD}, {"usb_subclass", get_hex_param, USBSUBCLASS_CMD}, {"usb_protocol", get_hex_param, USBPROTOCOL_CMD}, {"usb_dev_version", get_hex_param, USBDEVVERSION_CMD}, {"usb_max_packet_size", get_hex_param, USBMAXPACKETSIZE_CMD}, {"usb_max_rd_buffer_size", get_hex_param, USBMAXRDBUFFERSIZE_CMD}, {"usb_max_wr_buffer_size", get_hex_param, USBMAXWRBUFFERSIZE_CMD}, {"read_buffer_cache_size", get_hex_param, READBUFFERSIZE_CMD}, {"usb_functionfs_mode", get_hex_param, USBFUNCTIONFSMODE_CMD}, {"usb_dev_path", get_str_param, USB_DEV_PATH_CMD}, {"usb_epin_path", get_str_param, USB_EPIN_PATH_CMD}, {"usb_epout_path", get_str_param, USB_EPOUT_PATH_CMD}, {"usb_epint_path", get_str_param, USB_EPINT_PATH_CMD}, {"manufacturer", get_str_param, MANUFACTURER_STRING_CMD}, {"product", get_str_param, PRODUCT_STRING_CMD}, {"serial", get_str_param, SERIAL_STRING_CMD}, {"firmware_version", get_str_param, VERSION_STRING_CMD}, {"interface", get_str_param, INTERFACE_STRING_CMD}, {"wait", get_hex_param, WAIT_CONNECTION}, {"loop_on_disconnect", get_hex_param, LOOP_ON_DISCONNECT}, {"show_hidden_files", get_hex_param, SHOW_HIDDEN_FILES}, {"umask", get_oct_param, UMASK}, {"no_inotify", get_hex_param, NO_INOTIFY}, { 0, 0, 0 } }; static int exec_cmd(mtp_ctx * context, char * command,char * line) { int i; i = 0; while(kwlist[i].func) { if( !strcmp(kwlist[i].keyword,command) ) { kwlist[i].func(context, line, kwlist[i].cmd); return 1; } i++; } return 0; } int execute_line(mtp_ctx * context,char * line) { char command[MAX_CFG_STRING_SIZE]; command[0] = 0; if( extract_cmd(line, command) ) { if(strlen(command)) { if( !exec_cmd(context, command,line)) { PRINT_ERROR("Line syntax error : %s",line); return 0; } } return 1; } return 0; } int mtp_load_config_file(mtp_ctx * context, const char * conffile) { int err = 0; FILE * f; char line[MAX_CFG_STRING_SIZE]; memset((void*)&context->usb_cfg,0x00, sizeof(mtp_usb_cfg)); // Set default config strncpy(context->usb_cfg.usb_device_path, USB_DEV, MAX_CFG_STRING_SIZE); strncpy(context->usb_cfg.usb_endpoint_in, USB_EPIN, MAX_CFG_STRING_SIZE); strncpy(context->usb_cfg.usb_endpoint_out, USB_EPOUT, MAX_CFG_STRING_SIZE); strncpy(context->usb_cfg.usb_endpoint_intin, USB_EPINTIN, MAX_CFG_STRING_SIZE); strncpy(context->usb_cfg.usb_string_manufacturer, MANUFACTURER, MAX_CFG_STRING_SIZE); strncpy(context->usb_cfg.usb_string_product, PRODUCT, MAX_CFG_STRING_SIZE); strncpy(context->usb_cfg.usb_string_serial, SERIALNUMBER, MAX_CFG_STRING_SIZE); strncpy(context->usb_cfg.usb_string_version, "Rev A", MAX_CFG_STRING_SIZE); strncpy(context->usb_cfg.usb_string_interface, "MTP", MAX_CFG_STRING_SIZE); context->usb_cfg.usb_vendor_id = USB_DEV_VENDOR_ID; context->usb_cfg.usb_product_id = USB_DEV_PRODUCT_ID; context->usb_cfg.usb_class = USB_DEV_CLASS; context->usb_cfg.usb_subclass = USB_DEV_SUBCLASS; context->usb_cfg.usb_protocol = USB_DEV_PROTOCOL; context->usb_cfg.usb_dev_version = USB_DEV_VERSION; context->usb_cfg.usb_max_packet_size = MAX_PACKET_SIZE; context->usb_cfg.usb_functionfs_mode = USB_FFS_MODE; context->usb_cfg.wait_connection = 0; context->usb_cfg.loop_on_disconnect = 0; context->usb_cfg.show_hidden_files = 1; context->usb_cfg.val_umask = -1; context->no_inotify = 0; f = fopen(conffile, "r"); if(f) { do { if(!fgets(line,sizeof(line),f)) break; if(feof(f)) break; execute_line(context, line); }while(1); fclose(f); } else { PRINT_ERROR("Can't open %s ! Using default settings...", conffile); } PRINT_MSG("USB Device path : %s",context->usb_cfg.usb_device_path); PRINT_MSG("USB In End point path : %s",context->usb_cfg.usb_endpoint_in); PRINT_MSG("USB Out End point path : %s",context->usb_cfg.usb_endpoint_out); PRINT_MSG("USB Event End point path : %s",context->usb_cfg.usb_endpoint_intin); PRINT_MSG("USB Max packet size : 0x%X bytes",context->usb_cfg.usb_max_packet_size); PRINT_MSG("USB Max write buffer size : 0x%X bytes",context->usb_wr_buffer_max_size); PRINT_MSG("USB Max read buffer size : 0x%X bytes",context->usb_rd_buffer_max_size); PRINT_MSG("Read file buffer size : 0x%X bytes",context->read_file_buffer_size); PRINT_MSG("Manufacturer string : %s",context->usb_cfg.usb_string_manufacturer); PRINT_MSG("Product string : %s",context->usb_cfg.usb_string_product); PRINT_MSG("Serial string : %s",context->usb_cfg.usb_string_serial); PRINT_MSG("Firmware Version string : %s", context->usb_cfg.usb_string_version); PRINT_MSG("Interface string : %s",context->usb_cfg.usb_string_interface); PRINT_MSG("USB Vendor ID : 0x%.4X",context->usb_cfg.usb_vendor_id); PRINT_MSG("USB Product ID : 0x%.4X",context->usb_cfg.usb_product_id); PRINT_MSG("USB class ID : 0x%.2X",context->usb_cfg.usb_class); PRINT_MSG("USB subclass ID : 0x%.2X",context->usb_cfg.usb_subclass); PRINT_MSG("USB Protocol ID : 0x%.2X",context->usb_cfg.usb_protocol); PRINT_MSG("USB Device version : 0x%.4X",context->usb_cfg.usb_dev_version); if(context->usb_cfg.usb_functionfs_mode) { PRINT_MSG("USB FunctionFS Mode"); } else { PRINT_MSG("USB GadgetFS Mode"); } PRINT_MSG("Wait for connection : %i",context->usb_cfg.wait_connection); PRINT_MSG("Loop on disconnect : %i",context->usb_cfg.loop_on_disconnect); PRINT_MSG("Show hidden files : %i",context->usb_cfg.show_hidden_files); if(context->usb_cfg.val_umask >= 0) { PRINT_MSG("File creation umask : %03o",context->usb_cfg.val_umask); } else { PRINT_MSG("File creation umask : System default umask"); } PRINT_MSG("inotify : %s",context->no_inotify?"no":"yes"); return err; } umtp-responder-1.3.10/src/mtp_constant_strings.c000066400000000000000000000544141374176322100220130ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_constant_strings.c * @brief MTP Codes to string decoder (Debug purpose) * @author Jean-François DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_constant.h" const char DevInfos_MTP_Extensions[] = "microsoft.com: 1.0; android.com: 1.0;"; typedef struct _opcodestring { const char * str; uint16_t operation; }opcodestring; typedef struct _propertystring { const char * str; uint16_t property_id; }propertystring; typedef struct _formatstring { const char * str; uint16_t format_id; }formatstring; typedef struct _packettypestring { const char * str; uint16_t type; }packettypestring; const opcodestring op_codes[]= { { "MTP_OPERATION_GET_DEVICE_INFO", 0x1001 }, { "MTP_OPERATION_OPEN_SESSION", 0x1002 }, { "MTP_OPERATION_CLOSE_SESSION", 0x1003 }, { "MTP_OPERATION_GET_STORAGE_IDS", 0x1004 }, { "MTP_OPERATION_GET_STORAGE_INFO", 0x1005 }, { "MTP_OPERATION_GET_NUM_OBJECTS", 0x1006 }, { "MTP_OPERATION_GET_OBJECT_HANDLES", 0x1007 }, { "MTP_OPERATION_GET_OBJECT_INFO", 0x1008 }, { "MTP_OPERATION_GET_OBJECT", 0x1009 }, { "MTP_OPERATION_GET_THUMB", 0x100A }, { "MTP_OPERATION_DELETE_OBJECT", 0x100B }, { "MTP_OPERATION_SEND_OBJECT_INFO", 0x100C }, { "MTP_OPERATION_SEND_OBJECT", 0x100D }, { "MTP_OPERATION_INITIATE_CAPTURE", 0x100E }, { "MTP_OPERATION_FORMAT_STORE", 0x100F }, { "MTP_OPERATION_RESET_DEVICE", 0x1010 }, { "MTP_OPERATION_SELF_TEST", 0x1011 }, { "MTP_OPERATION_SET_OBJECT_PROTECTION", 0x1012 }, { "MTP_OPERATION_POWER_DOWN", 0x1013 }, { "MTP_OPERATION_GET_DEVICE_PROP_DESC", 0x1014 }, { "MTP_OPERATION_GET_DEVICE_PROP_VALUE", 0x1015 }, { "MTP_OPERATION_SET_DEVICE_PROP_VALUE", 0x1016 }, { "MTP_OPERATION_RESET_DEVICE_PROP_VALUE", 0x1017 }, { "MTP_OPERATION_TERMINATE_OPEN_CAPTURE", 0x1018 }, { "MTP_OPERATION_MOVE_OBJECT", 0x1019 }, { "MTP_OPERATION_COPY_OBJECT", 0x101A }, { "MTP_OPERATION_GET_PARTIAL_OBJECT ", 0x101B }, { "MTP_OPERATION_INITIATE_OPEN_CAPTURE", 0x101C }, { "MTP_OPERATION_GET_PARTIAL_OBJECT_64", 0x95C1 }, { "MTP_OPERATION_SEND_PARTIAL_OBJECT", 0x95C2 }, { "MTP_OPERATION_TRUNCATE_OBJECT", 0x95C3 }, { "MTP_OPERATION_BEGIN_EDIT_OBJECT", 0x95C4 }, { "MTP_OPERATION_END_EDIT_OBJECT", 0x95C5 }, { "MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED", 0x9801 }, { "MTP_OPERATION_GET_OBJECT_PROP_DESC ", 0x9802 }, { "MTP_OPERATION_GET_OBJECT_PROP_VALUE", 0x9803 }, { "MTP_OPERATION_SET_OBJECT_PROP_VALUE", 0x9804 }, { "MTP_OPERATION_GET_OBJECT_PROP_LIST ", 0x9805 }, { "MTP_OPERATION_SET_OBJECT_PROP_LIST ", 0x9806 }, { "MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC", 0x9807 }, { "MTP_OPERATION_SEND_OBJECT_PROP_LIST", 0x9808 }, { "MTP_OPERATION_GET_OBJECT_REFERENCES", 0x9810 }, { "MTP_OPERATION_SET_OBJECT_REFERENCES", 0x9811 }, { "MTP_OPERATION_SKIP", 0x9820 }, { 0, 0 } }; const propertystring property_codes[]= { { "MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER", 0xD401 }, { "MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME", 0xD402 }, { "MTP_DEVICE_PROPERTY_IMAGE_SIZE", 0x5003 }, { "MTP_DEVICE_PROPERTY_BATTERY_LEVEL", 0x5001 }, { "MTP_PROPERTY_OBJECT_FORMAT", 0xDC02 }, { "MTP_PROPERTY_STORAGE_ID", 0xDC01 }, { "MTP_PROPERTY_OBJECT_FORMAT", 0xDC02 }, { "MTP_PROPERTY_PROTECTION_STATUS", 0xDC03 }, { "MTP_PROPERTY_OBJECT_SIZE", 0xDC04 }, { "MTP_PROPERTY_ASSOCIATION_TYPE", 0xDC05 }, { "MTP_PROPERTY_ASSOCIATION_DESC", 0xDC06 }, { "MTP_PROPERTY_OBJECT_FILE_NAME", 0xDC07 }, { "MTP_PROPERTY_DATE_CREATED", 0xDC08 }, { "MTP_PROPERTY_DATE_MODIFIED", 0xDC09 }, { "MTP_PROPERTY_KEYWORDS", 0xDC0A }, { "MTP_PROPERTY_PARENT_OBJECT", 0xDC0B }, { "MTP_PROPERTY_ALLOWED_FOLDER_CONTENTS", 0xDC0C }, { "MTP_PROPERTY_HIDDEN", 0xDC0D }, { "MTP_PROPERTY_SYSTEM_OBJECT", 0xDC0E }, { "MTP_PROPERTY_PERSISTENT_UID", 0xDC41 }, { "MTP_PROPERTY_SYNC_ID", 0xDC42 }, { "MTP_PROPERTY_PROPERTY_BAG", 0xDC43 }, { "MTP_PROPERTY_NAME", 0xDC44 }, { "MTP_PROPERTY_CREATED_BY", 0xDC45 }, { "MTP_PROPERTY_ARTIST", 0xDC46 }, { "MTP_PROPERTY_DATE_AUTHORED", 0xDC47 }, { "MTP_PROPERTY_DESCRIPTION", 0xDC48 }, { "MTP_PROPERTY_URL_REFERENCE", 0xDC49 }, { "MTP_PROPERTY_LANGUAGE_LOCALE", 0xDC4A }, { "MTP_PROPERTY_COPYRIGHT_INFORMATION", 0xDC4B }, { "MTP_PROPERTY_SOURCE", 0xDC4C }, { "MTP_PROPERTY_ORIGIN_LOCATION", 0xDC4D }, { "MTP_PROPERTY_DATE_ADDED", 0xDC4E }, { "MTP_PROPERTY_NON_CONSUMABLE", 0xDC4F }, { "MTP_PROPERTY_CORRUPT_UNPLAYABLE", 0xDC50 }, { "MTP_PROPERTY_PRODUCER_SERIAL_NUMBER", 0xDC51 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_FORMAT", 0xDC81 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_SIZE", 0xDC82 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_HEIGHT", 0xDC83 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_WIDTH", 0xDC84 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DURATION", 0xDC85 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DATA", 0xDC86 }, { "MTP_PROPERTY_WIDTH", 0xDC87 }, { "MTP_PROPERTY_HEIGHT", 0xDC88 }, { "MTP_PROPERTY_DURATION", 0xDC89 }, { "MTP_PROPERTY_RATING", 0xDC8A }, { "MTP_PROPERTY_TRACK", 0xDC8B }, { "MTP_PROPERTY_GENRE", 0xDC8C }, { "MTP_PROPERTY_CREDITS", 0xDC8D }, { "MTP_PROPERTY_LYRICS", 0xDC8E }, { "MTP_PROPERTY_SUBSCRIPTION_CONTENT_ID", 0xDC8F }, { "MTP_PROPERTY_PRODUCED_BY", 0xDC90 }, { "MTP_PROPERTY_USE_COUNT", 0xDC91 }, { "MTP_PROPERTY_SKIP_COUNT", 0xDC92 }, { "MTP_PROPERTY_LAST_ACCESSED", 0xDC93 }, { "MTP_PROPERTY_PARENTAL_RATING", 0xDC94 }, { "MTP_PROPERTY_META_GENRE", 0xDC95 }, { "MTP_PROPERTY_COMPOSER", 0xDC96 }, { "MTP_PROPERTY_EFFECTIVE_RATING", 0xDC97 }, { "MTP_PROPERTY_SUBTITLE", 0xDC98 }, { "MTP_PROPERTY_ORIGINAL_RELEASE_DATE", 0xDC99 }, { "MTP_PROPERTY_ALBUM_NAME", 0xDC9A }, { "MTP_PROPERTY_ALBUM_ARTIST", 0xDC9B }, { "MTP_PROPERTY_MOOD", 0xDC9C }, { "MTP_PROPERTY_DRM_STATUS", 0xDC9D }, { "MTP_PROPERTY_SUB_DESCRIPTION", 0xDC9E }, { "MTP_PROPERTY_IS_CROPPED", 0xDCD1 }, { "MTP_PROPERTY_IS_COLOUR_CORRECTED", 0xDCD2 }, { "MTP_PROPERTY_IMAGE_BIT_DEPTH", 0xDCD3 }, { "MTP_PROPERTY_F_NUMBER", 0xDCD4 }, { "MTP_PROPERTY_EXPOSURE_TIME", 0xDCD5 }, { "MTP_PROPERTY_EXPOSURE_INDEX", 0xDCD6 }, { "MTP_PROPERTY_TOTAL_BITRATE", 0xDE91 }, { "MTP_PROPERTY_BITRATE_TYPE", 0xDE92 }, { "MTP_PROPERTY_SAMPLE_RATE", 0xDE93 }, { "MTP_PROPERTY_NUMBER_OF_CHANNELS", 0xDE94 }, { "MTP_PROPERTY_AUDIO_BIT_DEPTH", 0xDE95 }, { "MTP_PROPERTY_SCAN_TYPE", 0xDE97 }, { "MTP_PROPERTY_AUDIO_WAVE_CODEC", 0xDE99 }, { "MTP_PROPERTY_AUDIO_BITRATE", 0xDE9A }, { "MTP_PROPERTY_VIDEO_FOURCC_CODEC", 0xDE9B }, { "MTP_PROPERTY_VIDEO_BITRATE", 0xDE9C }, { "MTP_PROPERTY_FRAMES_PER_THOUSAND_SECONDS", 0xDE9D }, { "MTP_PROPERTY_KEYFRAME_DISTANCE", 0xDE9E }, { "MTP_PROPERTY_BUFFER_SIZE", 0xDE9F }, { "MTP_PROPERTY_ENCODING_QUALITY", 0xDEA0 }, { "MTP_PROPERTY_ENCODING_PROFILE", 0xDEA1 }, { "MTP_PROPERTY_DISPLAY_NAME", 0xDCE0 }, { "MTP_PROPERTY_BODY_TEXT", 0xDCE1 }, { "MTP_PROPERTY_SUBJECT", 0xDCE2 }, { "MTP_PROPERTY_PRIORITY", 0xDCE3 }, { "MTP_PROPERTY_GIVEN_NAME", 0xDD00 }, { "MTP_PROPERTY_MIDDLE_NAMES", 0xDD01 }, { "MTP_PROPERTY_FAMILY_NAME", 0xDD02 }, { "MTP_PROPERTY_PREFIX", 0xDD03 }, { "MTP_PROPERTY_SUFFIX", 0xDD04 }, { "MTP_PROPERTY_PHONETIC_GIVEN_NAME", 0xDD05 }, { "MTP_PROPERTY_PHONETIC_FAMILY_NAME", 0xDD06 }, { "MTP_PROPERTY_EMAIL_PRIMARY", 0xDD07 }, { "MTP_PROPERTY_EMAIL_PERSONAL_1", 0xDD08 }, { "MTP_PROPERTY_EMAIL_PERSONAL_2", 0xDD09 }, { "MTP_PROPERTY_EMAIL_BUSINESS_1", 0xDD0A }, { "MTP_PROPERTY_EMAIL_BUSINESS_2", 0xDD0B }, { "MTP_PROPERTY_EMAIL_OTHERS", 0xDD0C }, { "MTP_PROPERTY_PHONE_NUMBER_PRIMARY", 0xDD0D }, { "MTP_PROPERTY_PHONE_NUMBER_PERSONAL", 0xDD0E }, { "MTP_PROPERTY_PHONE_NUMBER_PERSONAL_2", 0xDD0F }, { "MTP_PROPERTY_PHONE_NUMBER_BUSINESS", 0xDD10 }, { "MTP_PROPERTY_PHONE_NUMBER_BUSINESS_2", 0xDD11 }, { "MTP_PROPERTY_PHONE_NUMBER_MOBILE", 0xDD12 }, { "MTP_PROPERTY_PHONE_NUMBER_MOBILE_2", 0xDD13 }, { "MTP_PROPERTY_FAX_NUMBER_PRIMARY", 0xDD14 }, { "MTP_PROPERTY_FAX_NUMBER_PERSONAL", 0xDD15 }, { "MTP_PROPERTY_FAX_NUMBER_BUSINESS", 0xDD16 }, { "MTP_PROPERTY_PAGER_NUMBER", 0xDD17 }, { "MTP_PROPERTY_PHONE_NUMBER_OTHERS", 0xDD18 }, { "MTP_PROPERTY_PRIMARY_WEB_ADDRESS", 0xDD19 }, { "MTP_PROPERTY_PERSONAL_WEB_ADDRESS", 0xDD1A }, { "MTP_PROPERTY_BUSINESS_WEB_ADDRESS", 0xDD1B }, { "MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS", 0xDD1C }, { "MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_2", 0xDD1D }, { "MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_3", 0xDD1E }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_FULL", 0xDD1F }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_1", 0xDD20 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_2", 0xDD21 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_CITY", 0xDD22 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_REGION", 0xDD23 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_POSTAL_CODE", 0xDD24 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_COUNTRY", 0xDD25 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_FULL", 0xDD26 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_1", 0xDD27 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_2", 0xDD28 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_CITY", 0xDD29 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_REGION", 0xDD2A }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_POSTAL_CODE", 0xDD2B }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_COUNTRY", 0xDD2C }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_FULL", 0xDD2D }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_1", 0xDD2E }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_2", 0xDD2F }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_CITY", 0xDD30 }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_REGION", 0xDD31 }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_POSTAL_CODE", 0xDD32 }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_COUNTRY", 0xDD33 }, { "MTP_PROPERTY_ORGANIZATION_NAME", 0xDD34 }, { "MTP_PROPERTY_PHONETIC_ORGANIZATION_NAME", 0xDD35 }, { "MTP_PROPERTY_ROLE", 0xDD36 }, { "MTP_PROPERTY_BIRTHDATE", 0xDD37 }, { "MTP_PROPERTY_MESSAGE_TO", 0xDD40 }, { "MTP_PROPERTY_MESSAGE_CC", 0xDD41 }, { "MTP_PROPERTY_MESSAGE_BCC", 0xDD42 }, { "MTP_PROPERTY_MESSAGE_READ", 0xDD43 }, { "MTP_PROPERTY_MESSAGE_RECEIVED_TIME", 0xDD44 }, { "MTP_PROPERTY_MESSAGE_SENDER", 0xDD45 }, { "MTP_PROPERTY_ACTIVITY_BEGIN_TIME", 0xDD50 }, { "MTP_PROPERTY_ACTIVITY_END_TIME", 0xDD51 }, { "MTP_PROPERTY_ACTIVITY_LOCATION", 0xDD52 }, { "MTP_PROPERTY_ACTIVITY_REQUIRED_ATTENDEES", 0xDD54 }, { "MTP_PROPERTY_ACTIVITY_OPTIONAL_ATTENDEES", 0xDD55 }, { "MTP_PROPERTY_ACTIVITY_RESOURCES", 0xDD56 }, { "MTP_PROPERTY_ACTIVITY_ACCEPTED", 0xDD57 }, { "MTP_PROPERTY_ACTIVITY_TENTATIVE", 0xDD58 }, { "MTP_PROPERTY_ACTIVITY_DECLINED", 0xDD59 }, { "MTP_PROPERTY_ACTIVITY_REMAINDER_TIME", 0xDD5A }, { "MTP_PROPERTY_ACTIVITY_OWNER", 0xDD5B }, { "MTP_PROPERTY_ACTIVITY_STATUS", 0xDD5C }, { "MTP_PROPERTY_OWNER", 0xDD5D }, { "MTP_PROPERTY_EDITOR", 0xDD5E }, { "MTP_PROPERTY_WEBMASTER", 0xDD5F }, { "MTP_PROPERTY_URL_SOURCE", 0xDD60 }, { "MTP_PROPERTY_URL_DESTINATION", 0xDD61 }, { "MTP_PROPERTY_TIME_BOOKMARK", 0xDD62 }, { "MTP_PROPERTY_OBJECT_BOOKMARK", 0xDD63 }, { "MTP_PROPERTY_BYTE_BOOKMARK", 0xDD64 }, { "MTP_PROPERTY_LAST_BUILD_DATE", 0xDD70 }, { "MTP_PROPERTY_TIME_TO_LIVE", 0xDD71 }, { "MTP_PROPERTY_MEDIA_GUID", 0xDD72 }, { 0, 0 } }; // MTP Format Codes const formatstring format_codes[]= { { "MTP_FORMAT_UNDEFINED", 0x3000 }, // Undefined object { "MTP_FORMAT_ASSOCIATION", 0x3001 }, // Association (for example, a folder) { "MTP_FORMAT_SCRIPT", 0x3002 }, // Device model-specific script { "MTP_FORMAT_EXECUTABLE", 0x3003 }, // Device model-specific binary executable { "MTP_FORMAT_TEXT", 0x3004 }, // Text file { "MTP_FORMAT_HTML", 0x3005 }, // Hypertext Markup Language file (text) { "MTP_FORMAT_DPOF", 0x3006 }, // Digital Print Order Format file (text) { "MTP_FORMAT_AIFF", 0x3007 }, // Audio clip { "MTP_FORMAT_WAV", 0x3008 }, // Audio clip { "MTP_FORMAT_MP3", 0x3009 }, // Audio clip { "MTP_FORMAT_AVI", 0x300A }, // Video clip { "MTP_FORMAT_MPEG", 0x300B }, // Video clip { "MTP_FORMAT_ASF", 0x300C }, // Microsoft Advanced Streaming Format (video) { "MTP_FORMAT_DEFINED", 0x3800 }, // Unknown image object { "MTP_FORMAT_EXIF_JPEG", 0x3801 }, // Exchangeable File Format, JEIDA standard { "MTP_FORMAT_TIFF_EP", 0x3802 }, // Tag Image File Format for Electronic Photography { "MTP_FORMAT_FLASHPIX", 0x3803 }, // Structured Storage Image Format { "MTP_FORMAT_BMP", 0x3804 }, // Microsoft Windows Bitmap file { "MTP_FORMAT_CIFF", 0x3805 }, // Canon Camera Image File Format { "MTP_FORMAT_GIF", 0x3807 }, // Graphics Interchange Format { "MTP_FORMAT_JFIF", 0x3808 }, // JPEG File Interchange Format { "MTP_FORMAT_CD", 0x3809 }, // PhotoCD Image Pac { "MTP_FORMAT_PICT", 0x380A }, // Quickdraw Image Format { "MTP_FORMAT_PNG", 0x380B }, // Portable Network Graphics { "MTP_FORMAT_TIFF", 0x380D }, // Tag Image File Format { "MTP_FORMAT_TIFF_IT", 0x380E }, // Tag Image File Format for Information Technology (graphic arts) { "MTP_FORMAT_JP2", 0x380F }, // JPEG2000 Baseline File Format { "MTP_FORMAT_JPX", 0x3810 }, // JPEG2000 Extended File Format { "MTP_FORMAT_DNG", 0x3811 }, // Digital Negative { "MTP_FORMAT_HEIF", 0x3812 }, // HEIF images { "MTP_FORMAT_UNDEFINED_FIRMWARE", 0xB802 }, { "MTP_FORMAT_WINDOWS_IMAGE_FORMAT", 0xB881 }, { "MTP_FORMAT_UNDEFINED_AUDIO", 0xB900 }, { "MTP_FORMAT_WMA", 0xB901 }, { "MTP_FORMAT_OGG", 0xB902 }, { "MTP_FORMAT_AAC", 0xB903 }, { "MTP_FORMAT_AUDIBLE", 0xB904 }, { "MTP_FORMAT_FLAC", 0xB906 }, { "MTP_FORMAT_UNDEFINED_VIDEO", 0xB980 }, { "MTP_FORMAT_WMV", 0xB981 }, { "MTP_FORMAT_MP4_CONTAINER", 0xB982 }, // ISO 14496-1 { "MTP_FORMAT_MP2", 0xB983 }, { "MTP_FORMAT_3GP_CONTAINER", 0xB984 }, // 3GPP file format. Details: http://www.3gpp.org/ftp/Specs/html-info/26244.htm (page title - \u201cTransparent end-to-end packet switched streaming service, 3GPP file format\u201d). { "MTP_FORMAT_UNDEFINED_COLLECTION", 0xBA00 }, { "MTP_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM", 0xBA01 }, { "MTP_FORMAT_ABSTRACT_IMAGE_ALBUM", 0xBA02 }, { "MTP_FORMAT_ABSTRACT_AUDIO_ALBUM", 0xBA03 }, { "MTP_FORMAT_ABSTRACT_VIDEO_ALBUM", 0xBA04 }, { "MTP_FORMAT_ABSTRACT_AV_PLAYLIST", 0xBA05 }, { "MTP_FORMAT_ABSTRACT_CONTACT_GROUP", 0xBA06 }, { "MTP_FORMAT_ABSTRACT_MESSAGE_FOLDER", 0xBA07 }, { "MTP_FORMAT_ABSTRACT_CHAPTERED_PRODUCTION", 0xBA08 }, { "MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST", 0xBA09 }, { "MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST", 0xBA0A }, { "MTP_FORMAT_ABSTRACT_MEDIACAST", 0xBA0B }, // For use with mediacasts; references multimedia enclosures of RSS feeds or episodic content { "MTP_FORMAT_WPL_PLAYLIST", 0xBA10 }, { "MTP_FORMAT_M3U_PLAYLIST", 0xBA11 }, { "MTP_FORMAT_MPL_PLAYLIST", 0xBA12 }, { "MTP_FORMAT_ASX_PLAYLIST", 0xBA13 }, { "MTP_FORMAT_PLS_PLAYLIST", 0xBA14 }, { "MTP_FORMAT_UNDEFINED_DOCUMENT", 0xBA80 }, { "MTP_FORMAT_ABSTRACT_DOCUMENT", 0xBA81 }, { "MTP_FORMAT_XML_DOCUMENT", 0xBA82 }, { "MTP_FORMAT_MS_WORD_DOCUMENT", 0xBA83 }, { "MTP_FORMAT_MHT_COMPILED_HTML_DOCUMENT", 0xBA84 }, { "MTP_FORMAT_MS_EXCEL_SPREADSHEET", 0xBA85 }, { "MTP_FORMAT_MS_POWERPOINT_PRESENTATION", 0xBA86 }, { "MTP_FORMAT_UNDEFINED_MESSAGE", 0xBB00 }, { "MTP_FORMAT_ABSTRACT_MESSSAGE", 0xBB01 }, { "MTP_FORMAT_UNDEFINED_CONTACT", 0xBB80 }, { "MTP_FORMAT_ABSTRACT_CONTACT", 0xBB81 }, { "MTP_FORMAT_VCARD_2", 0xBB82 }, { 0, 0 } }; const packettypestring packet_types[]= { { "UNDEFINED", 0}, { "OPERATION", 1}, { "DATA", 2}, { "RESPONSE", 3}, { "EVENT", 4}, { 0, 0 } }; const char * mtp_get_operation_string(uint16_t operation) { int i; const char * strptr; strptr = "????"; i = 0; while( op_codes[i].str && op_codes[i].operation != operation ) { i++; } if(op_codes[i].str) strptr = op_codes[i].str; return strptr; } const char * mtp_get_property_string(uint16_t property) { int i; const char * strptr; strptr = "????"; i = 0; while( property_codes[i].str && property_codes[i].property_id != property ) { i++; } if(property_codes[i].str) strptr = property_codes[i].str; return strptr; } const char * mtp_get_format_string(uint16_t format) { int i; const char * strptr; strptr = "????"; i = 0; while( format_codes[i].str && format_codes[i].format_id != format ) { i++; } if(format_codes[i].str) strptr = format_codes[i].str; return strptr; } const char * mtp_get_type_string(uint16_t type) { int i; const char * strptr; strptr = "????"; i = 0; while( packet_types[i].str && packet_types[i].type != type ) { i++; } if(op_codes[i].str) strptr = packet_types[i].str; return strptr; } umtp-responder-1.3.10/src/mtp_datasets.c000066400000000000000000000232431374176322100202150ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_datasets.c * @brief MTP datasets builders * @author Jean-François DEL NERO */ #include "buildconf.h" #include #include #include #include #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_constant_strings.h" #include "mtp_datasets.h" #include "mtp_support_def.h" #include "mtp_properties.h" #include "usb_gadget_fct.h" #include "fs_handles_db.h" #include "logs_out.h" int build_deviceinfo_dataset(mtp_ctx * ctx, void * buffer, int maxsize) { int ofs,i,elements_cnt; ofs = poke16(buffer, 0, maxsize, MTP_VERSION); // Standard Version ofs = poke32(buffer, ofs, maxsize, 0x00000006); // MTP Vendor Extension ID ofs = poke16(buffer, ofs, maxsize, MTP_VERSION); // MTP Version ofs = poke_string(buffer, ofs, maxsize, DevInfos_MTP_Extensions); // MTP Extensions ofs = poke16(buffer, ofs, maxsize, 0x0000); // Functional Mode ofs = poke_array(buffer, ofs, maxsize, supported_op_size, 2, (void*)&supported_op,1); // Operations Supported ofs = poke_array(buffer, ofs, maxsize, supported_event_size, 2, (void*)&supported_event,1); // Events Supported // Supported device properties elements_cnt = 0; while( dev_properties[elements_cnt].prop_code != 0xFFFF ) { elements_cnt++; } ofs = poke32(buffer, ofs, maxsize, elements_cnt); for( i = 0; i < elements_cnt ; i++ ) { ofs = poke16(buffer, ofs, maxsize, dev_properties[i].prop_code); } // Supported formats // Capture Formats... (No capture format) ofs = poke32(buffer, ofs, maxsize, 0x00000000); // Playback Formats elements_cnt = 0; while( fmt_properties[elements_cnt].format_code != 0xFFFF ) { elements_cnt++; } ofs = poke32(buffer, ofs, maxsize, elements_cnt); for( i = 0; i < elements_cnt ; i++ ) { ofs = poke16(buffer, ofs, maxsize, fmt_properties[i].format_code); } ofs = poke_string(buffer, ofs, maxsize, ctx->usb_cfg.usb_string_manufacturer); // Manufacturer ofs = poke_string(buffer, ofs, maxsize, ctx->usb_cfg.usb_string_product); // Model ofs = poke_string(buffer, ofs, maxsize, ctx->usb_cfg.usb_string_version); // Device Version ofs = poke_string(buffer, ofs, maxsize, ctx->usb_cfg.usb_string_serial); // Serial Number return ofs; } int build_storageinfo_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t storageid) { int ofs; char * storage_description; char volumeident[16]; char * storage_path = NULL; struct statvfs fsbuf; uint64_t freespace = 0x4000000000000000U; uint64_t totalspace = 0x8000000000000000U; uint32_t storage_flags; ofs = 0; storage_description = mtp_get_storage_description(ctx,storageid); storage_path = mtp_get_storage_root(ctx, storageid); storage_flags = mtp_get_storage_flags(ctx, storageid); if(storage_description && storage_path) { PRINT_DEBUG("Add storageinfo for %s", storage_path); ofs = poke16(buffer, ofs, maxsize, MTP_STORAGE_FIXED_RAM); // Storage Type ofs = poke16(buffer, ofs, maxsize, MTP_STORAGE_FILESYSTEM_HIERARCHICAL); // Filesystem Type // Access Capability if( storage_flags & UMTP_STORAGE_READONLY ) ofs = poke16(buffer, ofs, maxsize, MTP_STORAGE_READ_ONLY_WITHOUT_DELETE); else ofs = poke16(buffer, ofs, maxsize, MTP_STORAGE_READ_WRITE); if(statvfs(storage_path, &fsbuf) == 0) { totalspace = (uint64_t)fsbuf.f_bsize * (uint64_t)fsbuf.f_blocks; freespace = (uint64_t)fsbuf.f_bsize * (uint64_t)fsbuf.f_bavail; PRINT_DEBUG("Total space %" PRIu64 " byte(s)", totalspace); PRINT_DEBUG("Free space %" PRIu64 " byte(s)", freespace); } else { PRINT_WARN("Failed to get statvfs for %s", storage_path); } ofs = poke32(buffer, ofs, maxsize, totalspace&0x00000000FFFFFFFF); // Max Capacity ofs = poke32(buffer, ofs, maxsize, (totalspace>>32)); // ofs = poke32(buffer, ofs, maxsize, freespace&0x00000000FFFFFFFF); // Free space in Bytes ofs = poke32(buffer, ofs, maxsize, (freespace>>32)); // ofs = poke32(buffer, ofs, maxsize, 0x40000000); // Free Space In Objects ofs = poke_string(buffer, ofs, maxsize, storage_description); // Storage Description sprintf(volumeident,"UMTPRD_%.8X",storageid); ofs = poke_string(buffer, ofs, maxsize, volumeident); // Volume Identifier } else { PRINT_WARN("build_storageinfo_dataset : Storage not found ! (0x%.8X)", storageid); } return ofs; } int build_objectinfo_dataset(mtp_ctx * ctx, void * buffer, int maxsize,fs_entry * entry) { struct stat64 entrystat; time_t t; struct tm lt; int ofs,ret; char * path; char timestr[32]; ofs = 0; ret = -1; path = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); if(path) { ret = stat64(path, &entrystat); } if(ret) { if(path) free(path); return 0; } ofs = poke32(buffer, ofs, maxsize, entry->storage_id); // StorageID (NR) if(entry->flags & ENTRY_IS_DIR) ofs = poke16(buffer, ofs, maxsize, MTP_FORMAT_ASSOCIATION); // ObjectFormat Code else ofs = poke16(buffer, ofs, maxsize, MTP_FORMAT_UNDEFINED); // ObjectFormat Code ofs = poke16(buffer, ofs, maxsize, 0x0000); // Protection Status (NR) entry->size = entrystat.st_size; ofs = poke32(buffer, ofs, maxsize, entry->size); // Object Compressed Size ofs = poke16(buffer, ofs, maxsize, 0x0000); // Thumb Format (NR) ofs = poke32(buffer, ofs, maxsize, 0x00000000); // Thumb Compressed Size (NR) ofs = poke32(buffer, ofs, maxsize, 0x00000000); // Thumb Pix Width (NR) ofs = poke32(buffer, ofs, maxsize, 0x00000000); // Thumb Pix Height (NR) ofs = poke32(buffer, ofs, maxsize, 0x00000000); // Image Pix Width (NR) ofs = poke32(buffer, ofs, maxsize, 0x00000000); // Image Pix Height (NR) ofs = poke32(buffer, ofs, maxsize, 0x00000000); // Image Bit Depth (NR) ofs = poke32(buffer, ofs, maxsize, entry->parent); // Parent Object (NR) if(entry->flags & 0x000001) ofs = poke16(buffer, ofs, maxsize, MTP_ASSOCIATION_TYPE_GENERIC_FOLDER); // Association Type else ofs = poke16(buffer, ofs, maxsize, 0x0000); // Association Type ofs = poke32(buffer, ofs, maxsize, 0x00000000); // Association Description ofs = poke32(buffer, ofs, maxsize, 0x00000000); // Sequence Number (NR) ofs = poke_string(buffer, ofs, maxsize, entry->name); // Filename // Date Created (NR) "YYYYMMDDThhmmss.s" t = entrystat.st_mtime; localtime_r(&t, <); snprintf(timestr,sizeof(timestr),"%.4d%.2d%.2dT%.2d%.2d%.2d",1900 + lt.tm_year, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec); ofs = poke_string(buffer, ofs, maxsize, timestr); // Date Modified (NR) "YYYYMMDDThhmmss.s" t = entrystat.st_mtime; localtime_r(&t, <); snprintf(timestr,sizeof(timestr),"%.4d%.2d%.2dT%.2d%.2d%.2d",1900 + lt.tm_year, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec); ofs = poke_string(buffer, ofs, maxsize, timestr); ofs = poke08(buffer, ofs, maxsize, 0x00); // Keywords (NR) if(path) { free(path); } return ofs; } int build_event_dataset(mtp_ctx * ctx, void * buffer, int maxsize, uint32_t event, uint32_t session, uint32_t transaction, int nbparams, uint32_t * parameters) { int ofs,i; ofs = 0; ofs = poke32(buffer, ofs, maxsize, 0); // Size ofs = poke16(buffer, ofs, maxsize, MTP_CONTAINER_TYPE_EVENT); // Type ofs = poke16(buffer, ofs, maxsize, event ); // Event Code ofs = poke32(buffer, ofs, maxsize, ctx->session_id); // MTP Session ID for(i=0;i */ #include "buildconf.h" #include #include #include "mtp_helpers.h" #include "usbstring.h" #include "mtp_constant.h" #include "logs_out.h" int poke32(void * buffer, int index, int maxsize,uint32_t data) { unsigned char *ptr; if(index < 0) return index; if(index + 4 >= maxsize) { #ifdef DEBUG PRINT_DEBUG("poke32 : buffer overrun operation attempt ! index : %d, maxise : %d",index,maxsize); #endif return -1; } ptr = ((unsigned char *)buffer); ptr += index; *ptr++ = data & 0xFF; *ptr++ = (data>>8) & 0xFF; *ptr++ = (data>>16) & 0xFF; *ptr = (data>>24) & 0xFF; return index + 4; } int poke16(void * buffer, int index, int maxsize, uint16_t data) { unsigned char *ptr; if(index < 0) return index; if(index + 2 >= maxsize) { #ifdef DEBUG PRINT_DEBUG("poke16 : buffer overrun operation attempt ! index : %d, maxise : %d",index,maxsize); #endif return -1; } ptr = ((unsigned char *)buffer); ptr += index; *ptr++ = data & 0xFF; *ptr = (data>>8) & 0xFF; return index + 2; } int poke08(void * buffer, int index, int maxsize, uint8_t data) { if(index < 0) return index; if(index + 1 >= maxsize) { #ifdef DEBUG PRINT_DEBUG("poke08 : buffer overrun operation attempt ! index : %d, maxise : %d",index,maxsize); #endif return -1; } *(((unsigned char *)buffer) + index) = ((uint8_t)data); return index + 1; } uint32_t peek(void * buffer, int index, int typesize) { unsigned char *ptr; uint32_t data; unsigned int shift; ptr = ((unsigned char *)buffer); shift = 0; data = 0x00000000; do { data |= (((uint32_t)ptr[index]) << shift); index++; typesize--; shift += 8; }while( typesize ); return data; } uint64_t peek64(void * buffer, int index, int typesize) { unsigned char *ptr; uint64_t data; unsigned int shift; ptr = ((unsigned char *)buffer); shift = 0; data = 0x0000000000000000; do { data |= (((uint64_t)ptr[index]) << shift); index++; typesize--; shift += 8; }while( typesize ); return data; } int poke_string(void * buffer, int index, int maxsize, const char *str) { unsigned char *ptr; int sizeposition; int len; if(index < 0) return index; ptr = ((unsigned char *)buffer); if( index + 1 >= maxsize ) { #ifdef DEBUG PRINT_DEBUG("poke_string : buffer overrun operation attempt ! index : %d, maxise : %d",index,maxsize); #endif return -1; } // Reserve string size . sizeposition = index; ptr[index] = 0x00; index++; // Char to unicode... len = char2unicodestring((char*)ptr, index, maxsize, (char*)str, 256); if(len < 0) { #ifdef DEBUG PRINT_DEBUG("poke_string : char2unicodestring error %d !",len); #endif return -1; } index += (len*2); // Update size position ptr[sizeposition] = len; return index; } int poke_array(void * buffer, int index, int maxsize, int size, int elementsize, const unsigned char *bufferin,int prefixed) { unsigned char *ptr; int i,nbelement; if(index < 0) return index; if( index + (size + (prefixed*4)) >= maxsize ) { #ifdef DEBUG PRINT_DEBUG("poke_array : buffer overrun operation attempt ! prefixed : %d, index : %d, maxise : %d",prefixed,index,maxsize); #endif return -1; } ptr = ((unsigned char *)buffer); nbelement = size / elementsize; if(prefixed) { ptr[index++] = nbelement&0xFF; ptr[index++] = (nbelement>>8)&0xFF; ptr[index++] = (nbelement>>16)&0xFF; ptr[index++] = (nbelement>>24)&0xFF; } i = 0; while( i < size ) { ptr[index++] = bufferin[i]; i++; } return index; } uint16_t posix_to_mtp_errcode(int err) { uint16_t code; code = MTP_RESPONSE_GENERAL_ERROR; switch(err) { case EBUSY: return MTP_RESPONSE_DEVICE_BUSY; break; case ETXTBSY: return MTP_RESPONSE_DEVICE_BUSY; break; case EACCES: return MTP_RESPONSE_ACCESS_DENIED; break; case EPERM: return MTP_RESPONSE_ACCESS_DENIED; break; case EINPROGRESS: return MTP_RESPONSE_DEVICE_BUSY; break; case EAGAIN: return MTP_RESPONSE_DEVICE_BUSY; break; case EBADF: return MTP_RESPONSE_INVALID_OBJECT_HANDLE; break; case EBADFD: return MTP_RESPONSE_INVALID_OBJECT_HANDLE; break; case ENOENT: return MTP_RESPONSE_INVALID_OBJECT_HANDLE; break; case ECANCELED: return MTP_RESPONSE_INCOMPLETE_TRANSFER; break; case EDQUOT: return MTP_RESPONSE_STORAGE_FULL; break; case EEXIST: break; case EFBIG: return MTP_RESPONSE_STORAGE_FULL; break; case EHWPOISON: return MTP_RESPONSE_GENERAL_ERROR; break; case EINTR: return MTP_RESPONSE_GENERAL_ERROR; break; case EINVAL: return MTP_RESPONSE_INVALID_PARAMETER; break; case EREMOTEIO: case EIO: return MTP_RESPONSE_GENERAL_ERROR; break; case EISDIR: return MTP_RESPONSE_INVALID_PARAMETER; break; case ELIBACC: case ELIBBAD: case ELIBSCN: case ELIBMAX: case ELIBEXEC: case ENOEXEC: case ENOPKG: case ENOSYS: case ENOTRECOVERABLE: case ENOTSUP: case EPIPE: return MTP_RESPONSE_GENERAL_ERROR; break; case ELOOP: return MTP_RESPONSE_INCOMPLETE_TRANSFER; break; case EMEDIUMTYPE: return MTP_RESPONSE_INVALID_OBJECT_HANDLE; break; case EMFILE: return MTP_RESPONSE_STORAGE_FULL; break; case EMLINK: return MTP_RESPONSE_STORAGE_FULL; break; case ENOSPC: return MTP_RESPONSE_STORAGE_FULL; break; case ENOMEM: return MTP_RESPONSE_GENERAL_ERROR; break; case ENAMETOOLONG: return MTP_RESPONSE_INVALID_PARAMETER; break; case ENFILE: return MTP_RESPONSE_GENERAL_ERROR; break; case ENODEV: return MTP_RESPONSE_INVALID_PARAMETER; break; case ENOLINK: return MTP_RESPONSE_INVALID_OBJECT_HANDLE; break; case ENOMEDIUM: return MTP_RESPONSE_INVALID_OBJECT_HANDLE; break; case ENOTBLK: return MTP_RESPONSE_INVALID_OBJECT_HANDLE; break; case ENOTDIR: return MTP_RESPONSE_ACCESS_DENIED; break; case ENOTEMPTY: return MTP_RESPONSE_PARTIAL_DELETION; break; case EROFS: return MTP_RESPONSE_STORE_READ_ONLY; break; case ESPIPE: return MTP_RESPONSE_GENERAL_ERROR; break; case ESTALE: return MTP_RESPONSE_INVALID_OBJECT_HANDLE; break; } return code; } umtp-responder-1.3.10/src/mtp_operations/000077500000000000000000000000001374176322100204205ustar00rootroot00000000000000umtp-responder-1.3.10/src/mtp_operations/mtp_op_begineditobject.c000066400000000000000000000032141374176322100252630ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_begineditobject.c * @brief begin edit object operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "logs_out.h" uint32_t mtp_op_BeginEditObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t handle; uint32_t response_code; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); response_code = MTP_RESPONSE_OK; handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); check_handle_access( ctx, NULL, handle, 1, &response_code); pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_closesession.c000066400000000000000000000026121374176322100246540ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_closesession.c * @brief Close session operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "logs_out.h" uint32_t mtp_op_CloseSession(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; deinit_fs_db(ctx->fs_db); ctx->fs_db = 0; return MTP_RESPONSE_OK; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_deleteobject.c000066400000000000000000000035701374176322100246000ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_deleteobject.c * @brief Delete object operation * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_ops_helpers.h" #include "logs_out.h" uint32_t mtp_op_DeleteObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t response_code; uint32_t handle; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - object handle if( check_handle_access( ctx, NULL, handle, 1, &response_code) ) { pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; } if(delete_tree(ctx, handle)) { response_code = MTP_RESPONSE_OBJECT_WRITE_PROTECTED; } else { response_code = MTP_RESPONSE_OK; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_endeditobject.c000066400000000000000000000032051374176322100247450ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_endeditobject.c * @brief End edit object operation * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "logs_out.h" uint32_t mtp_op_EndEditObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t handle; uint32_t response_code; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); response_code = MTP_RESPONSE_OK; handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); check_handle_access( ctx, NULL, handle, 1, &response_code); pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getdeviceinfos.c000066400000000000000000000041611374176322100251420ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getdeviceinfos.c * @brief get device infos operation * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_datasets.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetDeviceInfos(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { int sz,tmp_sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size,0,0); if(sz < 0) goto error; tmp_sz = build_deviceinfo_dataset(ctx, ctx->wrbuffer + sizeof(MTP_PACKET_HEADER), ctx->usb_wr_buffer_max_size - sizeof(MTP_PACKET_HEADER)); if(tmp_sz < 0) goto error; sz += tmp_sz; // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sz); PRINT_DEBUG("MTP_OPERATION_GET_DEVICE_INFO response (%d Bytes):", sz); PRINT_DEBUG_BUF(ctx->wrbuffer, sz); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer, sz); check_and_send_USB_ZLP(ctx , sz ); *size = sz; return MTP_RESPONSE_OK; error: return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getdevicepropdesc.c000066400000000000000000000054161374176322100256470ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getdevicepropdesc.c * @brief get device prop desc operation * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_constant_strings.h" #include "mtp_operations.h" #include "mtp_properties.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetDevicePropDesc(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t property_id; uint32_t response_code; int sz,tmp_sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); property_id = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - property id sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(sz < 0) goto error; tmp_sz = build_device_properties_dataset(ctx,ctx->wrbuffer + sizeof(MTP_PACKET_HEADER), ctx->usb_wr_buffer_max_size - sizeof(MTP_PACKET_HEADER), property_id); if(tmp_sz < 0) goto error; sz += tmp_sz; if ( sz > sizeof(MTP_PACKET_HEADER) ) { // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sz); PRINT_DEBUG("MTP_OPERATION_GET_DEVICE_PROP_DESC response (%d Bytes):",sz); PRINT_DEBUG_BUF(ctx->wrbuffer, sz); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,sz); check_and_send_USB_ZLP(ctx , sz ); *size = sz; response_code = MTP_RESPONSE_OK; } else { PRINT_WARN("MTP_OPERATION_GET_DEVICE_PROP_DESC : Property unsupported ! : 0x%.4X (%s)", property_id, mtp_get_property_string(property_id)); response_code = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getdevicepropvalue.c000066400000000000000000000052271374176322100260450ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getdevicepropvalue.c * @brief get device prop value operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_properties.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetDevicePropValue(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t response_code,prop_code; int sz,tmp_sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); prop_code = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - PropCode PRINT_DEBUG("MTP_OPERATION_GET_DEVICE_PROP_VALUE : (Prop code : 0x%.4X )", prop_code); sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(sz < 0) goto error; tmp_sz = build_DevicePropValue_dataset(ctx,ctx->wrbuffer + sizeof(MTP_PACKET_HEADER), ctx->usb_wr_buffer_max_size - sizeof(MTP_PACKET_HEADER), prop_code); if(tmp_sz < 0) goto error; sz += tmp_sz; if ( sz > sizeof(MTP_PACKET_HEADER) ) { // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sz); PRINT_DEBUG("MTP_OPERATION_GET_DEVICE_PROP_VALUE response (%d Bytes):",sz); PRINT_DEBUG_BUF(ctx->wrbuffer, sz); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,sz); check_and_send_USB_ZLP(ctx , sz ); *size = sz; response_code = MTP_RESPONSE_OK; } else { response_code = MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getobject.c000066400000000000000000000050651374176322100241160ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getobject.c * @brief get object operation * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_ops_helpers.h" #include "logs_out.h" uint32_t mtp_op_GetObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { int sz; uint32_t response_code; uint32_t handle; fs_entry * entry; mtp_size actualsize; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - object handle entry = get_entry_by_handle(ctx->fs_db, handle); if(entry) { if( check_handle_access( ctx, entry, handle, 0, &response_code) ) { pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; } sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(sz<0) goto error; actualsize = send_file_data( ctx, entry, 0, entry->size ); if( actualsize >= 0) { *size = sz; response_code = MTP_RESPONSE_OK; } else { if(actualsize == -2) response_code = MTP_RESPONSE_NO_RESPONSE; else response_code = MTP_RESPONSE_INCOMPLETE_TRANSFER; } } else { PRINT_WARN("MTP_OPERATION_GET_OBJECT ! : Entry/Handle not found (0x%.8X)", handle); response_code = MTP_RESPONSE_INVALID_OBJECT_HANDLE; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getobjecthandles.c000066400000000000000000000111531374176322100254500ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getobjecthandles.c * @brief get object handles operation * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "usb_gadget_fct.h" #include "inotify.h" #include "logs_out.h" uint32_t mtp_op_GetObjectHandles(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { int ofs; uint32_t storageid; uint32_t parent_handle; int handle_index; int nb_of_handles; fs_entry * entry; char * full_path; char * tmp_str; int sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); storageid = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 0, 4); // Get param 1 - Storage ID sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(sz < 0) goto error; parent_handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER)+ 8, 4); // Get param 3 - parent handle PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_HANDLES - Parent Handle 0x%.8x, Storage ID 0x%.8x",parent_handle,storageid); if(!mtp_get_storage_root(ctx,storageid)) { PRINT_WARN("MTP_OPERATION_GET_OBJECT_HANDLES : INVALID STORAGE ID!"); return MTP_RESPONSE_INVALID_STORAGE_ID; } tmp_str = NULL; full_path = NULL; entry = NULL; if(parent_handle && parent_handle!=0xFFFFFFFF) { entry = get_entry_by_handle(ctx->fs_db, parent_handle); if(entry) { tmp_str = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); full_path = tmp_str; } } else { // root folder parent_handle = 0x00000000; full_path = mtp_get_storage_root(ctx,storageid); entry = get_entry_by_handle(ctx->fs_db, parent_handle); } nb_of_handles = 0; if( full_path ) { // Count the number of files... scan_and_add_folder(ctx->fs_db, full_path, parent_handle, storageid); init_search_handle(ctx->fs_db, parent_handle, storageid); while( get_next_child_handle(ctx->fs_db) ) { nb_of_handles++; } PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_HANDLES - %d objects found",nb_of_handles); // Restart init_search_handle(ctx->fs_db, parent_handle, storageid); // Register a watch point. if( entry ) { if ( entry->flags & ENTRY_IS_DIR ) { entry->watch_descriptor = inotify_handler_addwatch( ctx, full_path ); } } if (tmp_str) free(tmp_str); } // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sizeof(MTP_PACKET_HEADER) + ((1+nb_of_handles)*4) ); // Build and send the handles array ofs = sizeof(MTP_PACKET_HEADER); ofs = poke32(ctx->wrbuffer, ofs, ctx->usb_wr_buffer_max_size, nb_of_handles); PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_HANDLES response :"); handle_index = 0; do { do { entry = get_next_child_handle(ctx->fs_db); if(entry) { PRINT_DEBUG("File : %s Handle:%.8x",entry->name,entry->handle); ofs = poke32(ctx->wrbuffer, ofs, ctx->usb_wr_buffer_max_size, entry->handle); handle_index++; } }while( ofs >= 0 && ofs < ctx->max_packet_size && handle_index < nb_of_handles); if(sz < 0) goto error; PRINT_DEBUG_BUF(ctx->wrbuffer, ofs); // Current usb packet full, need to send it. write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,ofs); ofs = 0; }while( handle_index < nb_of_handles); // Total size = Header size + nb of handles field (uint32_t) + all handles check_and_send_USB_ZLP(ctx , sizeof(MTP_PACKET_HEADER) + sizeof(uint32_t) + (nb_of_handles * sizeof(uint32_t)) ); pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_OK; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getobjectinfo.c000066400000000000000000000052721374176322100247720ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getobjectinfo.c * @brief get object info operation * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_datasets.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetObjectInfo(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t handle; uint32_t response_code; int sz,tmp_sz; fs_entry * entry; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - object handle entry = get_entry_by_handle(ctx->fs_db, handle); if( entry ) { sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(sz<0) goto error; tmp_sz = build_objectinfo_dataset(ctx, ctx->wrbuffer + sizeof(MTP_PACKET_HEADER), ctx->usb_wr_buffer_max_size - sizeof(MTP_PACKET_HEADER),entry); if(tmp_sz<0) goto error; sz += tmp_sz; // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sz); PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_INFO response (%d Bytes):",sz); PRINT_DEBUG_BUF(ctx->wrbuffer, sz); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,sz); check_and_send_USB_ZLP(ctx , sz ); *size = sz; response_code = MTP_RESPONSE_OK; } else { PRINT_WARN("MTP_OPERATION_GET_OBJECT_INFO ! : Entry/Handle not found (0x%.8X)", handle); response_code = MTP_RESPONSE_INVALID_OBJECT_HANDLE; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getobjectpropdesc.c000066400000000000000000000057071374176322100256610ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getobjectpropdesc.c * @brief get object prop desc operation * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_constant_strings.h" #include "mtp_operations.h" #include "mtp_properties.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetObjectPropDesc(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t response_code; uint32_t format_id; uint32_t property_id; int sz,tmp_sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); property_id = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - property id format_id = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 4, 4); // Get param 2 - format sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(sz < 0) goto error; tmp_sz = build_properties_dataset(ctx,ctx->wrbuffer + sizeof(MTP_PACKET_HEADER), ctx->usb_wr_buffer_max_size - sizeof(MTP_PACKET_HEADER), property_id,format_id); if(tmp_sz<0) goto error; sz += tmp_sz; if ( sz > sizeof(MTP_PACKET_HEADER) ) { // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sz); PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_PROP_DESC response (%d Bytes):",sz); PRINT_DEBUG_BUF(ctx->wrbuffer, sz); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,sz); check_and_send_USB_ZLP(ctx , sz ); *size = sz; response_code = MTP_RESPONSE_OK; } else { PRINT_WARN("MTP_OPERATION_GET_OBJECT_PROP_DESC : Property unsupported ! : 0x%.4X (%s) (Format : 0x%.4X - %s )", property_id, mtp_get_property_string(property_id), format_id, mtp_get_format_string(format_id)); response_code = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getobjectproplist.c000066400000000000000000000073521374176322100257140ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getobjectproplist.c * @brief get object prop list operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_properties.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetObjectPropList(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { fs_entry * entry; uint32_t response_code; uint32_t handle; uint32_t format_id; uint32_t prop_code; uint32_t prop_group_code; uint32_t depth; int sz,tmp_sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); format_id = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 4, 4); prop_code = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 8, 4); prop_group_code = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 12, 4); depth = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 16, 4); PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_PROP_LIST :(Handle: 0x%.8X FormatCode: 0x%.8X ObjPropCode: 0x%.8X ObjPropGroupCode: 0x%.8X Depth: %d)", handle, format_id, prop_code, prop_group_code, depth); if( format_id != 0x00000000 ) { // Specification by format not currently supported response_code = MTP_RESPONSE_SPECIFICATION_BY_FORMAT_UNSUPPORTED; } if( prop_code == 0x00000000 ) { // ObjectPropGroupCode not currently supported if( prop_group_code == 0x00000000 ) { response_code = MTP_RESPONSE_PARAMETER_NOT_SUPPORTED; PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_PROP_LIST : ObjectPropGroupCode not currently supported !"); pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_PARAMETER_NOT_SUPPORTED; } else { } } entry = get_entry_by_handle(ctx->fs_db, handle); if( entry ) { sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size,0,0); if(sz < 0) goto error; tmp_sz = build_objectproplist_dataset(ctx, ctx->wrbuffer + sizeof(MTP_PACKET_HEADER),ctx->usb_wr_buffer_max_size - sizeof(MTP_PACKET_HEADER),entry, handle, format_id, prop_code, prop_group_code, depth); if( tmp_sz < 0) goto error; sz += tmp_sz; // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sz); PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_PROP_LIST response (%d Bytes):",sz); PRINT_DEBUG_BUF(ctx->wrbuffer, sz); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,sz); check_and_send_USB_ZLP(ctx , sz ); *size = sz; response_code = MTP_RESPONSE_OK; } else { response_code = MTP_RESPONSE_INVALID_OBJECT_HANDLE; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getobjectpropssupported.c000066400000000000000000000044351374176322100271500ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getobjectpropssupported.c * @brief get object props supported operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_properties.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetObjectPropsSupported(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t format_id; int sz,tmp_sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; format_id = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - format sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(sz < 0) goto error; tmp_sz = build_properties_supported_dataset(ctx,ctx->wrbuffer + sizeof(MTP_PACKET_HEADER), ctx->usb_wr_buffer_max_size - sizeof(MTP_PACKET_HEADER), format_id); if(tmp_sz < 0) goto error; sz += tmp_sz; // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sz); PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED response (%d Bytes):",sz); PRINT_DEBUG_BUF(ctx->wrbuffer, sz); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,sz); check_and_send_USB_ZLP(ctx , sz ); *size = sz; return MTP_RESPONSE_OK; error: return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getobjectpropvalue.c000066400000000000000000000057371374176322100260620ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getobjectpropvalue.c * @brief get oject prop value operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_properties.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetObjectPropValue(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t response_code; uint32_t handle; uint32_t prop_code; fs_entry * entry; int sz,tmp_sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - object handle prop_code = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 4, 4); // Get param 2 - PropCode PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_PROP_VALUE : (Handle : 0x%.8X - Prop code : 0x%.4X )", handle, prop_code); entry = get_entry_by_handle(ctx->fs_db, handle); if( entry ) { sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if( sz < 0 ) goto error; tmp_sz = build_ObjectPropValue_dataset(ctx,ctx->wrbuffer + sizeof(MTP_PACKET_HEADER), ctx->usb_wr_buffer_max_size - sizeof(MTP_PACKET_HEADER), handle, prop_code); if( tmp_sz < 0 ) goto error; sz += tmp_sz; // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sz); PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_PROP_VALUE response (%d Bytes):",sz); PRINT_DEBUG_BUF(ctx->wrbuffer, sz); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,sz); check_and_send_USB_ZLP(ctx , sz ); *size = sz; response_code = MTP_RESPONSE_OK; } else { PRINT_WARN("MTP_OPERATION_GET_OBJECT_PROP_VALUE ! : Entry/Handle not found (0x%.8X)", handle); response_code = MTP_RESPONSE_INVALID_OBJECT_HANDLE; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getobjectreferences.c000066400000000000000000000046571374176322100261660ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getobjectreferences.c * @brief get object references operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetObjectReferences(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t response_code; uint32_t handle; fs_entry * entry; int sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); entry = get_entry_by_handle(ctx->fs_db, handle); if( entry ) { sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); sz = poke32(ctx->wrbuffer, sz, ctx->usb_wr_buffer_max_size, 0x0000000); if(sz < 0) goto error; // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sz); PRINT_DEBUG("MTP_OPERATION_GET_OBJECT_REFERENCES response (%d Bytes):",sz); PRINT_DEBUG_BUF(ctx->wrbuffer, sz); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,sz); check_and_send_USB_ZLP(ctx , sz ); response_code = MTP_RESPONSE_OK; *size = sz; } else { response_code = MTP_RESPONSE_INVALID_OBJECT_HANDLE; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getpartialobject.c000066400000000000000000000067631374176322100255010ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getpartialobject.c * @brief get partial object operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_ops_helpers.h" #include "logs_out.h" uint32_t mtp_op_GetPartialObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { int sz; uint32_t response_code; uint32_t handle; fs_entry * entry; mtp_size actualsize; mtp_offset offset; int maxsize; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - Object handle if( mtp_packet_hdr->code == MTP_OPERATION_GET_PARTIAL_OBJECT_64 ) { offset = peek64(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 4, 8); // Get param 2 - Offset in bytes maxsize = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 12, 4); // Get param 3 - Max size in bytes entry = get_entry_by_handle(ctx->fs_db, handle); PRINT_DEBUG("MTP_OPERATION_GET_PARTIAL_OBJECT_64 : handle 0x%.8X - Offset 0x%"SIZEHEX" - Maxsize 0x%.8X", handle,offset,maxsize); } else { offset = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 4, 4); // Get param 2 - Offset in bytes maxsize = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 8, 4); // Get param 3 - Max size in bytes entry = get_entry_by_handle(ctx->fs_db, handle); PRINT_DEBUG("MTP_OPERATION_GET_PARTIAL_OBJECT : handle 0x%.8X - Offset 0x%"SIZEHEX" - Maxsize 0x%.8X", handle,offset,maxsize); } if( check_handle_access( ctx, entry, handle, 0, &response_code) ) { pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; } if(entry) { sz = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(sz < 0) goto error; actualsize = send_file_data( ctx, entry, offset, maxsize ); if( actualsize >= 0 ) { ret_params[0] = actualsize & 0xFFFFFFFF; *ret_params_size = sizeof(uint32_t); } else { if(actualsize == -2) { pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_NO_RESPONSE; } } *size = sz; response_code = MTP_RESPONSE_OK; } else { PRINT_WARN("MTP_OPERATION_GET_PARTIAL_OBJECT ! : Entry/Handle not found (0x%.8X)", handle); response_code = MTP_RESPONSE_INVALID_OBJECT_HANDLE; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; error: pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getstorageids.c000066400000000000000000000044271374176322100250150ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getstorageids.c * @brief get storage ids operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetStorageIDs(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { int ofs,i,cnt; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; ofs = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(ofs < 0) goto error; cnt = 0; i = 0; while( (i < MAX_STORAGE_NB) && ctx->storages[i].root_path) { if( !(ctx->storages[i].flags & UMTP_STORAGE_NOTMOUNTED) ) { ctx->temp_array[cnt] = ctx->storages[i].storage_id; // Storage ID cnt++; } i++; } ofs = poke_array(ctx->wrbuffer, ofs, ctx->usb_wr_buffer_max_size, 4 * cnt, 4, (void*)ctx->temp_array, 1); if(ofs < 0) goto error; // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, ofs); PRINT_DEBUG("MTP_OPERATION_GET_STORAGE_IDS response (%d Bytes):",ofs); PRINT_DEBUG_BUF(ctx->wrbuffer, ofs); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,ofs); check_and_send_USB_ZLP(ctx , ofs ); *size = ofs; return MTP_RESPONSE_OK; error: return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_getstorageinfo.c000066400000000000000000000045701374176322100251700ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_getstorageinfo.c * @brief get storage info operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "mtp_datasets.h" #include "usb_gadget_fct.h" #include "logs_out.h" uint32_t mtp_op_GetStorageInfo(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { int ofs,tmp_ofs; uint32_t storageid; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; storageid = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 0, 4); // Get param 1 - Storage ID if( mtp_get_storage_root(ctx,storageid) ) { ofs = build_response(ctx, mtp_packet_hdr->tx_id, MTP_CONTAINER_TYPE_DATA, mtp_packet_hdr->code, ctx->wrbuffer, ctx->usb_wr_buffer_max_size, 0,0); if(ofs < 0) goto error; tmp_ofs = build_storageinfo_dataset(ctx, ctx->wrbuffer + sizeof(MTP_PACKET_HEADER), ctx->usb_wr_buffer_max_size - sizeof(MTP_PACKET_HEADER),storageid); if(tmp_ofs < 0) goto error; ofs += tmp_ofs; // Update packet size poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, ofs); PRINT_DEBUG("MTP_OPERATION_GET_STORAGE_INFO response (%d Bytes):",ofs); PRINT_DEBUG_BUF(ctx->wrbuffer, ofs); write_usb(ctx->usb_ctx,EP_DESCRIPTOR_IN,ctx->wrbuffer,ofs); check_and_send_USB_ZLP(ctx , ofs ); *size = ofs; return MTP_RESPONSE_OK; } else { return MTP_RESPONSE_INVALID_STORAGE_ID; } error: return MTP_RESPONSE_GENERAL_ERROR; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_opensession.c000066400000000000000000000036261374176322100245160ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_opensession.c * @brief open session operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "logs_out.h" uint32_t mtp_op_OpenSession(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { int i; uint32_t id; id = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 if(!id) { return MTP_RESPONSE_INVALID_PARAMETER; } if(ctx->fs_db) { ret_params[0] = ctx->session_id; *ret_params_size = 1; return MTP_RESPONSE_SESSION_ALREADY_OPEN; } ctx->session_id = id; ctx->fs_db = init_fs_db(ctx); i = 0; while( (i < MAX_STORAGE_NB) && ctx->storages[i].root_path) { pthread_mutex_lock( &ctx->inotify_mutex ); alloc_root_entry(ctx->fs_db, ctx->storages[i].storage_id); pthread_mutex_unlock( &ctx->inotify_mutex ); i++; } PRINT_DEBUG("Open session - ID 0x%.8x",ctx->session_id); return MTP_RESPONSE_OK; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_sendobject.c000066400000000000000000000122261374176322100242650ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_sendobject.c * @brief send object operation. * @author Jean-François DEL NERO */ #include "buildconf.h" #include #include #include #include #include #include #include #include "logs_out.h" #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "usb_gadget_fct.h" uint32_t mtp_op_SendObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t response_code; fs_entry * entry; unsigned char * tmp_ptr; char * full_path; int file; int sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); response_code = MTP_RESPONSE_GENERAL_ERROR; if( mtp_packet_hdr->code == MTP_OPERATION_SEND_PARTIAL_OBJECT && mtp_packet_hdr->operation == MTP_CONTAINER_TYPE_COMMAND ) { ctx->SendObjInfoHandle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - Object handle ctx->SendObjInfoOffset = peek64(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 4, 8); // Get param 2 - Offset in bytes ctx->SendObjInfoSize = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 12, 4); // Get param 3 - Max size in bytes } if( ctx->SendObjInfoHandle != 0xFFFFFFFF ) { switch(mtp_packet_hdr->operation) { case MTP_CONTAINER_TYPE_DATA: entry = get_entry_by_handle(ctx->fs_db, ctx->SendObjInfoHandle); if(entry) { response_code = MTP_RESPONSE_GENERAL_ERROR; if( check_handle_access( ctx, entry, 0x00000000, 1, &response_code) ) { return response_code; } full_path = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); if(full_path) { if( mtp_packet_hdr->code == MTP_OPERATION_SEND_PARTIAL_OBJECT ) file = open(full_path,O_RDWR | O_LARGEFILE); else file = open(full_path,O_CREAT|O_WRONLY|O_TRUNC| O_LARGEFILE, S_IRUSR|S_IWUSR); if( file != -1 ) { ctx->transferring_file_data = 1; lseek64(file, ctx->SendObjInfoOffset, SEEK_SET); sz = *size - sizeof(MTP_PACKET_HEADER); tmp_ptr = ((unsigned char*)mtp_packet_hdr) ; tmp_ptr += sizeof(MTP_PACKET_HEADER); if(sz > 0) { if( write(file, tmp_ptr, sz) != sz) { // TODO : Handle this error case properly } ctx->SendObjInfoSize -= sz; } tmp_ptr = ctx->rdbuffer2; if( sz == ( ctx->usb_rd_buffer_max_size - sizeof(MTP_PACKET_HEADER) ) ) { sz = ctx->usb_rd_buffer_max_size; } if( mtp_packet_hdr->code == MTP_OPERATION_SEND_PARTIAL_OBJECT && ctx->SendObjInfoSize ) { sz = ctx->usb_rd_buffer_max_size; } while( sz == ctx->usb_rd_buffer_max_size && !ctx->cancel_req) { sz = read_usb(ctx->usb_ctx, ctx->rdbuffer2, ctx->usb_rd_buffer_max_size); if( write(file, tmp_ptr, sz) != sz) { // TODO : Handle this error case properly } ctx->SendObjInfoSize -= sz; }; entry->size = lseek64(file, 0, SEEK_END); ctx->transferring_file_data = 0; close(file); if(ctx->usb_cfg.val_umask >= 0) chmod(full_path, 0777 & (~ctx->usb_cfg.val_umask)); if(ctx->cancel_req) { ctx->cancel_req = 0; free( full_path ); pthread_mutex_unlock( &ctx->inotify_mutex ); return MTP_RESPONSE_NO_RESPONSE; } response_code = MTP_RESPONSE_OK; } free( full_path ); } } else { response_code = MTP_RESPONSE_INVALID_OBJECT_HANDLE; } break; case MTP_CONTAINER_TYPE_COMMAND: PRINT_DEBUG("SEND_OBJECT : Handle 0x%.8x, Offset 0x%"SIZEHEX", Size 0x%"SIZEHEX,ctx->SendObjInfoHandle,ctx->SendObjInfoOffset,ctx->SendObjInfoSize); if( check_handle_access( ctx, NULL, ctx->SendObjInfoHandle, 1, &response_code) ) { return response_code; } // no response to send, wait for the data... response_code = MTP_RESPONSE_NO_RESPONSE; break; default: break; } } else { PRINT_WARN("MTP_OPERATION_SEND_OBJECT ! : Invalid Handle (0x%.8X)", ctx->SendObjInfoHandle); response_code = MTP_RESPONSE_INVALID_OBJECT_HANDLE; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_sendobjectinfo.c000066400000000000000000000046441374176322100251460ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_sendobjectinfo.c * @brief send object info operation * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "logs_out.h" #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "usb_gadget_fct.h" uint32_t mtp_op_SendObjectInfo(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t response_code; uint32_t storageid; uint32_t parent_handle; uint32_t new_handle; int sz; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); storageid = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - storage id parent_handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 4, 4); // Get param 2 - parent handle PRINT_DEBUG("MTP_OPERATION_SEND_OBJECT_INFO : Rx dataset..."); sz = read_usb(ctx->usb_ctx, ctx->rdbuffer2, ctx->usb_rd_buffer_max_size); PRINT_DEBUG_BUF(ctx->rdbuffer2, sz); new_handle = 0xFFFFFFFF; response_code = parse_incomming_dataset(ctx,ctx->rdbuffer2,sz,&new_handle,parent_handle,storageid); if( response_code == MTP_RESPONSE_OK ) { PRINT_DEBUG("MTP_OPERATION_SEND_OBJECT_INFO : Response - storageid: 0x%.8X, parent_handle: 0x%.8X, new_handle: 0x%.8X ",storageid,parent_handle,new_handle); ret_params[0] = storageid; ret_params[1] = parent_handle; ret_params[2] = new_handle; *ret_params_size = sizeof(uint32_t) * 3; } pthread_mutex_unlock( &ctx->inotify_mutex ); *size = sz; return response_code; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_setobjectpropvalue.c000066400000000000000000000041521374176322100260640ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_setobjectpropvalue.c * @brief set object prop value operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include "logs_out.h" #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_properties.h" #include "mtp_operations.h" uint32_t mtp_op_SetObjectPropValue(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t response_code; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; switch(mtp_packet_hdr->operation) { case MTP_CONTAINER_TYPE_COMMAND: ctx->SetObjectPropValue_Handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); // Get param 1 - handle ctx->SetObjectPropValue_PropCode = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 4, 4); // Get param 2 - PropCode // no response to send, wait for the data... response_code = MTP_RESPONSE_NO_RESPONSE; break; case MTP_CONTAINER_TYPE_DATA: response_code = setObjectPropValue(ctx, mtp_packet_hdr, ctx->SetObjectPropValue_Handle, ctx->SetObjectPropValue_PropCode); ctx->SetObjectPropValue_Handle = 0xFFFFFFFF; break; default: response_code = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; break; } return response_code; } umtp-responder-1.3.10/src/mtp_operations/mtp_op_truncateobject.c000066400000000000000000000046141374176322100251630ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_op_truncateobject.c * @brief truncate object operation. * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include #include "logs_out.h" #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" uint32_t mtp_op_TruncateObject(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, int * size,uint32_t * ret_params, int * ret_params_size) { uint32_t response_code; uint32_t handle; mtp_offset offset; fs_entry * entry; char * full_path; if(!ctx->fs_db) return MTP_RESPONSE_SESSION_NOT_OPEN; pthread_mutex_lock( &ctx->inotify_mutex ); response_code = MTP_RESPONSE_GENERAL_ERROR; handle = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 4); offset = peek64(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER) + 4, 8); // Get param 2 - Offset in bytes entry = get_entry_by_handle(ctx->fs_db, handle); if( entry ) { if( check_handle_access( ctx, entry, handle, 1, &response_code) ) { pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; } full_path = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); if(full_path) { PRINT_DEBUG("Truncate file at 0x%"SIZEHEX" Bytes",offset); if( !truncate64(full_path, offset) ) { response_code = MTP_RESPONSE_OK; } else { response_code = posix_to_mtp_errcode(errno); } } } else { response_code = MTP_RESPONSE_INVALID_OBJECT_HANDLE; } pthread_mutex_unlock( &ctx->inotify_mutex ); return response_code; } umtp-responder-1.3.10/src/mtp_operations/mtp_ops_helpers.c000066400000000000000000000135431374176322100237750ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_ops_helpers.c * @brief mtp operations helpers * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_operations.h" #include "usb_gadget_fct.h" #include "inotify.h" #include "logs_out.h" mtp_size send_file_data( mtp_ctx * ctx, fs_entry * entry,mtp_offset offset, mtp_size maxsize ) { mtp_size actualsize; mtp_size j; int ofs; mtp_size blocksize; int file,bytes_read; mtp_offset buf_index; int io_buffer_index; int first_part_size; unsigned char * usb_buffer_ptr; if( !ctx->read_file_buffer ) { ctx->read_file_buffer = malloc( ctx->read_file_buffer_size ); if(!ctx->read_file_buffer) return 0; memset(ctx->read_file_buffer, 0, ctx->read_file_buffer_size); } usb_buffer_ptr = NULL; buf_index = -1; if( offset >= entry->size ) { actualsize = 0; } else { if( offset + maxsize > entry->size ) actualsize = entry->size - offset; else actualsize = maxsize; } poke32(ctx->wrbuffer, 0, ctx->usb_wr_buffer_max_size, sizeof(MTP_PACKET_HEADER) + actualsize); ofs = sizeof(MTP_PACKET_HEADER); PRINT_DEBUG("send_file_data : Offset 0x%"SIZEHEX" - Maxsize 0x%"SIZEHEX" - Size 0x%"SIZEHEX" - ActualSize 0x%"SIZEHEX, offset,maxsize,entry->size,actualsize); file = entry_open(ctx->fs_db, entry); if( file != -1 ) { ctx->transferring_file_data = 1; j = 0; do { if((j + ((mtp_size)(ctx->usb_wr_buffer_max_size) - ofs)) < actualsize) blocksize = ((mtp_size)(ctx->usb_wr_buffer_max_size) - ofs); else blocksize = actualsize - j; // Is the target page loaded ? if( buf_index != ((offset + j) & ~((mtp_offset)(ctx->read_file_buffer_size-1))) ) { bytes_read = entry_read(ctx->fs_db, file, ctx->read_file_buffer, ((offset + j) & ~((mtp_offset)(ctx->read_file_buffer_size-1))) , (mtp_size)ctx->read_file_buffer_size); if( bytes_read < 0 ) { entry_close( file ); return -1; } buf_index = ((offset + j) & ~((mtp_offset)(ctx->read_file_buffer_size-1))); } io_buffer_index = (offset + j) & (mtp_offset)(ctx->read_file_buffer_size-1); // Is a new page needed ? if( io_buffer_index + blocksize < ctx->read_file_buffer_size ) { // No, just use the io buffer if( !ofs ) { // Use the I/O buffer directly usb_buffer_ptr = (unsigned char *)&ctx->read_file_buffer[io_buffer_index]; } else { memcpy(&ctx->wrbuffer[ofs], &ctx->read_file_buffer[io_buffer_index], blocksize ); usb_buffer_ptr = (unsigned char *)&ctx->wrbuffer[0]; } } else { // Yes, new page needed. Get the first part in the io buffer and the load a new page to get the remaining data. first_part_size = blocksize - ( ( io_buffer_index + blocksize ) - (mtp_size)ctx->read_file_buffer_size); memcpy(&ctx->wrbuffer[ofs], &ctx->read_file_buffer[io_buffer_index], first_part_size ); buf_index += (mtp_offset)ctx->read_file_buffer_size; bytes_read = entry_read(ctx->fs_db, file, ctx->read_file_buffer, buf_index , ctx->read_file_buffer_size); if( bytes_read < 0 ) { entry_close( file ); return -1; } memcpy(&ctx->wrbuffer[ofs + first_part_size], &ctx->read_file_buffer[0], blocksize - first_part_size ); usb_buffer_ptr = (unsigned char *)&ctx->wrbuffer[0]; } j += blocksize; ofs += blocksize; PRINT_DEBUG("---> 0x%"SIZEHEX" (0x%X)",j,ofs); write_usb(ctx->usb_ctx, EP_DESCRIPTOR_IN, usb_buffer_ptr, ofs); ofs = 0; }while( j < actualsize && !ctx->cancel_req ); ctx->transferring_file_data = 0; entry_close( file ); if( ctx->cancel_req ) { PRINT_DEBUG("send_file_data : Cancelled ! Aborded..."); // Force a ZLP check_and_send_USB_ZLP(ctx , ctx->max_packet_size ); actualsize = -2; ctx->cancel_req = 0; } else { PRINT_DEBUG("send_file_data : Full transfert done !"); check_and_send_USB_ZLP(ctx , sizeof(MTP_PACKET_HEADER) + actualsize ); } } else actualsize = -1; return actualsize; } int delete_tree(mtp_ctx * ctx,uint32_t handle) { int ret; fs_entry * entry; char * path; ret = -1; entry = get_entry_by_handle(ctx->fs_db, handle); if(entry) { path = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); if (path) { if(entry->flags & ENTRY_IS_DIR) { ret = fs_remove_tree( path ); if(!ret) { entry->flags |= ENTRY_IS_DELETED; if( entry->watch_descriptor != -1 ) { inotify_handler_rmwatch( ctx, entry->watch_descriptor ); entry->watch_descriptor = -1; } } else scan_and_add_folder(ctx->fs_db, path, handle, entry->storage_id); // partially deleted ? update/sync the db. } else { ret = remove(path); if(!ret) { entry->flags |= ENTRY_IS_DELETED; if( entry->watch_descriptor != -1 ) { inotify_handler_rmwatch( ctx, entry->watch_descriptor ); entry->watch_descriptor = -1; } } } free(path); } } return ret; } umtp-responder-1.3.10/src/mtp_properties.c000066400000000000000000001133401374176322100205770ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_properties.c * @brief MTP properties datasets helpers * @author Jean-Franois DEL NERO */ #include "buildconf.h" #include #include #include #include #include #include #include #include "mtp.h" #include "mtp_helpers.h" #include "mtp_constant.h" #include "mtp_constant_strings.h" #include "mtp_properties.h" #include "fs_handles_db.h" #include "usb_gadget_fct.h" #include "logs_out.h" formats_property fmt_properties[]= { // prop_code data_type getset default value group code { MTP_FORMAT_UNDEFINED , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_ASSOCIATION , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} } #if 0 { MTP_FORMAT_TEXT , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_HTML , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_MP4_CONTAINER, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED, 0xFFFF} }, { MTP_FORMAT_3GP_CONTAINER, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED, 0xFFFF} }, { MTP_FORMAT_WAV , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,MTP_PROPERTY_ARTIST,MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE, MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_PROPERTY_SAMPLE_RATE, 0xFFFF} }, { MTP_FORMAT_MP3 , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED,MTP_PROPERTY_ARTIST,MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE, MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_PROPERTY_SAMPLE_RATE, 0xFFFF} }, { MTP_FORMAT_MPEG , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED, 0xFFFF} }, { MTP_FORMAT_EXIF_JPEG , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED, 0xFFFF} }, { MTP_FORMAT_BMP , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED, 0xFFFF} }, { MTP_FORMAT_GIF , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED, 0xFFFF} }, { MTP_FORMAT_JFIF , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED, 0xFFFF} }, { MTP_FORMAT_WMA , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE, MTP_PROPERTY_NUMBER_OF_CHANNELS, MTP_PROPERTY_SAMPLE_RATE, 0xFFFF} }, { MTP_FORMAT_OGG , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE, MTP_PROPERTY_NUMBER_OF_CHANNELS, MTP_PROPERTY_SAMPLE_RATE, 0xFFFF} }, { MTP_FORMAT_AAC , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_ALBUM_ARTIST, MTP_PROPERTY_TRACK, MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_GENRE, MTP_PROPERTY_COMPOSER, MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_PROPERTY_BITRATE_TYPE, MTP_PROPERTY_AUDIO_BITRATE, MTP_PROPERTY_NUMBER_OF_CHANNELS, MTP_PROPERTY_SAMPLE_RATE, 0xFFFF} }, { MTP_FORMAT_ABSTRACT_AV_PLAYLIST, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_WPL_PLAYLIST, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_M3U_PLAYLIST, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_PLS_PLAYLIST, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_XML_DOCUMENT, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_FLAC , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_AVI , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED, 0xFFFF} }, { MTP_FORMAT_ASF , (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, MTP_PROPERTY_ARTIST, MTP_PROPERTY_ALBUM_NAME, MTP_PROPERTY_DURATION, MTP_PROPERTY_DESCRIPTION, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_DATE_AUTHORED, 0xFFFF} }, { MTP_FORMAT_MS_WORD_DOCUMENT, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_MS_EXCEL_SPREADSHEET, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} }, { MTP_FORMAT_MS_POWERPOINT_PRESENTATION, (uint16_t[]){ MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_PROTECTION_STATUS, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DATE_MODIFIED, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_PERSISTENT_UID, MTP_PROPERTY_NAME, MTP_PROPERTY_DISPLAY_NAME, MTP_PROPERTY_DATE_CREATED, 0xFFFF} } #endif , { 0xFFFF , (uint16_t[]){ 0xFFFF } } }; profile_property properties[]= { // prop_code data_type getset default value group code format id {MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000001 , 0x00 , 0xFFFF }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_UNDEFINED , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_ASSOCIATION, 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_TEXT , 0x000000000 , 0x00 , MTP_FORMAT_TEXT }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_HTML , 0x000000000 , 0x00 , MTP_FORMAT_HTML }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_WAV , 0x000000000 , 0x00 , MTP_FORMAT_WAV }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MP3 , 0x000000000 , 0x00 , MTP_FORMAT_MP3 }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MPEG , 0x000000000 , 0x00 , MTP_FORMAT_MPEG }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_EXIF_JPEG , 0x000000000 , 0x00 , MTP_FORMAT_EXIF_JPEG }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_BMP , 0x000000000 , 0x00 , MTP_FORMAT_BMP }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_AIFF , 0x000000000 , 0x00 , MTP_FORMAT_AIFF }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MPEG , 0x000000000 , 0x00 , MTP_FORMAT_MPEG }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_WMA , 0x000000000 , 0x00 , MTP_FORMAT_WMA }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_OGG , 0x000000000 , 0x00 , MTP_FORMAT_OGG }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_AAC , 0x000000000 , 0x00 , MTP_FORMAT_AAC }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MP4_CONTAINER , 0x000000000 , 0x00 , MTP_FORMAT_MP4_CONTAINER }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_3GP_CONTAINER , 0x000000000 , 0x00 , MTP_FORMAT_3GP_CONTAINER }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_ABSTRACT_AV_PLAYLIST , 0x000000000 , 0x00 , MTP_FORMAT_ABSTRACT_AV_PLAYLIST }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_WPL_PLAYLIST , 0x000000000 , 0x00 , MTP_FORMAT_WPL_PLAYLIST }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_M3U_PLAYLIST , 0x000000000 , 0x00 , MTP_FORMAT_M3U_PLAYLIST }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_PLS_PLAYLIST , 0x000000000 , 0x00 , MTP_FORMAT_PLS_PLAYLIST }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_XML_DOCUMENT , 0x000000000 , 0x00 , MTP_FORMAT_XML_DOCUMENT }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_FLAC , 0x000000000 , 0x00 , MTP_FORMAT_FLAC }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_AVI , 0x000000000 , 0x00 , MTP_FORMAT_AVI }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_ASF , 0x000000000 , 0x00 , MTP_FORMAT_ASF }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MS_WORD_DOCUMENT , 0x000000000 , 0x00 , MTP_FORMAT_MS_WORD_DOCUMENT }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MS_EXCEL_SPREADSHEET , 0x000000000 , 0x00 , MTP_FORMAT_MS_EXCEL_SPREADSHEET }, {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16, 0x00, MTP_FORMAT_MS_POWERPOINT_PRESENTATION , 0x000000000 , 0x00 , MTP_FORMAT_MS_POWERPOINT_PRESENTATION }, {MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, 0x00, 0x0000000000000000 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16, 0x00, 0x0000 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR, 0x00, 0x0000 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, 0x01, 0x0000 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_DATE_CREATED, MTP_TYPE_STR, 0x00, 0x00 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, 0x00, 0x00 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128, 0x00, 0x00 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_NAME, MTP_TYPE_STR, 0x00, 0x00 , 0x000000000 , 0x00 , MTP_FORMAT_ASSOCIATION }, {MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, 0x00, 0x0000000000000000 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16, 0x00, 0x0000 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR, 0x00, 0x0000 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, 0x01, 0x0000 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_DATE_CREATED, MTP_TYPE_STR, 0x00, 0x00 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, 0x00, 0x00 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128, 0x00, 0x00 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, {MTP_PROPERTY_NAME, MTP_TYPE_STR, 0x00, 0x00 , 0x000000000 , 0x00 , MTP_FORMAT_UNDEFINED }, //{MTP_PROPERTY_ASSOCIATION_TYPE, MTP_TYPE_UINT16, 0x00, 0x0001 , 0x000000000 , 0x00 , 0xFFFF }, {MTP_PROPERTY_ASSOCIATION_DESC, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 , 0xFFFF }, {MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16, 0x00, 0x0000 , 0x000000000 , 0x00 , 0xFFFF }, {MTP_PROPERTY_HIDDEN, MTP_TYPE_UINT16, 0x00, 0x0000 , 0x000000000 , 0x00 , 0xFFFF }, {0xFFFF, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 } }; profile_property dev_properties[]= { // prop_code data_type getset default value group code //{MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 }, //{MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 }, {MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT16, 0x00, 0x00000000 , 0x000000000 , 0x00 }, {MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR, 0x00, 0x00000000 , 0x000000000 , 0x00 }, {0xFFFF, MTP_TYPE_UINT32, 0x00, 0x00000000 , 0x000000000 , 0x00 } }; int build_properties_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t property_id,uint32_t format_id) { int ofs,i,j; ofs = 0; PRINT_DEBUG("build_properties_dataset : 0x%.4X (%s) (Format : 0x%.4X - %s )", property_id, mtp_get_property_string(property_id), format_id, mtp_get_format_string(format_id)); i = 0; while(properties[i].prop_code != 0xFFFF ) { if( ( properties[i].prop_code == property_id ) && ( properties[i].format_id == format_id ) ) { break; } i++; } if( properties[i].prop_code == 0xFFFF ) { // Looking for default value i = 0; while(properties[i].prop_code != 0xFFFF ) { if( ( properties[i].prop_code == property_id ) && ( properties[i].format_id == 0xFFFF ) ) { break; } i++; } } if( properties[i].prop_code == property_id ) { ofs = poke16(buffer, ofs, maxsize, properties[i].prop_code); // PropertyCode ofs = poke16(buffer, ofs, maxsize, properties[i].data_type); // DataType ofs = poke08(buffer, ofs, maxsize, properties[i].getset); // Get / Set switch(properties[i].data_type) { case MTP_TYPE_STR: case MTP_TYPE_UINT8: ofs = poke08(buffer, ofs, maxsize, properties[i].default_value); // DefaultValue break; case MTP_TYPE_UINT16: ofs = poke16(buffer, ofs, maxsize, properties[i].default_value); // DefaultValue break; case MTP_TYPE_UINT32: ofs = poke32(buffer, ofs, maxsize, properties[i].default_value); // DefaultValue break; case MTP_TYPE_UINT64: ofs = poke32(buffer, ofs, maxsize, properties[i].default_value & 0xFFFFFFFF); // DefaultValue ofs = poke32(buffer, ofs, maxsize, properties[i].default_value >> 32); break; case MTP_TYPE_UINT128: for(j=0;j<4;j++) { ofs = poke32(buffer, ofs, maxsize, properties[i].default_value); } break; default: PRINT_ERROR("build_properties_dataset : Unsupported data type : 0x%.4X", properties[i].data_type ); break; } ofs = poke32(buffer, ofs, maxsize, properties[i].group_code); // Group code ofs = poke08(buffer, ofs, maxsize, properties[i].form_flag); // Form flag } return ofs; } int build_device_properties_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t property_id) { int ofs,i; ofs = 0; PRINT_DEBUG("build_device_properties_dataset : 0x%.4X (%s)", property_id, mtp_get_property_string(property_id)); i = 0; while(dev_properties[i].prop_code != 0xFFFF && dev_properties[i].prop_code != property_id) { i++; } if( dev_properties[i].prop_code == property_id ) { ofs = poke16(buffer, ofs, maxsize, dev_properties[i].prop_code); // PropertyCode ofs = poke16(buffer, ofs, maxsize, dev_properties[i].data_type); // DataType ofs = poke08(buffer, ofs, maxsize, dev_properties[i].getset); // Get / Set switch(dev_properties[i].data_type) { case MTP_TYPE_STR: case MTP_TYPE_UINT8: ofs = poke08(buffer, ofs, maxsize, dev_properties[i].default_value); ofs = poke08(buffer, ofs, maxsize, dev_properties[i].default_value); break; case MTP_TYPE_UINT16: ofs = poke16(buffer, ofs, maxsize, dev_properties[i].default_value); ofs = poke16(buffer, ofs, maxsize, dev_properties[i].default_value); break; case MTP_TYPE_UINT32: ofs = poke32(buffer, ofs, maxsize, dev_properties[i].default_value); ofs = poke32(buffer, ofs, maxsize, dev_properties[i].default_value); break; case MTP_TYPE_UINT64: ofs = poke32(buffer, ofs, maxsize, dev_properties[i].default_value & 0xFFFFFFFF); ofs = poke32(buffer, ofs, maxsize, dev_properties[i].default_value >> 32); ofs = poke32(buffer, ofs, maxsize, dev_properties[i].default_value & 0xFFFFFFFF); ofs = poke32(buffer, ofs, maxsize, dev_properties[i].default_value >> 32); break; default: PRINT_ERROR("build_device_properties_dataset : Unsupported data type : 0x%.4X", dev_properties[i].data_type ); return 0; break; } ofs = poke32(buffer, ofs, maxsize, dev_properties[i].group_code); // Group code ofs = poke08(buffer, ofs, maxsize, dev_properties[i].form_flag); // Form flag } return ofs; } int build_properties_supported_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t format_id) { int ofs,i,fmt_index; int nb_supported_prop; PRINT_DEBUG("build_properties_supported_dataset : (Format : 0x%.4X - %s )", format_id, mtp_get_format_string(format_id)); fmt_index = 0; while(fmt_properties[fmt_index].format_code != 0xFFFF && fmt_properties[fmt_index].format_code != format_id ) { fmt_index++; } if( fmt_properties[fmt_index].format_code == 0xFFFF ) return 0; nb_supported_prop = 0; while( fmt_properties[fmt_index].properties[nb_supported_prop] != 0xFFFF ) nb_supported_prop++; i = 0; ofs = poke32(buffer, 0, maxsize, nb_supported_prop); while( fmt_properties[fmt_index].properties[i] != 0xFFFF ) { ofs = poke16(buffer, ofs, maxsize, fmt_properties[fmt_index].properties[i]); i++; } return ofs; } int setObjectPropValue(mtp_ctx * ctx,MTP_PACKET_HEADER * mtp_packet_hdr, uint32_t handle,uint32_t prop_code) { fs_entry * entry; char * path; char * path2; char tmpstr[256+1]; unsigned int stringlen; uint32_t response_code; PRINT_DEBUG("setObjectPropValue : (Handle : 0x%.8X - Prop code : 0x%.4X )", handle, prop_code); response_code = 0x00000000; if( handle != 0xFFFFFFFF ) { switch( prop_code ) { case MTP_PROPERTY_OBJECT_FILE_NAME: entry = get_entry_by_handle(ctx->fs_db, handle); if( check_handle_access( ctx, entry, 0x00000000, 1, &response_code) ) return response_code; path = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); if(!path) return MTP_RESPONSE_GENERAL_ERROR; memset(tmpstr,0,sizeof(tmpstr)); stringlen = peek(mtp_packet_hdr, sizeof(MTP_PACKET_HEADER), 1); if( stringlen > sizeof(tmpstr)) stringlen = sizeof(tmpstr); unicode2charstring(tmpstr, (uint16_t *) ((char*)(mtp_packet_hdr) + sizeof(MTP_PACKET_HEADER) + 1), sizeof(tmpstr)); tmpstr[ sizeof(tmpstr) - 1 ] = 0; if( entry->name ) { free(entry->name); entry->name = NULL; } entry->name = malloc(strlen(tmpstr)+1); if( entry->name ) { strcpy(entry->name,tmpstr); } path2 = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); if(!path2) { free(path); return MTP_RESPONSE_GENERAL_ERROR; } if(rename(path, path2)) { PRINT_ERROR("setObjectPropValue : Can't rename %s to %s", path, path2); free(path); free(path2); return MTP_RESPONSE_GENERAL_ERROR; } free(path); free(path2); return MTP_RESPONSE_OK; break; default: return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE; break; } } else { return MTP_RESPONSE_INVALID_OBJECT_HANDLE; } } int build_ObjectPropValue_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t handle,uint32_t prop_code) { int ofs; fs_entry * entry; char timestr[32]; ofs = 0; PRINT_DEBUG("build_ObjectPropValue_dataset : Handle 0x%.8X - Property 0x%.4X (%s)", handle, prop_code, mtp_get_property_string(prop_code)); entry = get_entry_by_handle(ctx->fs_db, handle); if( entry ) { switch(prop_code) { case MTP_PROPERTY_OBJECT_FORMAT: if(entry->flags & ENTRY_IS_DIR) ofs = poke16(buffer, ofs, maxsize, MTP_FORMAT_ASSOCIATION); // ObjectFormat Code else ofs = poke16(buffer, ofs, maxsize, MTP_FORMAT_UNDEFINED); // ObjectFormat Code break; case MTP_PROPERTY_OBJECT_SIZE: ofs = poke32(buffer, ofs, maxsize, entry->size & 0xFFFFFFFF); ofs = poke32(buffer, ofs, maxsize, entry->size >> 32); break; case MTP_PROPERTY_DISPLAY_NAME: ofs = poke08(buffer, ofs, maxsize, 0); break; case MTP_PROPERTY_NAME: case MTP_PROPERTY_OBJECT_FILE_NAME: ofs = poke_string(buffer, ofs, maxsize, entry->name); // Filename break; case MTP_PROPERTY_STORAGE_ID: ofs = poke32(buffer, ofs, maxsize, entry->storage_id); break; case MTP_PROPERTY_PARENT_OBJECT: ofs = poke32(buffer, ofs, maxsize, entry->parent); break; case MTP_PROPERTY_HIDDEN: ofs = poke16(buffer, ofs, maxsize, 0x0000); break; case MTP_PROPERTY_SYSTEM_OBJECT: ofs = poke16(buffer, ofs, maxsize, 0x0000); break; case MTP_PROPERTY_PROTECTION_STATUS: ofs = poke16(buffer, ofs, maxsize, 0x0000); break; case MTP_PROPERTY_ASSOCIATION_TYPE: if(entry->flags & ENTRY_IS_DIR) ofs = poke16(buffer, ofs, maxsize, 0x0001); // ObjectFormat Code else ofs = poke16(buffer, ofs, maxsize, 0x0000); // ObjectFormat Code break; case MTP_PROPERTY_ASSOCIATION_DESC: ofs = poke32(buffer, ofs, maxsize, 0x00000000); break; case MTP_PROPERTY_DATE_CREATED: case MTP_PROPERTY_DATE_MODIFIED: snprintf(timestr,sizeof(timestr),"%.4d%.2d%.2dT%.2d%.2d%.2d",1900 + 110, 1, 2, 10, 11,12); ofs = poke_string(buffer, ofs, maxsize, timestr); break; case MTP_PROPERTY_PERSISTENT_UID: ofs = poke32(buffer, ofs, maxsize, entry->handle); ofs = poke32(buffer, ofs, maxsize, entry->parent); ofs = poke32(buffer, ofs, maxsize, entry->storage_id); ofs = poke32(buffer, ofs, maxsize, 0x00000000); break; default: PRINT_ERROR("build_ObjectPropValue_dataset : Unsupported property : 0x%.4X (%s)", prop_code, mtp_get_property_string(prop_code)); return 0; break; } } return ofs; } int build_DevicePropValue_dataset(mtp_ctx * ctx,void * buffer, int maxsize,uint32_t prop_code) { int ofs; ofs = 0; PRINT_DEBUG("build_DevicePropValue_dataset : Property 0x%.4X (%s)", prop_code, mtp_get_property_string(prop_code)); switch(prop_code) { case MTP_DEVICE_PROPERTY_BATTERY_LEVEL: ofs = poke16(buffer, ofs, maxsize, 0x8000); break; case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: ofs = poke_string(buffer, ofs, maxsize, ctx->usb_cfg.usb_string_product); break; default: PRINT_ERROR("build_DevicePropValue_dataset : Unsupported property : 0x%.4X (%s)", prop_code, mtp_get_property_string(prop_code)); return 0; break; } return ofs; } int objectproplist_element(mtp_ctx * ctx, void * buffer, int * ofs, int maxsize, uint16_t prop_code, uint32_t handle, void * data,uint32_t prop_code_param) { int i; if( (prop_code != prop_code_param) && (prop_code_param != 0xFFFFFFFF) ) { return 0; } i = 0; while(properties[i].prop_code != 0xFFFF && properties[i].prop_code != prop_code) { i++; } if( properties[i].prop_code == prop_code ) { *ofs = poke32(buffer, *ofs, maxsize, handle); *ofs = poke16(buffer, *ofs, maxsize, properties[i].prop_code); *ofs = poke16(buffer, *ofs, maxsize, properties[i].data_type); switch(properties[i].data_type) { case MTP_TYPE_STR: if(data) *ofs = poke_string(buffer, *ofs, maxsize, (char*)data); else *ofs = poke08(buffer, *ofs, maxsize, 0); break; case MTP_TYPE_UINT8: *ofs = poke08(buffer, *ofs, maxsize, *((uint8_t*)data)); break; case MTP_TYPE_UINT16: *ofs = poke16(buffer, *ofs, maxsize, *((uint16_t*)data)); break; case MTP_TYPE_UINT32: *ofs = poke32(buffer, *ofs, maxsize, *((uint32_t*)data)); break; case MTP_TYPE_UINT64: *ofs = poke32(buffer, *ofs, maxsize, *((uint64_t*)data) & 0xFFFFFFFF); *ofs = poke32(buffer, *ofs, maxsize, *((uint64_t*)data) >> 32); break; case MTP_TYPE_UINT128: for(i=0;i<4;i++) { *ofs = poke32(buffer, *ofs, maxsize, *((uint32_t*)data)+i); } break; default: PRINT_ERROR("objectproplist_element : Unsupported data type : 0x%.4X", properties[i].data_type ); break; } return 1; } return 0; } int build_objectproplist_dataset(mtp_ctx * ctx, void * buffer, int maxsize,fs_entry * entry, uint32_t handle,uint32_t format_id, uint32_t prop_code, uint32_t prop_group_code, uint32_t depth) { struct stat64 entrystat; time_t t; struct tm lt; int ofs,ret,numberofelements; char * path; char timestr[32]; uint32_t tmp_dword; uint32_t tmp_dword_array[4]; ret = -1; path = build_full_path(ctx->fs_db, mtp_get_storage_root(ctx, entry->storage_id), entry); if(path) { ret = stat64(path, &entrystat); } if(ret) { if(path) free(path); return 0; } numberofelements = 0; ofs = poke32(buffer, 0, maxsize, numberofelements); // Number of elements numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_STORAGE_ID, handle, &entry->storage_id,prop_code); if(entry->flags & ENTRY_IS_DIR) tmp_dword = MTP_FORMAT_ASSOCIATION; else tmp_dword = MTP_FORMAT_UNDEFINED; numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_OBJECT_FORMAT, handle, &tmp_dword,prop_code); if(entry->flags & ENTRY_IS_DIR) tmp_dword = MTP_ASSOCIATION_TYPE_GENERIC_FOLDER; else tmp_dword = 0x0000; numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_ASSOCIATION_TYPE, handle, &tmp_dword,prop_code); numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_PARENT_OBJECT, handle, &entry->parent,prop_code); numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_OBJECT_SIZE, handle, &entry->size,prop_code); tmp_dword = 0x0000; numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_PROTECTION_STATUS, handle, &tmp_dword,prop_code); numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_OBJECT_FILE_NAME, handle, entry->name,prop_code); numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_NAME, handle, entry->name,prop_code); numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_DISPLAY_NAME, handle, 0,prop_code); // Date Created (NR) "YYYYMMDDThhmmss.s" t = entrystat.st_mtime; localtime_r(&t, <); snprintf(timestr,sizeof(timestr),"%.4d%.2d%.2dT%.2d%.2d%.2d",1900 + lt.tm_year, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec); numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_DATE_CREATED, handle, ×tr,prop_code); // Date Modified (NR) "YYYYMMDDThhmmss.s" t = entrystat.st_mtime; localtime_r(&t, <); snprintf(timestr,sizeof(timestr),"%.4d%.2d%.2dT%.2d%.2d%.2d",1900 + lt.tm_year, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec); numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_DATE_MODIFIED, handle, ×tr,prop_code); tmp_dword_array[0] = entry->handle; tmp_dword_array[1] = entry->parent; tmp_dword_array[2] = entry->storage_id; tmp_dword_array[3] = 0x00000000; numberofelements += objectproplist_element(ctx, buffer, &ofs, maxsize, MTP_PROPERTY_PERSISTENT_UID, handle, &tmp_dword_array,prop_code); poke32(buffer, 0, maxsize, numberofelements); // Number of elements return ofs; } umtp-responder-1.3.10/src/mtp_support_def.c000066400000000000000000000067771374176322100207540ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mtp_support_def.c * @brief MTP support definitions. * @author Jean-François DEL NERO */ #include "buildconf.h" #include "mtp_constant.h" const unsigned short supported_op[]= { MTP_OPERATION_GET_DEVICE_INFO ,//0x1001 MTP_OPERATION_OPEN_SESSION ,//0x1002 MTP_OPERATION_CLOSE_SESSION ,//0x1003 MTP_OPERATION_GET_STORAGE_IDS ,//0x1004 MTP_OPERATION_GET_STORAGE_INFO ,//0x1005 //MTP_OPERATION_GET_NUM_OBJECTS ,//0x1006 MTP_OPERATION_GET_OBJECT_HANDLES ,//0x1007 MTP_OPERATION_GET_OBJECT_INFO ,//0x1008 MTP_OPERATION_GET_OBJECT ,//0x1009 //MTP_OPERATION_GET_THUMB ,//0x100A MTP_OPERATION_DELETE_OBJECT ,//0x100B MTP_OPERATION_SEND_OBJECT_INFO ,//0x100C MTP_OPERATION_SEND_OBJECT ,//0x100D MTP_OPERATION_GET_DEVICE_PROP_DESC ,//0x1014 MTP_OPERATION_GET_DEVICE_PROP_VALUE ,//0x1015 MTP_OPERATION_SET_DEVICE_PROP_VALUE ,//0x1016 //MTP_OPERATION_RESET_DEVICE_PROP_VALUE ,//0x1017 MTP_OPERATION_GET_PARTIAL_OBJECT ,//0x101B MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED ,//0x9801 MTP_OPERATION_GET_OBJECT_PROP_DESC ,//0x9802 MTP_OPERATION_GET_OBJECT_PROP_VALUE ,//0x9803 MTP_OPERATION_SET_OBJECT_PROP_VALUE ,//0x9804 MTP_OPERATION_GET_OBJECT_PROP_LIST ,//0x9805 //MTP_OPERATION_GET_OBJECT_REFERENCES ,//0x9810 //MTP_OPERATION_SET_OBJECT_REFERENCES ,//0x9811 MTP_OPERATION_GET_PARTIAL_OBJECT_64 ,//0x95C1 MTP_OPERATION_SEND_PARTIAL_OBJECT ,//0x95C2 MTP_OPERATION_TRUNCATE_OBJECT ,//0x95C3 MTP_OPERATION_BEGIN_EDIT_OBJECT ,//0x95C4 MTP_OPERATION_END_EDIT_OBJECT //0x95C5 }; const int supported_op_size=sizeof(supported_op); const unsigned short supported_event[]= { MTP_EVENT_OBJECT_ADDED , // 0x4002 MTP_EVENT_OBJECT_REMOVED , // 0x4003 MTP_EVENT_STORE_ADDED , // 0x4004 MTP_EVENT_STORE_REMOVED , // 0x4005 MTP_EVENT_STORAGE_INFO_CHANGED , // 0x400C MTP_EVENT_OBJECT_INFO_CHANGED , // 0x4007 MTP_EVENT_DEVICE_PROP_CHANGED , // 0x4006 MTP_EVENT_OBJECT_PROP_CHANGED // 0xC801 }; const int supported_event_size=sizeof(supported_event); umtp-responder-1.3.10/src/umtprd.c000066400000000000000000000064661374176322100170500ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file umtprd.c * @brief Main MTP Daemon program. * @author Jean-François DEL NERO */ #include "buildconf.h" #include #include #include #include #include #include "mtp.h" #include "usb_gadget.h" #include "usb_gadget_fct.h" #include "logs_out.h" #include "msgqueue.h" #include "default_cfg.h" mtp_ctx * mtp_context; void* io_thread(void* arg) { usb_gadget * ctx; int ret; ctx = (usb_gadget *)arg; while (is_usb_up(ctx)) { ret = mtp_incoming_packet(mtp_context); if(ret < 0) { ctx->stop = 1; } } return NULL; } static int main_thread(const char *conffile) { usb_gadget * usb_ctx; int retcode = 0; int loop_continue = 0; mtp_context = mtp_init_responder(); if(!mtp_context) { return -1; } mtp_load_config_file(mtp_context, conffile); loop_continue = mtp_context->usb_cfg.loop_on_disconnect; do { usb_ctx = init_usb_mtp_gadget(mtp_context); if(usb_ctx) { mtp_set_usb_handle(mtp_context, usb_ctx, mtp_context->usb_cfg.usb_max_packet_size); if( mtp_context->usb_cfg.usb_functionfs_mode ) { PRINT_DEBUG("uMTP Responder : FunctionFS Mode - entering handle_ffs_ep0"); handle_ffs_ep0(usb_ctx); } else { PRINT_DEBUG("uMTP Responder : GadgetFS Mode - entering handle_ep0"); handle_ep0(usb_ctx); } deinit_usb_mtp_gadget(usb_ctx); } else { PRINT_ERROR("USB Init failed !"); retcode = -2; loop_continue = 0; } PRINT_MSG("uMTP Responder : Disconnected"); if(mtp_context->fs_db) { deinit_fs_db(mtp_context->fs_db); mtp_context->fs_db = 0; } }while(loop_continue); mtp_deinit_responder(mtp_context); return retcode; } #define PARAMETER_IPCCMD "-cmd:" #define PARAMETER_CONF "-conf" int main(int argc, char *argv[]) { const char *conffile = UMTPR_CONF_FILE; int retcode; PRINT_MSG("uMTP Responder"); PRINT_MSG("Version: %s compiled the %s@%s", APP_VERSION, __DATE__, __TIME__); PRINT_MSG("(c) 2018 - 2020 Viveris Technologies"); if(argc>1) { if(argv[1]) { if(!strncmp(argv[1],PARAMETER_IPCCMD,sizeof(PARAMETER_IPCCMD)-1)) { PRINT_MSG("Sending command : %s",&argv[1][sizeof(PARAMETER_IPCCMD)-1]); retcode = send_message_queue( &argv[1][sizeof(PARAMETER_IPCCMD)-1] ); exit(retcode); } if(!strcmp(argv[1],PARAMETER_CONF) && argc > 2) conffile = argv[2]; } } retcode = main_thread(conffile); if( retcode ) PRINT_ERROR("Error : Couldn't run the main thread... (%d)", retcode); return -retcode; } umtp-responder-1.3.10/src/usb_gadget.c000066400000000000000000000637011374176322100176340ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file usb_gadget.c * @brief USB GadgetFS & FunctionFS layer. * @author Jean-François DEL NERO */ // GadgetFS support : Main inspiration from Grégory Soutadé (http://blog.soutade.fr/post/2016/07/create-your-own-usb-gadget-with-gadgetfs.html) #include "buildconf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_USB_NON_BLOCKING_WRITE #include #endif #include "fs_handles_db.h" #include "mtp.h" #include "mtp_constant.h" #include "usbstring.h" #include "usb_gadget.h" #include "usb_gadget_fct.h" #include "logs_out.h" #define CONFIG_VALUE 1 static struct usb_gadget_strings strings = { .language = 0x0409, /* en-us */ .strings = 0, }; extern void* io_thread(void* arg); extern mtp_ctx * mtp_context; typedef struct mtp_device_status_ { uint16_t wLength; uint16_t wCode; }mtp_device_status; int read_usb(usb_gadget * ctx, unsigned char * buffer, int maxsize) { int ret; ret = -1; if(ctx->ep_handles[EP_DESCRIPTOR_OUT] >= 0 && maxsize && buffer) { ret = read (ctx->ep_handles[EP_DESCRIPTOR_OUT], buffer, maxsize); } return ret; } int write_usb(usb_gadget * ctx, int channel, unsigned char * buffer, int size) { int ret; #ifdef CONFIG_USB_NON_BLOCKING_WRITE struct pollfd pfd; #endif ret = -1; if ( channel < EP_NB_OF_DESCRIPTORS ) { if(ctx->ep_handles[channel] >= 0 && buffer && !mtp_context->cancel_req) { #ifdef CONFIG_USB_NON_BLOCKING_WRITE fcntl(ctx->ep_handles[channel], F_SETFL, fcntl(ctx->ep_handles[channel], F_GETFL) | O_NONBLOCK); do { pfd.fd = ctx->ep_handles[channel]; pfd.events = POLLOUT; ret = poll(&pfd, 1, 2000); if(ret>0 && !mtp_context->cancel_req) { ret = write (ctx->ep_handles[channel], buffer, size); } }while( ret < 0 && ( (errno == EAGAIN) || (errno == EAGAIN) ) && !mtp_context->cancel_req ); fcntl(ctx->ep_handles[channel], F_SETFL, fcntl(ctx->ep_handles[channel], F_GETFL) & ~O_NONBLOCK); #else ret = write (ctx->ep_handles[channel], buffer, size); #endif } } return ret; } int is_usb_up(usb_gadget * ctx) { if(ctx->stop) return 0; else return 1; } void fill_config_descriptor(mtp_ctx * ctx , usb_gadget * usbctx,struct usb_config_descriptor * desc,int total_size, int hs) { memset(desc,0,sizeof(struct usb_config_descriptor)); desc->bLength = sizeof(struct usb_config_descriptor); desc->bDescriptorType = USB_DT_CONFIG; desc->wTotalLength = desc->bLength + total_size; desc->bNumInterfaces = 1; desc->bConfigurationValue = CONFIG_VALUE; if(hs) desc->iConfiguration = STRINGID_CONFIG_HS; else desc->iConfiguration = STRINGID_CONFIG_LS; desc->bmAttributes = USB_CONFIG_ATT_ONE; desc->bMaxPower = 1; PRINT_DEBUG("fill_config_descriptor: (Total Len : %u + %d = %d)", (unsigned int) sizeof(struct usb_config_descriptor), total_size, desc->wTotalLength); PRINT_DEBUG_BUF(desc, sizeof(struct usb_config_descriptor)); return; } void fill_dev_descriptor(mtp_ctx * ctx, usb_gadget * usbctx,struct usb_device_descriptor * desc) { memset(desc,0,sizeof(struct usb_device_descriptor)); desc->bLength = USB_DT_DEVICE_SIZE; desc->bDescriptorType = USB_DT_DEVICE; desc->bDeviceClass = ctx->usb_cfg.usb_class; desc->bDeviceSubClass = ctx->usb_cfg.usb_subclass; desc->bDeviceProtocol = ctx->usb_cfg.usb_protocol; desc->idVendor = ctx->usb_cfg.usb_vendor_id; desc->idProduct = ctx->usb_cfg.usb_product_id; desc->bcdDevice = ctx->usb_cfg.usb_dev_version; // Version // Strings desc->iManufacturer = STRINGID_MANUFACTURER; desc->iProduct = STRINGID_PRODUCT; desc->iSerialNumber = STRINGID_SERIAL; desc->bNumConfigurations = 1; // Only one configuration PRINT_DEBUG("fill_dev_descriptor:"); PRINT_DEBUG_BUF(desc, sizeof(struct usb_device_descriptor)); return; } void fill_if_descriptor(mtp_ctx * ctx, usb_gadget * usbctx, struct usb_interface_descriptor * desc) { memset(desc,0,sizeof(struct usb_interface_descriptor)); desc->bLength = sizeof(struct usb_interface_descriptor); desc->bDescriptorType = USB_DT_INTERFACE; desc->bInterfaceNumber = 0; desc->iInterface = 1; desc->bAlternateSetting = 0; desc->bNumEndpoints = 3; desc->bInterfaceClass = ctx->usb_cfg.usb_class; desc->bInterfaceSubClass = ctx->usb_cfg.usb_subclass; desc->bInterfaceProtocol = ctx->usb_cfg.usb_protocol; if( ctx->usb_cfg.usb_functionfs_mode ) { desc->iInterface = 1; } else { desc->iInterface = STRINGID_INTERFACE; } PRINT_DEBUG("fill_if_descriptor:"); PRINT_DEBUG_BUF(desc, sizeof(struct usb_interface_descriptor)); return; } void fill_ep_descriptor(mtp_ctx * ctx, usb_gadget * usbctx,struct usb_endpoint_descriptor_no_audio * desc,int index,unsigned int flags) { memset(desc,0,sizeof(struct usb_endpoint_descriptor_no_audio)); desc->bLength = USB_DT_ENDPOINT_SIZE; desc->bDescriptorType = USB_DT_ENDPOINT; if(flags & EP_OUT_DIR) desc->bEndpointAddress = USB_DIR_OUT | (index); else desc->bEndpointAddress = USB_DIR_IN | (index); if(flags & EP_BULK_MODE) { desc->bmAttributes = USB_ENDPOINT_XFER_BULK; desc->wMaxPacketSize = ctx->usb_cfg.usb_max_packet_size; } else { desc->bmAttributes = USB_ENDPOINT_XFER_INT; desc->wMaxPacketSize = 28; // HS size desc->bInterval = 6; } PRINT_DEBUG("fill_ep_descriptor:"); PRINT_DEBUG_BUF(desc, sizeof(struct usb_endpoint_descriptor_no_audio)); return; } int init_ep(usb_gadget * ctx,int index,int ffs_mode) { int fd,ret; PRINT_DEBUG("Init end point %s (%d)",ctx->ep_path[index],index); fd = open(ctx->ep_path[index], O_RDWR); if ( fd <= 0 ) { PRINT_ERROR("init_ep : Endpoint %s (%d) init failed ! : Can't open the endpoint ! (error %d - %m)",ctx->ep_path[index],index,fd); goto init_ep_error; } ctx->ep_handles[index] = fd; ctx->ep_config[index]->head = 1; if( ctx->usb_ffs_config ) { memcpy(&ctx->ep_config[index]->ep_desc[0], &ctx->usb_ffs_config->ep_desc[index],sizeof(struct usb_endpoint_descriptor_no_audio)); memcpy(&ctx->ep_config[index]->ep_desc[1], &ctx->usb_ffs_config->ep_desc[index],sizeof(struct usb_endpoint_descriptor_no_audio)); } else { memcpy(&ctx->ep_config[index]->ep_desc[0], &ctx->usb_config->ep_desc[index],sizeof(struct usb_endpoint_descriptor_no_audio)); memcpy(&ctx->ep_config[index]->ep_desc[1], &ctx->usb_config->ep_desc[index],sizeof(struct usb_endpoint_descriptor_no_audio)); } PRINT_DEBUG("init_ep (%d):",index); PRINT_DEBUG_BUF(ctx->ep_config[index], sizeof(ep_cfg)); if(!ffs_mode) { ret = write(fd, ctx->ep_config[index], sizeof(ep_cfg)); if (ret != sizeof(ep_cfg)) { PRINT_ERROR("init_ep : Endpoint %s (%d) init failed ! : Write Error %d - %m",ctx->ep_path[index], index, ret); goto init_ep_error; } } else { PRINT_DEBUG("init_ep (%d): FunctionFS Mode - Don't write the endpoint descriptor.",index); } return fd; init_ep_error: return 0; } int init_eps(usb_gadget * ctx, int ffs_mode) { if( !init_ep(ctx, EP_DESCRIPTOR_IN, ffs_mode) ) goto init_eps_error; if( !init_ep(ctx, EP_DESCRIPTOR_OUT, ffs_mode) ) goto init_eps_error; if( !init_ep(ctx, EP_DESCRIPTOR_INT_IN, ffs_mode) ) goto init_eps_error; return 0; init_eps_error: return 1; } static void handle_setup_request(usb_gadget * ctx, struct usb_ctrlrequest* setup) { int status,cnt; uint8_t buffer[512]; mtp_device_status dstatus; PRINT_DEBUG("Setup request 0x%.2X", setup->bRequest); switch (setup->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (setup->bRequestType != USB_DIR_IN) goto stall; switch (setup->wValue >> 8) { case USB_DT_STRING: PRINT_DEBUG("Get string id #%d (max length %d)", setup->wValue & 0xff, setup->wLength); status = usb_gadget_get_string (&strings, setup->wValue & 0xff, buffer); // Error if (status < 0) { PRINT_ERROR("handle_setup_request : String id #%d (max length %d) not found !",setup->wValue & 0xff, setup->wLength); break; } else { PRINT_DEBUG("Found %d bytes", status); PRINT_DEBUG_BUF(buffer, status); } if ( write (ctx->usb_device, buffer, status) < 0 ) { PRINT_ERROR("handle_setup_request - USB_REQ_GET_DESCRIPTOR : usb device write error !"); break; } return; break; default: PRINT_DEBUG("Cannot return descriptor %d", (setup->wValue >> 8)); break; } break; case USB_REQ_SET_CONFIGURATION: if (setup->bRequestType != USB_DIR_OUT) { PRINT_DEBUG("Bad dir"); goto stall; } switch (setup->wValue) { case CONFIG_VALUE: PRINT_DEBUG("Set config value"); if (ctx->ep_handles[EP_DESCRIPTOR_IN] <= 0) { status = init_eps(ctx,0); } else status = 0; if (!status) { ctx->stop = 0; if( ctx->thread_not_started ) ctx->thread_not_started = pthread_create(&ctx->thread, NULL, io_thread, ctx); } break; case 0: PRINT_DEBUG("Disable threads"); ctx->stop = 1; break; default: PRINT_DEBUG("Unhandled configuration value %d", setup->wValue); break; } // Just ACK status = read (ctx->usb_device, &status, 0); return; break; case USB_REQ_GET_INTERFACE: PRINT_DEBUG("GET_INTERFACE"); buffer[0] = 0; if ( write (ctx->usb_device, buffer, 1) < 0 ) { PRINT_ERROR("handle_setup_request - USB_REQ_GET_INTERFACE : usb device write error !"); break; } return; break; case USB_REQ_SET_INTERFACE: PRINT_DEBUG("SET_INTERFACE"); ioctl (ctx->ep_handles[EP_DESCRIPTOR_IN], GADGETFS_CLEAR_HALT); ioctl (ctx->ep_handles[EP_DESCRIPTOR_OUT], GADGETFS_CLEAR_HALT); ioctl (ctx->ep_handles[EP_DESCRIPTOR_INT_IN], GADGETFS_CLEAR_HALT); // ACK status = read (ctx->usb_device, &status, 0); return; break; case MTP_REQ_CANCEL: PRINT_DEBUG("MTP_REQ_CANCEL !"); status = read (ctx->usb_device, &status, 0); mtp_context->cancel_req = 1; cnt = 0; while( mtp_context->cancel_req ) { // Wait the end of the current transfer if( cnt > 250 ) { // Timeout... Unblock pending usb read/write. PRINT_DEBUG("MTP_REQ_CANCEL : Forcing read/write exit..."); pthread_kill(ctx->thread, SIGUSR1); usleep(500); break; } else usleep(1000); cnt++; } while( mtp_context->cancel_req ) { // Still Waiting the end of the current transfer... if( cnt > 500 ) { // Still blocked... Killing the link PRINT_DEBUG("MTP_REQ_CANCEL : Stalled ... Killing the link..."); usleep(500); ctx->stop = 1; break; } else usleep(1000); cnt++; } PRINT_DEBUG("MTP_REQ_CANCEL done !"); return; break; case MTP_REQ_RESET: PRINT_DEBUG("MTP_REQ_RESET !"); // Just ACK status = read (ctx->usb_device, &status, 0); return; break; case MTP_REQ_GET_DEVICE_STATUS: PRINT_DEBUG("MTP_REQ_GET_DEVICE_STATUS !"); dstatus.wLength = sizeof(mtp_device_status); dstatus.wCode = MTP_RESPONSE_OK; if ( write (ctx->usb_device, (void*)&dstatus, sizeof(mtp_device_status) ) < 0 ) { PRINT_ERROR("MTP_REQ_GET_DEVICE_STATUS : usb device write error !"); break; } return; break; } stall: PRINT_DEBUG("Stalled"); // Error if (setup->bRequestType & USB_DIR_IN) { if ( read (ctx->usb_device, &status, 0) < 0 ) { PRINT_DEBUG("handle_setup_request - stall : usb device read error !"); } } else { if ( write (ctx->usb_device, &status, 0) < 0 ) { PRINT_DEBUG("handle_setup_request - stall : usb device write error !"); } } } // GadgetFS mode handler int handle_ep0(usb_gadget * ctx) { struct timeval timeout; int ret, nevents, i, cnt; fd_set read_set; struct usb_gadgetfs_event events[5]; PRINT_DEBUG("handle_ep0 : Entering..."); timeout.tv_sec = 4; timeout.tv_usec = 0; while (!ctx->stop) { FD_ZERO(&read_set); FD_SET(ctx->usb_device, &read_set); if(timeout.tv_sec) { ret = select(ctx->usb_device+1, &read_set, NULL, NULL, &timeout); } else { PRINT_DEBUG("handle_ep0 : Select without timeout"); ret = select(ctx->usb_device+1, &read_set, NULL, NULL, NULL); } if(ctx->wait_connection && ret == 0 ) continue; if( ret <= 0 ) return ret; timeout.tv_sec = 0; ret = read(ctx->usb_device, &events, sizeof(events)); if (ret < 0) { PRINT_ERROR("handle_ep0 : Read error %d (%m)", errno); goto end; } nevents = ret / sizeof(events[0]); PRINT_DEBUG("handle_ep0 : %d event(s)", nevents); for (i=0; istop = 1; if( !ctx->thread_not_started ) { pthread_cancel(ctx->thread); pthread_join(ctx->thread, NULL); ctx->thread_not_started = 1; } break; case GADGETFS_SETUP: PRINT_DEBUG("handle_ep0 : EP0 SETUP event"); handle_setup_request(ctx, &events[i].u.setup); break; case GADGETFS_NOP: PRINT_DEBUG("handle_ep0 : EP0 NOP event"); break; case GADGETFS_SUSPEND: PRINT_DEBUG("handle_ep0 : EP0 SUSPEND event"); if(mtp_context->transferring_file_data) { // Cancel the ongoing file transfer mtp_context->cancel_req = 1; cnt = 0; while( mtp_context->cancel_req ) { // Wait the end of the current transfer if( cnt > 250 ) { // Timeout... Unblock pending usb read/write. PRINT_DEBUG("GADGETFS_SUSPEND : Forcing usb file transfer read/write exit..."); pthread_kill(ctx->thread, SIGUSR1); usleep(500); break; } else usleep(1000); cnt++; } } break; default: PRINT_DEBUG("handle_ep0 : EP0 unknown event : %d",events[i].type); break; } } } ctx->stop = 1; end: PRINT_DEBUG("handle_ep0 : Leaving (ctx->stop=%d)...",ctx->stop); return 1; } // Function FS mode handler int handle_ffs_ep0(usb_gadget * ctx) { struct timeval timeout; int ret, nevents, i; fd_set read_set; struct usb_functionfs_event event; int status; PRINT_DEBUG("handle_ffs_ep0 : Entering..."); timeout.tv_sec = 40; timeout.tv_usec = 0; while (!ctx->stop) { FD_ZERO(&read_set); FD_SET(ctx->usb_device, &read_set); if(timeout.tv_sec) { ret = select(ctx->usb_device+1, &read_set, NULL, NULL, &timeout); } else { PRINT_DEBUG("Select without timeout"); ret = select(ctx->usb_device+1, &read_set, NULL, NULL, NULL); } if(ctx->wait_connection && ret == 0 ) continue; if( ret <= 0 ) return ret; timeout.tv_sec = 0; ret = read(ctx->usb_device, &event, sizeof(event)); if (ret < 0) { PRINT_ERROR("handle_ffs_ep0 : Read error %d (%m)", ret); goto end; } nevents = ret / sizeof(event); PRINT_DEBUG("%d event(s)", nevents); for (i=0; iep_handles[EP_DESCRIPTOR_IN] <= 0) { status = init_eps(ctx,1); } else status = 0; if (!status) { ctx->stop = 0; if( ctx->thread_not_started ) ctx->thread_not_started = pthread_create(&ctx->thread, NULL, io_thread, ctx); } break; case FUNCTIONFS_DISABLE: PRINT_DEBUG("EP0 FFS DISABLE"); // Set timeout for a reconnection during the enumeration... timeout.tv_sec = 0; timeout.tv_usec = 0; // Stop the main rx thread. ctx->stop = 1; if( !ctx->thread_not_started ) { pthread_join(ctx->thread, NULL); ctx->thread_not_started = 1; } // But don't close the endpoints ! ctx->stop = 0; // Drop the file system db pthread_mutex_lock( &mtp_context->inotify_mutex ); deinit_fs_db(mtp_context->fs_db); mtp_context->fs_db = 0; pthread_mutex_unlock( &mtp_context->inotify_mutex ); break; case FUNCTIONFS_SETUP: PRINT_DEBUG("EP0 FFS SETUP"); handle_setup_request(ctx, &event.u.setup); break; case FUNCTIONFS_BIND: PRINT_DEBUG("EP0 FFS BIND"); break; case FUNCTIONFS_UNBIND: PRINT_DEBUG("EP0 FFS UNBIND"); break; case FUNCTIONFS_SUSPEND: PRINT_DEBUG("EP0 FFS SUSPEND"); break; case FUNCTIONFS_RESUME: PRINT_DEBUG("EP0 FFS RESUME"); break; } } } ctx->stop = 1; end: PRINT_DEBUG("handle_ffs_ep0 : Leaving... (ctx->stop=%d)",ctx->stop); return 1; } int add_usb_string(usb_gadget * usbctx, int id, char * string) { int i; i = 0; while( i < MAX_USB_STRING ) { if( !usbctx->stringtab[i].id ) { usbctx->stringtab[i].id = id; if(string) { usbctx->stringtab[i].str = malloc(strlen(string) + 1); if(usbctx->stringtab[i].str) { memset(usbctx->stringtab[i].str,0,strlen(string) + 1); strcpy(usbctx->stringtab[i].str,string); return i; } else { usbctx->stringtab[i].id = 0; return -2; } } else { return i; } } i++; } return -1; } usb_gadget * init_usb_mtp_gadget(mtp_ctx * ctx) { usb_gadget * usbctx; int cfg_size; int ret,i; ffs_strings ffs_str; usbctx = NULL; if(ctx->wrbuffer) free(ctx->wrbuffer); ctx->wrbuffer = malloc( ctx->usb_wr_buffer_max_size ); if(!ctx->wrbuffer) goto init_error; memset(ctx->wrbuffer,0,ctx->usb_wr_buffer_max_size); if(ctx->rdbuffer) free(ctx->rdbuffer); ctx->rdbuffer = malloc( ctx->usb_rd_buffer_max_size ); if(!ctx->rdbuffer) goto init_error; memset(ctx->rdbuffer,0,ctx->usb_rd_buffer_max_size); if(ctx->rdbuffer2) free(ctx->rdbuffer2); ctx->rdbuffer2 = malloc( ctx->usb_rd_buffer_max_size ); if(!ctx->rdbuffer2) goto init_error; memset(ctx->rdbuffer2,0,ctx->usb_rd_buffer_max_size); usbctx = malloc(sizeof(usb_gadget)); if(usbctx) { memset(usbctx,0,sizeof(usb_gadget)); usbctx->usb_device = -1; usbctx->thread_not_started = 1; i = 0; while( i < EP_NB_OF_DESCRIPTORS ) { usbctx->ep_handles[i] = -1; i++; } add_usb_string(usbctx, STRINGID_MANUFACTURER, ctx->usb_cfg.usb_string_manufacturer); add_usb_string(usbctx, STRINGID_PRODUCT, ctx->usb_cfg.usb_string_product); add_usb_string(usbctx, STRINGID_SERIAL, ctx->usb_cfg.usb_string_serial); add_usb_string(usbctx, STRINGID_CONFIG_HS, "High speed configuration"); add_usb_string(usbctx, STRINGID_CONFIG_LS, "Low speed configuration"); add_usb_string(usbctx, STRINGID_INTERFACE, ctx->usb_cfg.usb_string_interface); add_usb_string(usbctx, STRINGID_MAX, NULL); strings.strings = usbctx->stringtab; usbctx->wait_connection = ctx->usb_cfg.wait_connection; for(i=0;i<3;i++) { usbctx->ep_config[i] = malloc(sizeof(ep_cfg)); if(!usbctx->ep_config[i]) goto init_error; memset(usbctx->ep_config[i],0,sizeof(ep_cfg)); } usbctx->ep_path[0] = ctx->usb_cfg.usb_endpoint_in; usbctx->ep_path[1] = ctx->usb_cfg.usb_endpoint_out; usbctx->ep_path[2] = ctx->usb_cfg.usb_endpoint_intin; usbctx->usb_device = open(ctx->usb_cfg.usb_device_path, O_RDWR|O_SYNC); if (usbctx->usb_device <= 0) { PRINT_ERROR("init_usb_mtp_gadget : Unable to open %s (%m)", ctx->usb_cfg.usb_device_path); goto init_error; } cfg_size = sizeof(struct usb_interface_descriptor) + (sizeof(struct usb_endpoint_descriptor_no_audio) * 3); if( ctx->usb_cfg.usb_functionfs_mode ) { // FunctionFS mode usbctx->usb_ffs_config = malloc(sizeof(usb_ffs_cfg)); if(!usbctx->usb_ffs_config) goto init_error; memset(usbctx->usb_ffs_config,0,sizeof(usb_ffs_cfg)); #ifdef OLD_FUNCTIONFS_DESCRIPTORS // Kernel < v3.15 usbctx->usb_ffs_config->magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC); #else usbctx->usb_ffs_config->magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2); usbctx->usb_ffs_config->flags = htole32(FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC); #endif usbctx->usb_ffs_config->fs_count = htole32(4), usbctx->usb_ffs_config->hs_count = htole32(4), usbctx->usb_ffs_config->length = htole32(sizeof(usb_ffs_cfg)); fill_if_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->if_desc); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc[EP_DESCRIPTOR_IN],1, EP_BULK_MODE | EP_IN_DIR); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc[EP_DESCRIPTOR_OUT],2, EP_BULK_MODE | EP_OUT_DIR); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc[EP_DESCRIPTOR_INT_IN],3, EP_INT_MODE | EP_IN_DIR); fill_if_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->if_desc_hs); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_hs[EP_DESCRIPTOR_IN],1, EP_BULK_MODE | EP_IN_DIR | EP_HS_MODE); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_hs[EP_DESCRIPTOR_OUT],2, EP_BULK_MODE | EP_OUT_DIR | EP_HS_MODE); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_ffs_config->ep_desc_hs[EP_DESCRIPTOR_INT_IN],3, EP_INT_MODE | EP_IN_DIR | EP_HS_MODE); PRINT_DEBUG("init_usb_mtp_gadget :"); PRINT_DEBUG_BUF(usbctx->usb_ffs_config, sizeof(usb_ffs_cfg)); ret = write(usbctx->usb_device, usbctx->usb_ffs_config, sizeof(usb_ffs_cfg)); if(ret != sizeof(usb_ffs_cfg)) { PRINT_ERROR("FunctionFS USB Config write error (%d != %zu)",ret,sizeof(usb_ffs_cfg)); goto init_error; } memset( &ffs_str, 0, sizeof(ffs_strings)); ffs_str.header.magic = htole32(FUNCTIONFS_STRINGS_MAGIC); ffs_str.header.length = htole32(sizeof(struct usb_functionfs_strings_head) + sizeof(uint16_t) + strlen(ctx->usb_cfg.usb_string_interface) + 1); ffs_str.header.str_count = htole32(1); ffs_str.header.lang_count = htole32(1); ffs_str.code = htole16(0x0409); // en-us strcpy(ffs_str.string_data,ctx->usb_cfg.usb_string_interface); PRINT_DEBUG("write string :"); PRINT_DEBUG_BUF(&ffs_str, sizeof(ffs_strings)); ret = write(usbctx->usb_device, &ffs_str, ffs_str.header.length); if( ret != ffs_str.header.length ) { PRINT_ERROR("FunctionFS String Config write error (%d != %zu)",ret,(size_t)ffs_str.header.length); goto init_error; } } else { usbctx->usb_config = malloc(sizeof(usb_cfg)); if(!usbctx->usb_config) goto init_error; memset(usbctx->usb_config,0,sizeof(usb_cfg)); usbctx->usb_config->head = 0x00000000; fill_config_descriptor(ctx, usbctx, &usbctx->usb_config->cfg, cfg_size, 0); fill_if_descriptor(ctx, usbctx, &usbctx->usb_config->if_desc); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc[EP_DESCRIPTOR_IN],1, EP_BULK_MODE | EP_IN_DIR); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc[EP_DESCRIPTOR_OUT],2, EP_BULK_MODE | EP_OUT_DIR); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc[EP_DESCRIPTOR_INT_IN],3, EP_INT_MODE | EP_IN_DIR); fill_config_descriptor(ctx, usbctx, &usbctx->usb_config->cfg_hs, cfg_size, 1); fill_if_descriptor(ctx, usbctx, &usbctx->usb_config->if_desc_hs); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_hs[EP_DESCRIPTOR_IN],1, EP_BULK_MODE | EP_IN_DIR | EP_HS_MODE); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_hs[EP_DESCRIPTOR_OUT],2, EP_BULK_MODE | EP_OUT_DIR | EP_HS_MODE); fill_ep_descriptor(ctx, usbctx, &usbctx->usb_config->ep_desc_hs[EP_DESCRIPTOR_INT_IN],3, EP_INT_MODE | EP_IN_DIR | EP_HS_MODE); fill_dev_descriptor(ctx, usbctx,&usbctx->usb_config->dev_desc); PRINT_DEBUG("init_usb_mtp_gadget :"); PRINT_DEBUG_BUF(usbctx->usb_config, sizeof(usb_cfg)); ret = write(usbctx->usb_device, usbctx->usb_config, sizeof(usb_cfg)); if(ret != sizeof(usb_cfg)) { PRINT_ERROR("GadgetFS USB Config write error (%d != %zu)",ret,sizeof(usb_cfg)); goto init_error; } } PRINT_DEBUG("init_usb_mtp_gadget : USB config done"); return usbctx; } init_error: PRINT_ERROR("init_usb_mtp_gadget init error !"); deinit_usb_mtp_gadget(usbctx); return 0; } void deinit_usb_mtp_gadget(usb_gadget * usbctx) { int i; PRINT_DEBUG("entering deinit_usb_mtp_gadget"); if( usbctx ) { usbctx->stop = 1; i = 0; while( i < EP_NB_OF_DESCRIPTORS ) { if( usbctx->ep_handles[i] >= 0 ) { PRINT_DEBUG("Closing End Point %d...",i); close(usbctx->ep_handles[i] ); } i++; } if (usbctx->usb_device >= 0) { PRINT_DEBUG("Closing usb device..."); close(usbctx->usb_device); usbctx->usb_device = - 1; } if( !usbctx->thread_not_started ) { PRINT_DEBUG("Stopping USB Thread..."); pthread_cancel (usbctx->thread); pthread_join(usbctx->thread, NULL); usbctx->thread_not_started = 1; } if(usbctx->usb_config) { free(usbctx->usb_config); usbctx->usb_config = 0; } if(usbctx->usb_ffs_config) { free(usbctx->usb_ffs_config); usbctx->usb_ffs_config = 0; } for(i=0;i<3;i++) { if( usbctx->ep_config[i] ) free( usbctx->ep_config[i] ); } i = 0; while( i < MAX_USB_STRING ) { if( usbctx->stringtab[i].str ) { free ( usbctx->stringtab[i].str ); } i++; } free( usbctx ); } if(mtp_context->wrbuffer) { free(mtp_context->wrbuffer); mtp_context->wrbuffer = NULL; } if(mtp_context->rdbuffer) { free(mtp_context->rdbuffer); mtp_context->rdbuffer = NULL; } if(mtp_context->rdbuffer2) { free(mtp_context->rdbuffer2); mtp_context->rdbuffer2 = NULL; } PRINT_DEBUG("leaving deinit_usb_mtp_gadget"); } umtp-responder-1.3.10/src/usbstring.c000066400000000000000000000161241374176322100175450ustar00rootroot00000000000000/* * uMTP Responder * Copyright (c) 2018 - 2020 Viveris Technologies * * uMTP Responder is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * uMTP Responder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License * along with uMTP Responder; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file usbstring.c * @brief USB Strings * @author Jean-François DEL NERO */ /* * * Note : This source file is based on the Linux kernel usbstring.c * with the following Licence/copyright : * */ /* * Copyright (C) 2003 David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. */ #include "buildconf.h" #include #include #include #include #include #include #include "usbstring.h" /* From usbstring.[ch] */ static inline void put_unaligned_le16(uint16_t val, uint16_t *cp) { uint8_t *p = (void *)cp; *p++ = (uint8_t) val; *p++ = (uint8_t) (val >> 8); } static int utf8_to_utf16le(const char *s, uint16_t *cp, unsigned len) { int count = 0; uint8_t c; uint16_t uchar; /* this insists on correct encodings, though not minimal ones. * BUT it currently rejects legit 4-byte UTF-8 code points, * which need surrogate pairs. (Unicode 3.1 can use them.) */ while (len != 0 && (c = (uint8_t) *s++) != 0) { if (c & 0x80) { // 2-byte sequence: // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx if ((c & 0xe0) == 0xc0) { uchar = (c & 0x1f) << 6; c = (uint8_t) *s++; if ((c & 0xc0) != 0xc0) goto fail; c &= 0x3f; uchar |= c; // 3-byte sequence (most CJKV characters): // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx } else if ((c & 0xf0) == 0xe0) { uchar = (c & 0x0f) << 12; c = (uint8_t) *s++; if ((c & 0xc0) != 0xc0) goto fail; c &= 0x3f; uchar |= c << 6; c = (uint8_t) *s++; if ((c & 0xc0) != 0xc0) goto fail; c &= 0x3f; uchar |= c; /* no bogus surrogates */ if (0xd800 <= uchar && uchar <= 0xdfff) goto fail; // 4-byte sequence (surrogate pairs, currently rare): // 11101110wwwwzzzzyy + 110111yyyyxxxxxx // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx // (uuuuu = wwww + 1) // FIXME accept the surrogate code points (only) } else goto fail; } else uchar = c; put_unaligned_le16 (uchar, cp++); count++; len--; } return count; fail: return -1; } int usb_gadget_get_string (struct usb_gadget_strings *table, int id, uint8_t *buf) { struct usb_string *s; int len; /* descriptor 0 has the language id */ if (id == 0) { buf [0] = 4; buf [1] = USB_DT_STRING; buf [2] = (uint8_t) table->language; buf [3] = (uint8_t) (table->language >> 8); return 4; } for (s = table->strings; s && s->str; s++) if (s->id == id) break; /* unrecognized: stall. */ if (!s || !s->str) return -EINVAL; /* string descriptors have length, tag, then UTF16-LE text */ len = strlen (s->str); if (len > 126) len = 126; memset (buf + 2, 0, 2 * len); /* zero all the bytes */ len = utf8_to_utf16le(s->str, (uint16_t *)&buf[2], len); if (len < 0) return -EINVAL; buf [0] = (len + 1) * 2; buf [1] = USB_DT_STRING; return buf [0]; } int utf8_encode(char *out, uint32_t unicode) { if (unicode <= 0x7F) { // ASCII *out++ = (char) unicode; *out++ = 0; return 1; } else if (unicode <= 0x07FF) { // 2-bytes unicode *out++ = (char) (((unicode >> 6) & 0x1F) | 0xC0); *out++ = (char) (((unicode >> 0) & 0x3F) | 0x80); *out++ = 0; return 2; } else if (unicode <= 0xFFFF) { // 3-bytes unicode *out++ = (char) (((unicode >> 12) & 0x0F) | 0xE0); *out++ = (char) (((unicode >> 6) & 0x3F) | 0x80); *out++ = (char) (((unicode >> 0) & 0x3F) | 0x80); *out++ = 0; return 3; } else if (unicode <= 0x10FFFF) { // 4-bytes unicode *out++ = (char) (((unicode >> 18) & 0x07) | 0xF0); *out++ = (char) (((unicode >> 12) & 0x3F) | 0x80); *out++ = (char) (((unicode >> 6) & 0x3F) | 0x80); *out++ = (char) (((unicode >> 0) & 0x3F) | 0x80); *out++ = 0; return 4; } else { // error return 0; } } int unicode2charstring(char * str, uint16_t * unicodestr, int maxstrsize) { int i,j,ret; int chunksize; char tmpstr[8]; ret = 0; i = 0; while( *unicodestr ) { chunksize = utf8_encode((char*)&tmpstr, *unicodestr++); if(!chunksize) { // Error -> default character tmpstr[0] = '?'; tmpstr[1] = 0; chunksize = 1; } if( (i + chunksize) < maxstrsize ) { for( j = 0 ; j < chunksize ; j++ ) { str[i] = tmpstr[j]; i++; } } else { str[ maxstrsize - 1 ] = 0; ret = 1; break; } }; if( i < maxstrsize ) str[i] = 0; return ret; } static int utf8_size(char c) { int count = 0; while (c & 0x80) { c = c << 1; count++; } if(!count) count = 1; return count; } uint16_t utf2unicode(const unsigned char* pInput, int * ofs) { uint8_t b1, b2, b3; int utfsize; uint16_t unicode_out; *ofs = 0; utfsize = utf8_size(*pInput); switch ( utfsize ) { case 1: unicode_out = *pInput; *ofs = 1; return unicode_out; break; case 2: b1 = *pInput++; b2 = *pInput++; if ( (b2 & 0xC0) != 0x80 ) return 0x0000; unicode_out = ( ( (b1 & 0x1F) << 6 ) | (b2 & 0x3F) ) & 0xFF; unicode_out |= (uint16_t)((b1 & 0x1F) >> 2) << 8; *ofs = 2; return unicode_out; break; case 3: b1 = *pInput++; b2 = *pInput++; b3 = *pInput++; if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) ) return 0x0000; unicode_out = (uint16_t)( ((b2 & 0x3F) << 6) | (b3 & 0x3F) ) & 0x00FF; unicode_out |= (uint16_t)( ((b1 & 0xF) << 4) | ((b2 & 0x3F) >> 2 ) ) << 8; *ofs = 3; return unicode_out; break; default: *ofs = 0; return 0x0000; break; } return 0x0000; } int char2unicodestring(char * unicodestr, int index, int maxsize, char * str, int unicodestrsize) { uint16_t unicode; int ofs, len, start; start = index; len = 0; ofs = 0; do{ unicode = utf2unicode((unsigned char*)str, &ofs); str = str + ofs; if(index + 2 >= maxsize) return -1; unicodestr[index++] = unicode & 0xFF; unicodestr[index++] = (unicode >> 8) & 0xFF; len++; }while(unicode && ofs && index < unicodestrsize*2); if( len >= unicodestrsize) { if(start + ((unicodestrsize*2)-2) >= maxsize) return -1; unicodestr[start + ((unicodestrsize*2)-2)] = 0x00; unicodestr[start + ((unicodestrsize*2)-1)] = 0x00; len = unicodestrsize; } return len; }